diff --git a/windows-updater.ps1 b/windows-updater.ps1 index fdcfdfa..d8b211d 100644 --- a/windows-updater.ps1 +++ b/windows-updater.ps1 @@ -9,9 +9,9 @@ Author: Patrick Asmus Web: https://www.cleveradmin.de Repository: https://git.techniverse.net/scriptos/windows-updater.git License: MIT -Version: 2.2.0 +Version: 2.3.0 Datum: 06.07.2026 -Modifiaktione: Service-Watchdog: Dienste nach Updates ohne Reboot neu starten und überwachen. +Modifiaktione: Reviews and improvements ##################################################### #> @@ -355,21 +355,29 @@ function New-HtmlUpdateReport { $rows = "" foreach ($r in $Results) { - $color = if ($r.Result -match "Install|Success") { "#2d7d2d" } else { "#c0392b" } - $bgColor = if ($r.Result -match "Install|Success") { "#e8f5e9" } else { "#fde8e8" } + $color = if ($r.Result -match "^Installed|^Succeeded|^Success") { "#2d7d2d" } else { "#c0392b" } + $bgColor = if ($r.Result -match "^Installed|^Succeeded|^Success") { "#e8f5e9" } else { "#fde8e8" } + $eDate = [System.Net.WebUtility]::HtmlEncode($r.Date) + $eKB = [System.Net.WebUtility]::HtmlEncode($r.KB) + $eTitle = [System.Net.WebUtility]::HtmlEncode($r.Title) + $eSize = [System.Net.WebUtility]::HtmlEncode($r.Size) + $eResult = [System.Net.WebUtility]::HtmlEncode($r.Result) $rows += @" - $($r.Date) - $($r.KB) - $($r.Title) - $($r.Size) - $($r.Result) + $eDate + $eKB + $eTitle + $eSize + $eResult "@ } - $successCount = ($Results | Where-Object { $_.Result -match "Install|Success" } | Measure-Object).Count - $failCount = ($Results | Where-Object { $_.Result -notmatch "Install|Success" } | Measure-Object).Count + $successCount = ($Results | Where-Object { $_.Result -match "^Installed|^Succeeded|^Success" } | Measure-Object).Count + $failCount = ($Results | Where-Object { $_.Result -notmatch "^Installed|^Succeeded|^Success" } | Measure-Object).Count + + $eHostname = [System.Net.WebUtility]::HtmlEncode($Hostname) + $eOSCaption = [System.Net.WebUtility]::HtmlEncode($OSCaption) $html = @" @@ -377,8 +385,8 @@ function New-HtmlUpdateReport {

Windows Update Report

-

Host: $Hostname
- OS: $OSCaption
+

Host: $eHostname
+ OS: $eOSCaption
Date: $(Get-Date -Format "dd.MM.yyyy HH:mm:ss")
Successful: $successCount | Failed: $failCount

@@ -510,7 +518,7 @@ function Send-TeamsNotification { } foreach ($r in $UpdateResults) { - $icon = if ($r.Result -match "Install|Success") { "✅" } else { "❌" } + $icon = if ($r.Result -match "^Installed|^Succeeded|^Success") { "✅" } else { "❌" } $bodyItems += @{ type = "TextBlock" text = "$icon **$($r.KB)** — $($r.Title) ($($r.Size)) — $($r.Result)" @@ -761,7 +769,8 @@ function Get-AvailableUpdates { } catch { Write-Log "Error scanning for updates: $($_.Exception.Message)" -Level ERROR - return @() + $script:HasErrors = $true + return $null } } @@ -833,7 +842,7 @@ function Install-PendingUpdates { Add-UpdateHistoryEntry -KB $kbStr -Title $r.Title -Size $sizeStr -Result $resultStr } - $failed = $deduplicated | Where-Object { $_.Result -and $_.Result.ToString() -notmatch "Install|Success" } + $failed = $deduplicated | Where-Object { $_.Result -and $_.Result.ToString() -notmatch "^Installed|^Succeeded|^Success" } if ($failed -and $retryCount -gt 0) { Write-Log "Retrying $(@($failed).Count) failed update(s)..." -Level WARN foreach ($f in $failed) { @@ -844,7 +853,7 @@ function Install-PendingUpdates { Write-Log " Retry $i/$retryCount for $kbId - $($f.Title)" -Level WARN try { $retryResult = Install-WindowsUpdate -KBArticleID $kbId -AcceptAll -ErrorAction Stop - if ($retryResult -and $retryResult.Result -and $retryResult.Result.ToString() -match "Install|Success") { + if ($retryResult -and $retryResult.Result -and $retryResult.Result.ToString() -match "^Installed|^Succeeded|^Success") { Write-Log " Retry successful for $kbId" -Level INFO $retrySuccess = $true @@ -925,12 +934,14 @@ function Invoke-WingetUpgrade { } else { Write-Log "Winget upgrade finished with exit code: $exitCode" -Level WARN + $script:HasErrors = $true } Add-UpdateHistoryEntry -KB "winget" -Title "Winget Upgrade --all" -Size "N/A" -Result "ExitCode: $exitCode" -UpdateType "Winget" } catch { - Write-Log "Winget upgrade error: $($_.Exception.Message)" -Level WARN + Write-Log "Winget upgrade error: $($_.Exception.Message)" -Level ERROR + $script:HasErrors = $true } } @@ -1165,12 +1176,25 @@ function Start-WindowsUpdater { $dryRun = Get-ConfigValue -Config $script:Config -Section "General" -Key "DryRun" -Default $false -Type bool $availableUpdates = Get-AvailableUpdates - if (-not $availableUpdates -or @($availableUpdates).Count -eq 0) { + if ($null -eq $availableUpdates) { + Write-Log "Update scan failed, aborting" -Level ERROR + Send-Notification -Subject "Scan Error - $env:COMPUTERNAME" ` + -Body "Windows update scan failed on $env:COMPUTERNAME. Check logs for details." ` + -Priority "high" -EventName "UpdateComplete" + Invoke-UpdateHook -Phase Post | Out-Null + Write-Log "Windows Updater finished (scan error)" + exit 1 + } + + if (@($availableUpdates).Count -eq 0) { Write-Log "No updates available" Send-Notification -Subject "No Updates - $env:COMPUTERNAME" ` -Body "No Windows updates are currently available for $env:COMPUTERNAME." ` -EventName "NoUpdates" - Invoke-WingetUpgrade + if (-not $dryRun) { + Invoke-WingetUpgrade + Export-UpdateHistory + } Invoke-UpdateHook -Phase Post | Out-Null Write-Log "Windows Updater finished (no updates)" exit 0 @@ -1198,7 +1222,6 @@ function Start-WindowsUpdater { Send-Notification -Subject "Dry-Run Report - $env:COMPUTERNAME" -Body $reportBody -EventName "DryRun" - Invoke-WingetUpgrade Invoke-UpdateHook -Phase Post | Out-Null Write-Log "Windows Updater finished (dry-run)" exit 0 @@ -1214,8 +1237,8 @@ function Start-WindowsUpdater { Export-UpdateHistory # --- Send Summary Notification --- - $successCount = ($script:UpdateResults | Where-Object { $_.Result -match "Install|Success" } | Measure-Object).Count - $failCount = ($script:UpdateResults | Where-Object { $_.Result -notmatch "Install|Success" } | Measure-Object).Count + $successCount = ($script:UpdateResults | Where-Object { $_.Result -match "^Installed|^Succeeded|^Success" } | Measure-Object).Count + $failCount = ($script:UpdateResults | Where-Object { $_.Result -notmatch "^Installed|^Succeeded|^Success" } | Measure-Object).Count $summaryBody = @( "Windows Update Summary for $env:COMPUTERNAME" @@ -1232,8 +1255,9 @@ function Start-WindowsUpdater { } $summaryText = $summaryBody -join "`n" - $priority = if ($failCount -gt 0) { "high" } else { "default" } - $subjectPrefix = if ($failCount -gt 0) { "Updates (with errors)" } else { "Updates OK" } + $hasFailures = $failCount -gt 0 -or $script:HasErrors + $priority = if ($hasFailures) { "high" } else { "default" } + $subjectPrefix = if ($hasFailures) { "Updates (with errors)" } else { "Updates OK" } Send-Notification -Subject "$subjectPrefix - $env:COMPUTERNAME" ` -Body $summaryText -Priority $priority `