diff --git a/config.example.ini b/config.example.ini index 96ff624..1e8ecb1 100644 --- a/config.example.ini +++ b/config.example.ini @@ -67,6 +67,24 @@ TeamsEnabled = false # Webhook URL for Microsoft Teams (Incoming Webhook connector or Workflows) TeamsWebhookUrl = +[NotificationEvents] +# Control which events trigger notifications (true/false) +# All events are enabled by default +# Module load failure - PSWindowsUpdate could not be loaded +NotifyOnModuleError = true +# Pre-update hook failed and aborted the update process +NotifyOnHookFailure = true +# No updates available +NotifyOnNoUpdates = true +# Dry-run mode report with list of available updates +NotifyOnDryRun = true +# Summary after update installation (success and errors) +NotifyOnUpdateComplete = true +# System reboot triggered (immediate, delayed, or scheduled) +NotifyOnReboot = true +# Reboot required but auto-reboot is disabled +NotifyOnRebootRequired = true + [Hooks] # Path to PowerShell script to execute BEFORE updates (leave empty to disable) PreUpdateScript = diff --git a/docs/configuration.md b/docs/configuration.md index 487b1bf..daa8541 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -62,6 +62,27 @@ Alle Einstellungen werden in der Datei `config.ini` vorgenommen, die sich im sel | `EmailTo` | String | *(leer)* | Empfänger-Adresse(n), kommagetrennt | | `EmailHtmlReport` | Boolean | `true` | HTML-formatierten Report mit Update-Tabelle senden | +#### Microsoft Teams + +| Option | Typ | Standard | Beschreibung | +|---|---|---|---| +| `TeamsEnabled` | Boolean | `false` | Teams-Benachrichtigungen aktivieren | +| `TeamsWebhookUrl` | String | *(leer)* | Webhook-URL für den Teams-Kanal | + +### [NotificationEvents] + +Steuert, welche Ereignisse eine Benachrichtigung auslösen. Alle Ereignisse sind standardmäßig aktiviert. Details zu jedem Ereignis: siehe [Benachrichtigungen](notifications.md#benachrichtigungs-ereignisse). + +| Option | Typ | Standard | Beschreibung | +|---|---|---|---| +| `NotifyOnModuleError` | Boolean | `true` | PSWindowsUpdate-Modul konnte nicht geladen werden | +| `NotifyOnHookFailure` | Boolean | `true` | Pre-Update Hook fehlgeschlagen, Updates abgebrochen | +| `NotifyOnNoUpdates` | Boolean | `true` | Keine Updates verfügbar | +| `NotifyOnDryRun` | Boolean | `true` | Dry-Run Report mit verfügbaren Updates | +| `NotifyOnUpdateComplete` | Boolean | `true` | Zusammenfassung nach Update-Installation | +| `NotifyOnReboot` | Boolean | `true` | Neustart wird ausgeführt (immediate/delayed/scheduled) | +| `NotifyOnRebootRequired` | Boolean | `true` | Neustart nötig, aber Auto-Reboot ist deaktiviert | + ### [Hooks] | Option | Typ | Standard | Beschreibung | @@ -164,6 +185,18 @@ EmailFrom = updater@example.com EmailTo = admin@example.com,ops@example.com EmailHtmlReport = true +TeamsEnabled = true +TeamsWebhookUrl = https://xxxxx.webhook.office.com/webhookb2/... + +[NotificationEvents] +NotifyOnModuleError = true +NotifyOnHookFailure = true +NotifyOnNoUpdates = false +NotifyOnDryRun = true +NotifyOnUpdateComplete = true +NotifyOnReboot = true +NotifyOnRebootRequired = true + [Hooks] PreUpdateScript = C:\scripts\pre-update.ps1 AbortOnPreHookFailure = true diff --git a/docs/notifications.md b/docs/notifications.md index 8fb8d85..27d1673 100644 --- a/docs/notifications.md +++ b/docs/notifications.md @@ -153,18 +153,94 @@ Die Teams-Benachrichtigung wird als Adaptive Card dargestellt und enthält: ## Benachrichtigungs-Ereignisse -Das Script sendet Benachrichtigungen bei folgenden Ereignissen: +Das Script sendet Benachrichtigungen bei folgenden Ereignissen. Jedes Ereignis kann einzeln in der Sektion `[NotificationEvents]` der `config.ini` ein- oder ausgeschaltet werden. Standardmäßig sind alle Ereignisse aktiviert. -| Ereignis | Priorität | Beschreibung | -|---|---|---| -| Keine Updates | default | Keine Updates verfügbar | -| Dry-Run Report | default | Liste der verfügbaren Updates (ohne Installation) | -| Updates OK | default | Zusammenfassung aller erfolgreich installierten Updates | -| Updates mit Fehlern | high | Zusammenfassung inkl. fehlgeschlagener Updates | -| Modul-Fehler | high | PSWindowsUpdate konnte nicht geladen werden | -| Pre-Hook fehlgeschlagen | high | Pre-Update Script ist fehlgeschlagen, Updates abgebrochen | -| Neustart steht an | high | System wird neugestartet (mit Modus und Zeitpunkt) | -| Neustart erforderlich | high | Neustart nötig, aber Auto-Reboot ist deaktiviert | +### Übersicht + +| Ereignis | Config-Schlüssel | Priorität | Subject-Muster | +|---|---|---|---| +| Modul-Fehler | `NotifyOnModuleError` | high | `Windows Update FAILED - ` | +| Pre-Hook fehlgeschlagen | `NotifyOnHookFailure` | high | `Windows Update ABORTED - ` | +| Keine Updates | `NotifyOnNoUpdates` | default | `No Updates - ` | +| Dry-Run Report | `NotifyOnDryRun` | default | `Dry-Run Report - ` | +| Update-Zusammenfassung | `NotifyOnUpdateComplete` | default/high | `Updates OK - ` oder `Updates (with errors) - ` | +| Neustart wird ausgeführt | `NotifyOnReboot` | high | `Reboot - ` / `Reboot in X min - ` / `Reboot scheduled at HH:MM - ` | +| Neustart erforderlich | `NotifyOnRebootRequired` | high | `Reboot Required - ` | + +### Details zu jedem Ereignis + +#### Modul-Fehler (`NotifyOnModuleError`) + +Das PSWindowsUpdate-Modul konnte weder online (PSGallery) noch offline (lokaler Modules-Ordner) geladen werden. Das Script bricht ab, es werden keine Updates installiert. + +- **Priorität:** high +- **Subject:** `Windows Update FAILED - ` +- **Inhalt:** Fehlermeldung, dass das Modul nicht geladen werden konnte + +#### Pre-Hook fehlgeschlagen (`NotifyOnHookFailure`) + +Das in `[Hooks] PreUpdateScript` konfigurierte Script hat einen Exit-Code ≠ 0 zurückgegeben und `AbortOnPreHookFailure = true` ist gesetzt. Der Update-Prozess wird abgebrochen. + +- **Priorität:** high +- **Subject:** `Windows Update ABORTED - ` +- **Inhalt:** Exit-Code und Pfad des fehlgeschlagenen Hook-Scripts + +#### Keine Updates (`NotifyOnNoUpdates`) + +Der Update-Scan hat keine verfügbaren Windows-Updates gefunden. Das Script beendet sich regulär. + +- **Priorität:** default +- **Subject:** `No Updates - ` +- **Inhalt:** Hinweis, dass keine Updates verfügbar sind + +#### Dry-Run Report (`NotifyOnDryRun`) + +Im Dry-Run-Modus (`DryRun = true`) werden verfügbare Updates nur gemeldet, aber nicht installiert. + +- **Priorität:** default +- **Subject:** `Dry-Run Report - ` +- **Inhalt:** Liste aller verfügbaren Updates mit KB-Nummer, Titel und Größe + +#### Update-Zusammenfassung (`NotifyOnUpdateComplete`) + +Nach Abschluss der Update-Installation wird eine Zusammenfassung aller Ergebnisse gesendet. Die Priorität richtet sich danach, ob Fehler aufgetreten sind. + +- **Priorität:** default (alle erfolgreich) oder high (mindestens ein Fehler) +- **Subject:** `Updates OK - ` oder `Updates (with errors) - ` +- **Inhalt:** Hostname, Betriebssystem, Anzahl erfolgreicher/fehlgeschlagener Updates, Detail-Liste aller Updates. Per E-Mail optional als HTML-Report mit farbcodierter Tabelle (`EmailHtmlReport = true`). Per Teams als Adaptive Card mit Status-Icons. + +#### Neustart wird ausgeführt (`NotifyOnReboot`) + +Nach der Update-Installation ist ein Neustart erforderlich und `[Reboot] Enabled = true`. Je nach konfiguriertem Modus wird der Neustart sofort, verzögert oder zu einer festen Uhrzeit eingeleitet. + +- **Priorität:** high +- **Subject:** `Reboot - ` (immediate) / `Reboot in X min - ` (delayed) / `Reboot scheduled at HH:MM - ` (scheduled) +- **Inhalt:** Information über den Neustart-Zeitpunkt, inklusive Update-Details + +#### Neustart erforderlich (`NotifyOnRebootRequired`) + +Ein Neustart ist nach der Update-Installation nötig, aber der automatische Neustart ist deaktiviert (`[Reboot] Enabled = false`). Ein manueller Neustart ist erforderlich. + +- **Priorität:** high +- **Subject:** `Reboot Required - ` +- **Inhalt:** Hinweis, dass ein manueller Neustart durchgeführt werden muss + +### Einzelne Ereignisse deaktivieren + +In der Sektion `[NotificationEvents]` der `config.ini` kann jedes Ereignis individuell gesteuert werden. Beispiel — nur bei Fehlern und Reboot-Bedarf benachrichtigen: + +```ini +[NotificationEvents] +NotifyOnModuleError = true +NotifyOnHookFailure = true +NotifyOnNoUpdates = false +NotifyOnDryRun = false +NotifyOnUpdateComplete = true +NotifyOnReboot = true +NotifyOnRebootRequired = true +``` + +Wird die Sektion `[NotificationEvents]` nicht angegeben oder ein Schlüssel weggelassen, ist das jeweilige Ereignis standardmäßig **aktiviert** (`true`). ## Sicherheitshinweis diff --git a/windows-updater.ps1 b/windows-updater.ps1 index 761cb39..d62282a 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.1.0 +Version: 2.1.1 Datum: 06.07.2026 -Modifiaktione: Microsoft Teams Benachrichtigungen hinzugefügt +Modifiaktione: Notifications können detallierter konfiguriert werden, z.B. nur bei Fehlern oder nur bei Reboot erforderlich. ##################################################### #> @@ -547,14 +547,32 @@ function Send-TeamsNotification { } } +function Test-NotificationEvent { + param( + [ValidateSet('ModuleError', 'HookFailure', 'NoUpdates', 'DryRun', 'UpdateComplete', 'Reboot', 'RebootRequired')] + [string]$Event + ) + + $key = "NotifyOn$Event" + return Get-ConfigValue -Config $script:Config -Section "NotificationEvents" -Key $key -Default $true -Type bool +} + function Send-Notification { param( [string]$Subject, [string]$Body, [string]$Priority = "default", - [array]$UpdateResults = @() + [array]$UpdateResults = @(), + [string]$EventName = "" ) + if (-not [string]::IsNullOrWhiteSpace($EventName)) { + if (-not (Test-NotificationEvent -Event $EventName)) { + Write-Log "Notification event '$EventName' is disabled, skipping" + return + } + } + $ntfyEnabled = Get-ConfigValue -Config $script:Config -Section "Notification" -Key "NtfyEnabled" -Default $false -Type bool $emailEnabled = Get-ConfigValue -Config $script:Config -Section "Notification" -Key "EmailEnabled" -Default $false -Type bool $teamsEnabled = Get-ConfigValue -Config $script:Config -Section "Notification" -Key "TeamsEnabled" -Default $false -Type bool @@ -693,7 +711,7 @@ function Invoke-UpdateHook { Write-Log "Aborting update process due to pre-hook failure" -Level ERROR Send-Notification -Subject "Windows Update ABORTED - $env:COMPUTERNAME" ` -Body "Pre-update hook failed with exit code $($hookProcess.ExitCode). Update process aborted.`nHook: $scriptPath" ` - -Priority "high" + -Priority "high" -EventName "HookFailure" return $false } } @@ -964,7 +982,7 @@ function Invoke-ScheduledReboot { Write-Log "Initiating immediate reboot..." Send-Notification -Subject "Reboot - $env:COMPUTERNAME" ` -Body "System is rebooting now after Windows Updates." ` - -Priority "high" -UpdateResults @($script:UpdateResults) + -Priority "high" -UpdateResults @($script:UpdateResults) -EventName "Reboot" Start-Sleep -Seconds 5 Restart-Computer -Force } @@ -975,7 +993,7 @@ function Invoke-ScheduledReboot { Write-Log "Scheduling reboot in $delayMinutes minute(s)..." Send-Notification -Subject "Reboot in $delayMinutes min - $env:COMPUTERNAME" ` -Body "System will reboot in $delayMinutes minute(s) after Windows Updates." ` - -Priority "high" -UpdateResults @($script:UpdateResults) + -Priority "high" -UpdateResults @($script:UpdateResults) -EventName "Reboot" & shutdown /r /t $delaySec /f /c "Windows Updater: Scheduled reboot in $delayMinutes minute(s)" } "scheduled" { @@ -992,7 +1010,7 @@ function Invoke-ScheduledReboot { Write-Log "Scheduling reboot at $scheduledTime (in $([math]::Round($delaySec / 60)) minutes)..." Send-Notification -Subject "Reboot scheduled at $scheduledTime - $env:COMPUTERNAME" ` -Body "System will reboot at $scheduledTime after Windows Updates." ` - -Priority "high" -UpdateResults @($script:UpdateResults) + -Priority "high" -UpdateResults @($script:UpdateResults) -EventName "Reboot" & shutdown /r /t $delaySec /f /c "Windows Updater: Scheduled reboot at $scheduledTime" } default { @@ -1035,7 +1053,7 @@ function Start-WindowsUpdater { Write-Log "Cannot continue without PSWindowsUpdate module" -Level ERROR Send-Notification -Subject "Windows Update FAILED - $env:COMPUTERNAME" ` -Body "Failed to load PSWindowsUpdate module. No updates were installed." ` - -Priority "high" + -Priority "high" -EventName "ModuleError" exit 1 } @@ -1067,7 +1085,8 @@ function Start-WindowsUpdater { if (-not $availableUpdates -or @($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." + -Body "No Windows updates are currently available for $env:COMPUTERNAME." ` + -EventName "NoUpdates" Invoke-WingetUpgrade Invoke-UpdateHook -Phase Post | Out-Null Write-Log "Windows Updater finished (no updates)" @@ -1094,7 +1113,7 @@ function Start-WindowsUpdater { } $reportBody = $reportLines -join "`n" - Send-Notification -Subject "Dry-Run Report - $env:COMPUTERNAME" -Body $reportBody + Send-Notification -Subject "Dry-Run Report - $env:COMPUTERNAME" -Body $reportBody -EventName "DryRun" Invoke-WingetUpgrade Invoke-UpdateHook -Phase Post | Out-Null @@ -1135,7 +1154,7 @@ function Start-WindowsUpdater { Send-Notification -Subject "$subjectPrefix - $env:COMPUTERNAME" ` -Body $summaryText -Priority $priority ` - -UpdateResults @($script:UpdateResults) + -UpdateResults @($script:UpdateResults) -EventName "UpdateComplete" # --- Post-Update Hook --- Invoke-UpdateHook -Phase Post | Out-Null @@ -1149,7 +1168,7 @@ function Start-WindowsUpdater { Write-Log "Auto-reboot is disabled, manual reboot required" -Level WARN Send-Notification -Subject "Reboot Required - $env:COMPUTERNAME" ` -Body "Windows updates have been installed on $env:COMPUTERNAME but a reboot is required. Auto-reboot is disabled." ` - -Priority "high" + -Priority "high" -EventName "RebootRequired" } } else {