Service-Watchdog: Dienste nach Updates ohne Reboot neu starten und überwachen
This commit is contained in:
@@ -84,6 +84,19 @@ NotifyOnUpdateComplete = true
|
||||
NotifyOnReboot = true
|
||||
# Reboot required but auto-reboot is disabled
|
||||
NotifyOnRebootRequired = true
|
||||
# Service Watchdog failed to restart one or more services
|
||||
NotifyOnServiceRestartFailure = true
|
||||
|
||||
[ServiceWatchdog]
|
||||
# Enable service watchdog: restart specific services after updates when no reboot is required
|
||||
Enabled = false
|
||||
# Comma-separated list of Windows service names to restart (use the service name, not the display name)
|
||||
# Example: Services = Spooler,W3SVC,MSSQLSERVER
|
||||
Services =
|
||||
# Seconds to wait for each service to reach Running state (default: 30)
|
||||
WaitSeconds = 30
|
||||
# Number of restart attempts per service (default: 3)
|
||||
RetryCount = 3
|
||||
|
||||
[Hooks]
|
||||
# Path to PowerShell script to execute BEFORE updates (leave empty to disable)
|
||||
|
||||
@@ -82,6 +82,16 @@ Steuert, welche Ereignisse eine Benachrichtigung auslösen. Alle Ereignisse sind
|
||||
| `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 |
|
||||
| `NotifyOnServiceRestartFailure` | Boolean | `true` | Service-Watchdog konnte einen oder mehrere Dienste nicht starten |
|
||||
|
||||
### [ServiceWatchdog]
|
||||
|
||||
| Option | Typ | Standard | Beschreibung |
|
||||
|---|---|---|---|
|
||||
| `Enabled` | Boolean | `false` | Service-Watchdog aktivieren: Dienste nach Updates neu starten, wenn kein Reboot erforderlich ist |
|
||||
| `Services` | String | *(leer)* | Kommagetrennte Liste von Windows-Dienstnamen (Service Name, nicht Display Name), z.B. `Spooler,W3SVC,MSSQLSERVER` |
|
||||
| `WaitSeconds` | Integer | `30` | Wartezeit in Sekunden, bis ein Dienst den Status "Running" erreicht hat |
|
||||
| `RetryCount` | Integer | `3` | Anzahl Neustartversuche pro Dienst |
|
||||
|
||||
### [Hooks]
|
||||
|
||||
@@ -196,6 +206,13 @@ NotifyOnDryRun = true
|
||||
NotifyOnUpdateComplete = true
|
||||
NotifyOnReboot = true
|
||||
NotifyOnRebootRequired = true
|
||||
NotifyOnServiceRestartFailure = true
|
||||
|
||||
[ServiceWatchdog]
|
||||
Enabled = true
|
||||
Services = Spooler,W3SVC
|
||||
WaitSeconds = 30
|
||||
RetryCount = 3
|
||||
|
||||
[Hooks]
|
||||
PreUpdateScript = C:\scripts\pre-update.ps1
|
||||
|
||||
@@ -166,6 +166,7 @@ Das Script sendet Benachrichtigungen bei folgenden Ereignissen. Jedes Ereignis k
|
||||
| Update-Zusammenfassung | `NotifyOnUpdateComplete` | default/high | `Updates OK - <Hostname>` oder `Updates (with errors) - <Hostname>` |
|
||||
| Neustart wird ausgeführt | `NotifyOnReboot` | high | `Reboot - <Hostname>` / `Reboot in X min - <Hostname>` / `Reboot scheduled at HH:MM - <Hostname>` |
|
||||
| Neustart erforderlich | `NotifyOnRebootRequired` | high | `Reboot Required - <Hostname>` |
|
||||
| Dienst-Neustart fehlgeschlagen | `NotifyOnServiceRestartFailure` | high | `Service Restart FAILED - <Hostname>` |
|
||||
|
||||
### Details zu jedem Ereignis
|
||||
|
||||
@@ -225,6 +226,14 @@ Ein Neustart ist nach der Update-Installation nötig, aber der automatische Neus
|
||||
- **Subject:** `Reboot Required - <Hostname>`
|
||||
- **Inhalt:** Hinweis, dass ein manueller Neustart durchgeführt werden muss
|
||||
|
||||
#### Dienst-Neustart fehlgeschlagen (`NotifyOnServiceRestartFailure`)
|
||||
|
||||
Der Service-Watchdog konnte einen oder mehrere konfigurierte Dienste nach den Updates nicht starten. Der Watchdog wird nur ausgeführt, wenn kein Neustart erforderlich ist (`[ServiceWatchdog] Enabled = true`).
|
||||
|
||||
- **Priorität:** high
|
||||
- **Subject:** `Service Restart FAILED - <Hostname>`
|
||||
- **Inhalt:** Liste der betroffenen Dienste mit Fehlerbeschreibung (Dienst nicht gefunden, alle Versuche fehlgeschlagen)
|
||||
|
||||
### Einzelne Ereignisse deaktivieren
|
||||
|
||||
In der Sektion `[NotificationEvents]` der `config.ini` kann jedes Ereignis individuell gesteuert werden. Beispiel — nur bei Fehlern und Reboot-Bedarf benachrichtigen:
|
||||
@@ -238,6 +247,7 @@ NotifyOnDryRun = false
|
||||
NotifyOnUpdateComplete = true
|
||||
NotifyOnReboot = true
|
||||
NotifyOnRebootRequired = true
|
||||
NotifyOnServiceRestartFailure = true
|
||||
```
|
||||
|
||||
Wird die Sektion `[NotificationEvents]` nicht angegeben oder ein Schlüssel weggelassen, ist das jeweilige Ereignis standardmäßig **aktiviert** (`true`).
|
||||
|
||||
+88
-3
@@ -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.1
|
||||
Version: 2.2.0
|
||||
Datum: 06.07.2026
|
||||
Modifiaktione: Notifications können detallierter konfiguriert werden, z.B. nur bei Fehlern oder nur bei Reboot erforderlich.
|
||||
Modifiaktione: Service-Watchdog: Dienste nach Updates ohne Reboot neu starten und überwachen.
|
||||
#####################################################
|
||||
#>
|
||||
|
||||
@@ -549,7 +549,7 @@ function Send-TeamsNotification {
|
||||
|
||||
function Test-NotificationEvent {
|
||||
param(
|
||||
[ValidateSet('ModuleError', 'HookFailure', 'NoUpdates', 'DryRun', 'UpdateComplete', 'Reboot', 'RebootRequired')]
|
||||
[ValidateSet('ModuleError', 'HookFailure', 'NoUpdates', 'DryRun', 'UpdateComplete', 'Reboot', 'RebootRequired', 'ServiceRestartFailure')]
|
||||
[string]$Event
|
||||
)
|
||||
|
||||
@@ -1024,6 +1024,89 @@ function Invoke-ScheduledReboot {
|
||||
|
||||
#endregion
|
||||
|
||||
# ===================================================
|
||||
#region Service Watchdog
|
||||
# ===================================================
|
||||
|
||||
function Invoke-ServiceWatchdog {
|
||||
$watchdogEnabled = Get-ConfigValue -Config $script:Config -Section "ServiceWatchdog" -Key "Enabled" -Default $false -Type bool
|
||||
if (-not $watchdogEnabled) { return }
|
||||
|
||||
$serviceList = Get-ConfigValue -Config $script:Config -Section "ServiceWatchdog" -Key "Services" -Default ""
|
||||
if ([string]::IsNullOrWhiteSpace($serviceList)) {
|
||||
Write-Log "ServiceWatchdog enabled but no services configured" -Level WARN
|
||||
return
|
||||
}
|
||||
|
||||
$services = $serviceList -split ',' | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
||||
if ($services.Count -eq 0) { return }
|
||||
|
||||
$waitSeconds = Get-ConfigValue -Config $script:Config -Section "ServiceWatchdog" -Key "WaitSeconds" -Default 30 -Type int
|
||||
$retryCount = Get-ConfigValue -Config $script:Config -Section "ServiceWatchdog" -Key "RetryCount" -Default 3 -Type int
|
||||
|
||||
Write-Log "Service Watchdog: Restarting $($services.Count) service(s)..."
|
||||
|
||||
$failedServices = [System.Collections.ArrayList]::new()
|
||||
|
||||
foreach ($svcName in $services) {
|
||||
Write-Log " Restarting service: $svcName"
|
||||
|
||||
$svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
|
||||
if (-not $svc) {
|
||||
Write-Log " Service '$svcName' not found on this system" -Level ERROR
|
||||
$failedServices.Add([PSCustomObject]@{ Name = $svcName; Reason = "Service not found" }) | Out-Null
|
||||
continue
|
||||
}
|
||||
|
||||
$started = $false
|
||||
for ($attempt = 1; $attempt -le $retryCount; $attempt++) {
|
||||
try {
|
||||
if ($attempt -eq 1) {
|
||||
Restart-Service -Name $svcName -Force -ErrorAction Stop
|
||||
}
|
||||
else {
|
||||
Start-Service -Name $svcName -ErrorAction Stop
|
||||
}
|
||||
|
||||
$svc.WaitForStatus([System.ServiceProcess.ServiceControllerStatus]::Running, [TimeSpan]::FromSeconds($waitSeconds))
|
||||
$svc.Refresh()
|
||||
|
||||
if ($svc.Status -eq 'Running') {
|
||||
Write-Log " Service '$svcName' is running (attempt $attempt/$retryCount)"
|
||||
$started = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Log " Attempt $attempt/$retryCount for '$svcName' failed: $($_.Exception.Message)" -Level WARN
|
||||
if ($attempt -lt $retryCount) {
|
||||
Start-Sleep -Seconds 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $started) {
|
||||
$svc.Refresh()
|
||||
Write-Log " Service '$svcName' could not be started (status: $($svc.Status))" -Level ERROR
|
||||
$failedServices.Add([PSCustomObject]@{ Name = $svcName; Reason = "Failed after $retryCount attempts (status: $($svc.Status))" }) | Out-Null
|
||||
$script:HasErrors = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($failedServices.Count -gt 0) {
|
||||
$failList = ($failedServices | ForEach-Object { " - $($_.Name): $($_.Reason)" }) -join "`n"
|
||||
$body = "Service Watchdog on $env:COMPUTERNAME failed to restart $($failedServices.Count) service(s):`n$failList"
|
||||
Write-Log "Service Watchdog: $($failedServices.Count) service(s) failed" -Level ERROR
|
||||
Send-Notification -Subject "Service Restart FAILED - $env:COMPUTERNAME" `
|
||||
-Body $body -Priority "high" -EventName "ServiceRestartFailure"
|
||||
}
|
||||
else {
|
||||
Write-Log "Service Watchdog: All services restarted successfully"
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
# ===================================================
|
||||
#region Main Execution
|
||||
# ===================================================
|
||||
@@ -1173,6 +1256,8 @@ function Start-WindowsUpdater {
|
||||
}
|
||||
else {
|
||||
Write-Log "No reboot required"
|
||||
# --- Service Watchdog (only when no reboot is pending) ---
|
||||
Invoke-ServiceWatchdog
|
||||
}
|
||||
|
||||
# --- Finish ---
|
||||
|
||||
Reference in New Issue
Block a user