diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index a17a517e16..09baddc695 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -7,10 +7,10 @@ body: attributes: value: | # 🐞 **Issue Report** - Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently. + Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently. - ## ⚠️ **IMPORTANT** - - 🛠️ **Supported environments only:** We only support Windows 11. Custom ISOs that are not made using Microwin are not supported. + ## ⚠️ **IMPORTANT** + - 🛠️ **Supported environments only:** We only support Windows 11. Custom ISOs that are not made using Microwin are not supported. - 💡 For general questions, use the [Discussions section](https://github.com/Christitustech/winutil/discussions) or join our Community-driven [Discord Server](https://discord.gg/RUbZUZyByQ). - type: checkboxes diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index d32fae1ed6..65e24338fc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -9,7 +9,7 @@ body: # ✨ **Feature request** Thank you for taking the time to suggest a feature! Please provide as much detail as possible to help us understand and evaluate your request. - ## ⚠️ **IMPORTANT** + ## ⚠️ **IMPORTANT** - 🛠️ **Supported environments only:** We only support Windows 11. - 💡 For general questions, use the [Discussions section](https://github.com/Christitustech/winutil/discussions) or join our Community-driven [Discord Server](https://discord.gg/RUbZUZyByQ). @@ -54,4 +54,4 @@ body: label: 🖼️ Additional context placeholder: "Include screenshots, code blocks (use triple backticks ```), or any other relevant information." validations: - required: false \ No newline at end of file + required: false diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1 index 0b79e553dc..ae9b753ed7 100644 --- a/functions/public/Invoke-WPFButton.ps1 +++ b/functions/public/Invoke-WPFButton.ps1 @@ -61,5 +61,10 @@ function Invoke-WPFButton { "WPFWinUtilInstallPSProfile" {Invoke-WinUtilInstallPSProfile} "WPFWinUtilUninstallPSProfile" {Invoke-WinUtilUninstallPSProfile} "WPFWinUtilSSHServer" {Invoke-WPFSSHServer} + "WPFScanUpdates" {Invoke-WPFUpdatesScan} + "WPFShowUpdateHistory" { Invoke-WPFUpdateHistoryToggle } + "WPFUpdateSelectedInstall" {Invoke-WPFUpdateMGMT -Selected} + "WPFUpdateAllInstall" {Invoke-WPFUpdateMGMT -All} + "WPFUpdateScanHistory" {Invoke-WPFUpdateScanHistory} } } diff --git a/functions/public/Invoke-WPFUpdateHistoryToggle.ps1 b/functions/public/Invoke-WPFUpdateHistoryToggle.ps1 new file mode 100644 index 0000000000..030b6be13d --- /dev/null +++ b/functions/public/Invoke-WPFUpdateHistoryToggle.ps1 @@ -0,0 +1,11 @@ +function Invoke-WPFUpdateHistoryToggle { + if ($sync["WPFShowUpdateHistory"].Content -eq "Show History") { + $sync["WPFShowUpdateHistory"].Content = "Show available Updates" + $sync["HistoryGrid"].Visibility = "Visible" + $sync["UpdatesGrid"].Visibility = "Collapsed" + } else { + $sync["WPFShowUpdateHistory"].Content = "Show History" + $sync["HistoryGrid"].Visibility = "Collapsed" + $sync["UpdatesGrid"].Visibility = "Visible" + } +} diff --git a/functions/public/Invoke-WPFUpdateMGMGT.ps1 b/functions/public/Invoke-WPFUpdateMGMGT.ps1 new file mode 100644 index 0000000000..d6cec270f7 --- /dev/null +++ b/functions/public/Invoke-WPFUpdateMGMGT.ps1 @@ -0,0 +1,45 @@ +function Invoke-WPFUpdateMGMT { + param ( + [switch]$Selected, + [switch]$All + ) + + if ($All) { + Write-Host "Installing all available updates ..." + Invoke-WPFRunspace -ArgumentList $sync["WPFUpdateVerbose"].IsChecked -DebugPreference $DebugPreference -ScriptBlock { + param ($WPFUpdateVerbose) + if ($WPFUpdateVerbose) { + Install-WindowsUpdate -Verbose -Confirm:$false -IgnoreReboot:$true -IgnoreRebootRequired:$true + } else { + Install-WindowsUpdate -Confirm:$false -IgnoreReboot:$true -IgnoreRebootRequired:$true + } + Write-Host "All Update Processes Completed" + } + } elseif (($Selected) -and ($sync["WPFUpdatesList"].SelectedItems.Count -gt 0)) { + write-host "Installing selected updates..." + $selectedUpdates = $sync["WPFUpdatesList"].SelectedItems | ForEach-Object { + [PSCustomObject]@{ + ComputerName = $_.ComputerName + Title = $_.LongTitle + KB = $_.KB + Size = $_.Size + } + } + Invoke-WPFRunspace -ParameterList @(("selectedUpdates", $selectedUpdates), ("WPFUpdateVerbose", $sync["WPFUpdateVerbose"].IsChecked)) -DebugPreference $DebugPreference -ScriptBlock { + param ($selectedUpdates, $WPFUpdateVerbose) + foreach ($update in $selectedUpdates) { + Write-Host "Installing update $($update.Title) on $($update.ComputerName)" + if ($WPFUpdateVerbose) { + Get-WindowsUpdate -ComputerName $update.ComputerName -Title $update.Title -Install -Confirm:$false -Verbose -IgnoreReboot:$true -IgnoreRebootRequired:$true + } else { + Get-WindowsUpdate -ComputerName $update.ComputerName -Title $update.Title -Install -Confirm:$false -IgnoreReboot:$true -IgnoreRebootRequired:$true + } + } + Write-Host "Selected Update Processes Completed" + } + } else { + Write-Host "No updates selected" + return + } + +} diff --git a/functions/public/Invoke-WPFUpdateScanHistory.ps1 b/functions/public/Invoke-WPFUpdateScanHistory.ps1 new file mode 100644 index 0000000000..4138e746a5 --- /dev/null +++ b/functions/public/Invoke-WPFUpdateScanHistory.ps1 @@ -0,0 +1,46 @@ +function Invoke-WPFUpdateScanHistory { + $sync["WPFUpdateHistory"].Items.Clear() + Invoke-WPFRunspace -DebugPreference $DebugPreference -ScriptBlock { + write-host "Scanning for Windows update history..." + $UpdateHistory = Get-WUHistory -Last 50 -ErrorAction SilentlyContinue + if ($UpdateHistory) { + foreach ($update in $UpdateHistory) { + $item = New-Object PSObject -Property @{ + ComputerName = $update.ComputerName + Result = $update.Result + Title = $update.Title -replace '\s*\(KB\d+\)', '' -replace '\s*KB\d+\b', '' # Remove KB number from title, first in parentheses, then standalone + KB = $update.KB + Date = $update.Date + } + $Computers = $item | Select-Object -ExpandProperty ComputerName -Unique + $sync.form.Dispatcher.Invoke([action] { + $sync["WPFUpdateHistory"].Items.Add($item) + if ($item.Result -eq "Succeeded") { + # does not work : $sync["WPFUpdateHistory"].Items[$sync["WPFUpdateHistory"].Items.Count - 1].Foreground = "Green" + #write-host "$($item.Title) was successful" + } + elseif ($item.Result -eq "Failed") { + # does not work : $sync["WPFUpdateHistory"].Items[$sync["WPFUpdateHistory"].Items.Count - 1].Foreground = "Red" + #write-host "$($item.Title) failed" + } + }) + } + write-host "Found $($UpdateHistory.Count) updates." + $sync.form.Dispatcher.Invoke([action] { + if ($Computers.Count -gt 1) { + $sync["WPFUpdateHistory"].Columns[0].Visibility = "Visible" + } + else { + Write-Debug "Hiding ComputerName column, only $item.ComputerName" + $sync["WPFUpdateHistory"].Columns[0].Visibility = "Collapsed" + } + }) + } + else { + $sync.form.Dispatcher.Invoke([action] { + $sync["WPFUpdateHistory"].Items.Clear() + }) + Write-Host "No update history available." + } + } +} diff --git a/functions/public/Invoke-WPFUpdatesScan.ps1 b/functions/public/Invoke-WPFUpdatesScan.ps1 new file mode 100644 index 0000000000..4805b022f3 --- /dev/null +++ b/functions/public/Invoke-WPFUpdatesScan.ps1 @@ -0,0 +1,58 @@ +function Invoke-WPFUpdatesScan { + + + Invoke-WPFRunspace -DebugPreference $DebugPreference -ScriptBlock { + # Check if the PSWindowsUpdate module is installed + if (-not (Get-Module -ListAvailable -Name PSWindowsUpdate)) { + try { + Write-Host "PSWindowsUpdate module not found. Attempting to install..." + Install-Module -Name PSWindowsUpdate -Force -Scope CurrentUser + Write-Host "PSWindowsUpdate module installed successfully." + } + catch { + Write-Error "Failed to install PSWindowsUpdate module: $_" + return + } + } + + # Import the module + try { + Import-Module PSWindowsUpdate -ErrorAction Stop + Write-Host "PSWindowsUpdate module imported successfully." + } + catch { + Write-Error "Failed to import PSWindowsUpdate module: $_" + return + } + + try { + $sync.form.Dispatcher.Invoke([action] { $sync["WPFUpdatesList"].Items.Clear() }) + Write-Host "Scanning for Windows updates..." + $updates = Get-WindowsUpdate -ErrorAction Stop + Write-Host "Found $($updates.Count) updates." + + $sync.form.Dispatcher.Invoke([action] { + foreach ($update in $updates) { + $item = New-Object PSObject -Property @{ + LongTitle = $update.Title + ComputerName = $update.ComputerName + KB = $update.KB + Size = $update.Size + Title = $update.Title -replace '\s*\(KB\d+\)', '' -replace '\s*KB\d+\b', '' # Remove KB number from title, first in parentheses, then standalone + Status = "Not Installed" + } + $Computers = $item | Select-Object -ExpandProperty ComputerName -Unique + $sync["WPFUpdatesList"].Items.Add($item) + } + if ($Computers.Count -gt 1) { + $sync["WPFUpdatesList"].Columns[0].Visibility = "Visible" + } else { + Write-Debug "Hiding ComputerName column, only $item.ComputerName" + $sync["WPFUpdatesList"].Columns[0].Visibility = "Collapsed" + } + }) + } catch { + Write-Error "Error scanning for updates: $_" + } + } +} diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 63a41af54e..18e60fd32b 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -842,6 +842,182 @@ + + + + + + + + + + + + + + @@ -1132,100 +1308,232 @@ - + - - + + - - - + - - - + + + +