diff --git a/config/tweaks.json b/config/tweaks.json index 045f6f69..bbcb7840 100644 --- a/config/tweaks.json +++ b/config/tweaks.json @@ -2417,13 +2417,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 ae9b753e..7fdfaf62 100644 --- a/functions/public/Invoke-WPFButton.ps1 +++ b/functions/public/Invoke-WPFButton.ps1 @@ -61,10 +61,10 @@ function Invoke-WPFButton { "WPFWinUtilInstallPSProfile" {Invoke-WinUtilInstallPSProfile} "WPFWinUtilUninstallPSProfile" {Invoke-WinUtilUninstallPSProfile} "WPFWinUtilSSHServer" {Invoke-WPFSSHServer} - "WPFScanUpdates" {Invoke-WPFUpdatesScan} + "WPFScanUpdates" {Invoke-WPFUpdateScan -type "updates"} "WPFShowUpdateHistory" { Invoke-WPFUpdateHistoryToggle } "WPFUpdateSelectedInstall" {Invoke-WPFUpdateMGMT -Selected} "WPFUpdateAllInstall" {Invoke-WPFUpdateMGMT -All} - "WPFUpdateScanHistory" {Invoke-WPFUpdateScanHistory} + "WPFUpdateScanHistory" {Invoke-WPFUpdateScan -type "history"} } } diff --git a/functions/public/Invoke-WPFUpdateHistoryToggle.ps1 b/functions/public/Invoke-WPFUpdateHistoryToggle.ps1 deleted file mode 100644 index 030b6be1..00000000 --- a/functions/public/Invoke-WPFUpdateHistoryToggle.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 41369988..00000000 --- a/functions/public/Invoke-WPFUpdateMGMGT.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -function Invoke-WPFUpdateMGMT { - param ( - [switch]$Selected, - [switch]$All - ) - - if ((-not $Selected -and -not $All) -or ($Selected -and $All)) { - Write-Host "[Invoke-WPFUpdateMGMT] Use either 'Selected' or 'All' switches, used switches are: 'Selected' is $Selected, 'All' is $All" -ForegroundColor Red - return - } - - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" }) - - 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 - } - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }) - Write-Host "All Update Processes Completed" - #catch $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }) - } - } 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 ($update.KB -ne "") { - if ($WPFUpdateVerbose) { - Get-WindowsUpdate -ComputerName $update.ComputerName -KBArticleID $update.KB -Install -Confirm:$false -Verbose -IgnoreReboot:$true -IgnoreRebootRequired:$true - } else { - Get-WindowsUpdate -ComputerName $update.ComputerName -KBArticleID $update.KB -Install -Confirm:$false -IgnoreReboot:$true -IgnoreRebootRequired:$true - } - } else { - 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 - } - } - } - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }) - Write-Host "Selected Update Processes Completed" - #catch $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }) - } - } else { - Write-Host "No updates selected" - return - } -} 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-WPFUpdateScanHistory.ps1 b/functions/public/Invoke-WPFUpdateScanHistory.ps1 deleted file mode 100644 index 8c8dcdb5..00000000 --- a/functions/public/Invoke-WPFUpdateScanHistory.ps1 +++ /dev/null @@ -1,49 +0,0 @@ -function Invoke-WPFUpdateScanHistory { - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" }) - $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" - } - }) - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }) - #catch $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }) - } - 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 deleted file mode 100644 index 85fb04f8..00000000 --- a/functions/public/Invoke-WPFUpdatesScan.ps1 +++ /dev/null @@ -1,67 +0,0 @@ -function Invoke-WPFUpdatesScan { - $sync["WPFScanUpdates"].IsEnabled = $false - $sync["WPFUpdateSelectedInstall"].IsEnabled = $false - $sync["WPFUpdateAllInstall"].IsEnabled = $false - Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" - 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: $_" - $sync.form.Dispatcher.Invoke([action] { $sync["WPFScanUpdates"].IsEnabled = $true }) - return - } - } - - # Import the module - try { - Import-Module PSWindowsUpdate -ErrorAction Stop - Write-Host "PSWindowsUpdate module imported successfully." - } - catch { - Write-Error "Failed to import PSWindowsUpdate module: $_" - $sync.form.Dispatcher.Invoke([action] { $sync["WPFScanUpdates"].IsEnabled = $true }) - 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" - } - }) - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }) - } catch { - Write-Error "Error scanning for updates: $_" - $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }) - } - } - $sync["WPFScanUpdates"].IsEnabled = $false - $sync["WPFUpdateSelectedInstall"].IsEnabled = $false - $sync["WPFUpdateAllInstall"].IsEnabled = $false -} 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 + } + } +}