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 `