diff --git a/config/tweaks.json b/config/tweaks.json index 27c7f3b5..4c1fd600 100644 --- a/config/tweaks.json +++ b/config/tweaks.json @@ -2382,13 +2382,7 @@ Set-ItemProperty -Path \"HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SystemRestore\" -Name \"SystemRestorePointCreationFrequency\" -Value \"0\" -Type DWord -Force -ErrorAction Stop | Out-Null } - # Attempt to load the required module for Get-ComputerRestorePoint - try { - Import-Module Microsoft.PowerShell.Management -ErrorAction Stop - } catch { - Write-Host \"Failed to load the Microsoft.PowerShell.Management module: $_\" - return - } + Invoke-WinUtilInitializeModule -module \"Microsoft.PowerShell.Management\" # Get all the restore points for the current day try { diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1 index b90c63d3..9d17b713 100644 --- a/functions/public/Invoke-WPFButton.ps1 +++ b/functions/public/Invoke-WPFButton.ps1 @@ -62,5 +62,10 @@ function Invoke-WPFButton { "WPFWinUtilInstallPSProfile" {Invoke-WinUtilInstallPSProfile} "WPFWinUtilUninstallPSProfile" {Invoke-WinUtilUninstallPSProfile} "WPFWinUtilSSHServer" {Invoke-WPFSSHServer} + "WPFScanUpdates" {Invoke-WPFUpdateScan -type "updates"} + "WPFShowUpdateHistory" { Invoke-WPFUpdateHistoryToggle } + "WPFUpdateSelectedInstall" {Invoke-WPFUpdateMGMT -Selected} + "WPFUpdateAllInstall" {Invoke-WPFUpdateMGMT -All} + "WPFUpdateScanHistory" {Invoke-WPFUpdateScan -type "history"} } } diff --git a/functions/public/Invoke-WPFUpdateMGMT.ps1 b/functions/public/Invoke-WPFUpdateMGMT.ps1 new file mode 100644 index 00000000..f3ba25b7 --- /dev/null +++ b/functions/public/Invoke-WPFUpdateMGMT.ps1 @@ -0,0 +1,127 @@ + +function Invoke-WinUtilUpdateInstall { + + <# + .SYNOPSIS + Installs Windows updates using the Initialize-WindowsUpdateModule and Install-WindowsUpdate cmdlets. + + .PARAMETER Params + A hashtable containing the parameters for the Install-WindowsUpdate cmdlet. + + #> + + param ( + [Parameter(Mandatory=$true)] + [hashtable]$Params + ) + + try { + Initialize-WindowsUpdateModule + Install-WindowsUpdate @Params + Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" + } + catch { + Write-Host "Error installing updates: $_" -ForegroundColor Red + Set-WinUtilTaskbaritem -state "Error" -overlay "warning" + } +} + +function Invoke-WPFUpdateMGMT { + + <# + .SYNOPSIS + Manages Windows Update Installation + + .PARAMETER Selected + A switch parameter that indicates whether to install only selected updates. + + .PARAMETER All + A switch parameter that indicates whether to install all available updates. + + #> + + param ( + [switch]$Selected, + [switch]$All + ) + + # Prepare common installation parameters + $params = @{ + Confirm = $false + IgnoreReboot = $true + IgnoreRebootRequired = $true + } + + if ($sync["WPFUpdateVerbose"].IsChecked) { + $params['Verbose'] = $true + } + + try { + if ($All) { + Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" + Invoke-WinUtilUpdateControls -state $false + Invoke-WPFRunspace -ArgumentList $params -DebugPreference $DebugPreference -ScriptBlock { + param ($params) + + try { + Write-Host "Installing all available updates..." + Invoke-WinUtilUpdateInstall -Params $params + Write-Host "All available updates installed successfully" + $sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }) + } catch { + Write-Host "Error installing updates: $_" -ForegroundColor Red + $sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }) + } + } + Invoke-WinUtilUpdateControls -state $true + } elseif ($Selected -and $sync["WPFUpdatesList"].SelectedItems.Count -gt 0) { + Write-Host "Installing selected updates..." + + # Get selected updates + $selectedUpdates = $sync["WPFUpdatesList"].SelectedItems | ForEach-Object { + [PSCustomObject]@{ + ComputerName = $_.ComputerName + Title = $_.LongTitle + KB = $_.KB + } + } + + # Install selected updates + Invoke-WPFRunspace -ParameterList @(("selectedUpdates", $selectedUpdates),("params", $params)) -DebugPreference $DebugPreference -ScriptBlock { + param ($selectedUpdates, $params) + + $sync.form.Dispatcher.Invoke([action] { + Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" + Invoke-WinUtilUpdateControls -state $false + }) + + foreach ($update in $selectedUpdates) { + Write-Host "Installing update $($update.Title) on $($update.ComputerName)" + + # Prepare update-specific parameters + $updateParams = $params.Clone() + $updateParams['ComputerName'] = $update.ComputerName + + # Install update based on KB or Title + if ($update.KB) { + Get-WindowsUpdate -KBArticleID $update.KB -Install @updateParams + } else { + Get-WindowsUpdate -Title $update.Title -Install @updateParams + } + } + + $sync.form.Dispatcher.Invoke([action] { + Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" + Invoke-WinUtilUpdateControls -state $true + }) + Write-Host "Selected updates installed successfully" + } + } else { + Write-Host "No updates selected" + } + + } catch { + Write-Host "Error installing updates: $_" -ForegroundColor Red + Set-WinUtilTaskbaritem -state "Error" -overlay "warning" + } +} diff --git a/functions/public/Invoke-WPFUpdateScan.ps1 b/functions/public/Invoke-WPFUpdateScan.ps1 new file mode 100644 index 00000000..3e3e538b --- /dev/null +++ b/functions/public/Invoke-WPFUpdateScan.ps1 @@ -0,0 +1,122 @@ +function Invoke-WPFUpdateHistoryToggle { + <# + .SYNOPSIS + Toggles the visibility of the Windows update history and available updates. + #> + + $showHistory = $sync["WPFShowUpdateHistory"].Content -eq "Show History" + + $sync["WPFShowUpdateHistory"].Content = if ($showHistory) { "Show available Updates" } else { "Show History" } + $sync["HistoryGrid"].Visibility = if ($showHistory) { "Visible" } else { "Collapsed" } + $sync["UpdatesGrid"].Visibility = if ($showHistory) { "Collapsed" } else { "Visible" } +} + +function Invoke-WinUtilUpdateControls { + <# + .SYNOPSIS + Disables or enables the update controls based on the specified state. + + .PARAMETER state + The state to set the controls to. + #> + + param ( + [boolean]$state + ) + + $sync["WPFScanUpdates"].IsEnabled = $state + $sync["WPFUpdateScanHistory"].IsEnabled = $state + $sync["WPFUpdateSelectedInstall"].IsEnabled = $state + $sync["WPFUpdateAllInstall"].IsEnabled = $state +} + + +function Invoke-WPFUpdateScan { + <# + .SYNOPSIS + Scans for Windows updates and history and builds the DataGrids for the UI. + + .PARAMETER type + The type of scan to perform. + + #> + + param ( + [string]$type + ) + + Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" + Invoke-WinUtilUpdateControls -state $false + + Invoke-WPFRunspace -ArgumentList $type -DebugPreference $DebugPreference -ScriptBlock { + param ($type) + try { + Invoke-WinUtilInitializeModule -module "PSWindowsUpdate" + switch ($type) { + "updates" { + $sync.form.Dispatcher.Invoke([action] { $sync["WPFUpdatesList"].ItemsSource = $null }) + Write-Host "Scanning for Windows updates..." + $updates = Get-WindowsUpdate -ErrorAction SilentlyContinue + Write-Host "Found $($updates.Count) updates." + + # Build the list of items first + $items = foreach ($update in $updates) { + [PSCustomObject]@{ + LongTitle = $update.Title + ComputerName = $update.ComputerName + KB = $update.KB + Size = $update.Size + Title = $update.Title -replace '\s*\(KB\d+\)', '' -replace '\s*KB\d+\b', '' + Status = "Not Installed" + } + } + + $Computers = $updates.ComputerName | Select-Object -Unique + + # Update the DataGrid at once + $sync.form.Dispatcher.Invoke([action] { + $sync["WPFUpdatesList"].ItemsSource = $items + $sync["WPFUpdatesList"].Columns[0].Visibility = if ($Computers.Count -gt 1) { "Visible" } else { "Collapsed" } + }) + } + "history" { + $sync.form.Dispatcher.Invoke([action] { $sync["WPFUpdateHistory"].ItemsSource = $null }) + Write-Host "Scanning for Windows update history..." + $history = Get-WUHistory -Last 50 -ErrorAction Stop + if (!$history) { + Write-Host "No update history available." + return + } + + # Build the list of history items first + $items = foreach ($update in $history) { + [PSCustomObject]@{ + ComputerName = $update.ComputerName + Result = $update.Result + Title = $update.Title -replace '\s*\(KB\d+\)', '' -replace '\s*KB\d+\b', '' + KB = $update.KB + Date = $update.Date + } + } + + $Computers = $history.ComputerName | Select-Object -Unique + + # Update the DataGrid at once + $sync.form.Dispatcher.Invoke([action] { + $sync["WPFUpdateHistory"].ItemsSource = $items + $sync["WPFUpdateHistory"].Columns[0].Visibility = if ($Computers.Count -gt 1) { "Visible" } else { "Collapsed" } + }) + Write-Host "Scanning for Windows update history completed" + } + } + + $sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }) + } + catch { + $sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }) + Write-Host "Error during scan: $_" -ForegroundColor Red + } finally { + $sync.form.Dispatcher.Invoke([action] { Invoke-WinUtilUpdateControls -state $true }) + } + } +} diff --git a/functions/public/Invoke-WinUtilInitializeModule.ps1 b/functions/public/Invoke-WinUtilInitializeModule.ps1 new file mode 100644 index 00000000..4089faba --- /dev/null +++ b/functions/public/Invoke-WinUtilInitializeModule.ps1 @@ -0,0 +1,28 @@ +function Invoke-WinUtilInitializeModule { + <# + .SYNOPSIS + Initializes and imports a specified PowerShell module. + + .PARAMETER module + The name of the module to be installed and imported. If the module is not already available, it will be installed for the current user. + + #> + + param ( + [string]$module + ) + + Invoke-WPFRunspace -ArgumentList $module -DebugPreference $DebugPreference -ScriptBlock { + param ($module) + try { + if (-not (Get-Module -ListAvailable -Name $module)) { + Write-Host "Installing $module module..." + Install-Module -Name $module -Force -Scope CurrentUser + } + Import-Module $module -ErrorAction Stop + Write-Host "Imported $module module successfully" + } catch { + Write-Host "Error importing $module module: $_" -ForegroundColor Red + } + } +} diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 5de6af1f..05d7d6fb 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -842,6 +842,182 @@ + + + + + + + + + + + + + + @@ -1132,100 +1308,232 @@ - + - - + + - - - + - - - + + + +