Reviews and improvements

This commit is contained in:
Patrick Asmus
2026-07-06 09:46:33 +02:00
parent b6894df214
commit 89f38e13f9

View File

@@ -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 += @"
<tr style="background-color: $bgColor;">
<td style="padding: 8px; border: 1px solid #ddd;">$($r.Date)</td>
<td style="padding: 8px; border: 1px solid #ddd;">$($r.KB)</td>
<td style="padding: 8px; border: 1px solid #ddd;">$($r.Title)</td>
<td style="padding: 8px; border: 1px solid #ddd;">$($r.Size)</td>
<td style="padding: 8px; border: 1px solid #ddd; color: $color; font-weight: bold;">$($r.Result)</td>
<td style="padding: 8px; border: 1px solid #ddd;">$eDate</td>
<td style="padding: 8px; border: 1px solid #ddd;">$eKB</td>
<td style="padding: 8px; border: 1px solid #ddd;">$eTitle</td>
<td style="padding: 8px; border: 1px solid #ddd;">$eSize</td>
<td style="padding: 8px; border: 1px solid #ddd; color: $color; font-weight: bold;">$eResult</td>
</tr>
"@
}
$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 = @"
<!DOCTYPE html>
@@ -377,8 +385,8 @@ function New-HtmlUpdateReport {
<head><meta charset="utf-8"></head>
<body style="font-family: Segoe UI, Arial, sans-serif; color: #333; max-width: 900px; margin: 0 auto; padding: 20px;">
<h2 style="color: #1a5276;">Windows Update Report</h2>
<p><strong>Host:</strong> $Hostname<br>
<strong>OS:</strong> $OSCaption<br>
<p><strong>Host:</strong> $eHostname<br>
<strong>OS:</strong> $eOSCaption<br>
<strong>Date:</strong> $(Get-Date -Format "dd.MM.yyyy HH:mm:ss")<br>
<strong>Successful:</strong> $successCount | <strong>Failed:</strong> $failCount</p>
<table style="border-collapse: collapse; width: 100%; font-size: 14px;">
@@ -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"
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 `