<# .SYNOPSIS Herstart relevante services wanneer een VSS back-up is mislukt. .DESCRIPTION - Zoekt in de Event Logs (Application/System) naar recente VSS-fouten. - (Optioneel) Controleert VSS-writers via 'vssadmin list writers' op Failed. - Herstart een configureerbare set van VSS-gerelateerde services. - Logt acties naar bestand en uitvoer; verifieert na afloop de writer-status. .PARAMETER LookbackMinutes Periode (minuten) om terug te kijken voor VSS-fouten in Event Logs. .PARAMETER RequireFailedWriter Alleen services herstarten als er daadwerkelijk één of meer VSS-writers in Failed staan. .PARAMETER Force Stop-Service gebruikt -Force wanneer nodig. .PARAMETER LogPath Pad naar logbestand. .PARAMETER ServiceList Overschrijf de standaardlijst met te herstarten services (servicenamen, niet weergavenamen). .NOTES - Run als Administrator. - Pas de standaard ServiceList aan voor de betreffende serverrol(len). #> [CmdletBinding()] param( [int]$LookbackMinutes = 60, [switch]$RequireFailedWriter, [switch]$Force, [string]$LogPath = "C:\Windows\Temp\VSS-Restart-$(Get-Date -Format 'yyyyMMdd_HHmmss').log", [string[]]$ServiceList = @( # Kern VSS 'VSS', # Volume Shadow Copy 'SwPrv', # Microsoft Software Shadow Copy Provider 'EventSystem', # COM+ Event System 'COMSysApp', # COM+ System Application (soms niet nodig/aanwezig) # Veelvoorkomende writers (pas aan op rol) 'SQLWriter', # SQL Server VSS Writer (indien aanwezig) 'IISADMIN', # IIS Admin Service (indien aanwezig) 'W3SVC', # World Wide Web Publishing (indien aanwezig) 'BITS', # Background Intelligent Transfer Service (soms storend bij backups) 'wbengine', # Windows Backup Engine (indien gebruikt) # Hyper-V (host of guest; alleen herstarten als aanwezig) 'vmicvss', # Hyper-V Volume Shadow Copy Requestor (Guest service) 'vmms' # Hyper-V Virtual Machine Management (Host) ) ) # ---------- Auto-defaults wanneer GEEN parameters zijn meegegeven ---------- $NoParams = ($PSBoundParameters.Count -eq 0) if ($NoParams) { try { if (-not (Test-Path -LiteralPath 'C:\Temp')) { New-Item -ItemType Directory -Path 'C:\Temp' -Force | Out-Null } } catch {} $LogPath = "C:\Temp\VSS-Restart-$(Get-Date -Format 'yyyyMMdd_HHmmss').log" } # Force-effectiviteit wordt later bepaald met $ForceEffective i.p.v. $Force direct te wijzigen $ForceEffective = ($NoParams -or $Force.IsPresent) # ---------- Helpers ---------- function Write-Log { param([string]$Message) $stamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss') $line = "[$stamp] $Message" Write-Output $line try { Add-Content -Path $LogPath -Value $line -Encoding UTF8 -ErrorAction Stop } catch {} } function Test-VssErrors { param([int]$Minutes) $since = (Get-Date).AddMinutes(-$Minutes) $filters = @( @{ LogName='Application'; ProviderName='VSS' }, @{ LogName='System'; ProviderName='VolSnap' }, # Volsnap driver errors @{ LogName='Application'; ProviderName='Backup' }, # Sommige backupapps loggen onder 'Backup' @{ LogName='Application'; ProviderName='Windows Server Backup' } # WSB ) $events = foreach ($f in $filters) { try { Get-WinEvent -FilterHashtable @{ LogName = $f.LogName ProviderName = $f.ProviderName Level = 2 # Error StartTime = $since } -ErrorAction SilentlyContinue } catch {} } $hasErrors = $false if ($events) { $hasErrors = $true Write-Log "VSS/VOLSNAP/Backup fouten gevonden sinds ${since}:" $events | Sort-Object TimeCreated -Descending | Select-Object -First 10 | ForEach-Object { Write-Log (" {0:u} {1} {2}: {3}" -f $_.TimeCreated, $_.ProviderName, $_.Id, ($_.Message -replace '\r?\n',' ')) } } else { Write-Log "Geen VSS-gerelateerde fouten gevonden sinds $since." } return $hasErrors } function Get-VssWriterStatus { # Parse 'vssadmin list writers' op Failed writers $failed = @() $all = @() $output = & vssadmin list writers 2>$null if (-not $output) { Write-Log "Kon 'vssadmin list writers' niet uitvoeren of geen output." return ,@(),@() } $current = [ordered]@{ Writer=''; State=''; LastError='' } foreach ($line in $output) { if ($line -match "^\s*Writer name:\s+'(.+?)'") { if ($current.Writer) { $all += [pscustomobject]$current } $current = [ordered]@{ Writer=$matches[1]; State=''; LastError='' } } elseif ($line -match '^\s*State:\s+\[(\d+)\]\s+(.+)$') { $current.State = "$($matches[1]) $($matches[2])" } elseif ($line -match '^\s*Last error:\s+(.+)$') { $current.LastError = $matches[1] } } if ($current.Writer) { $all += [pscustomobject]$current } foreach ($w in $all) { if ($w.State -match '^\s*9\b|Failed') { $failed += $w } } return ,$failed,$all } function Restart-ServiceSafe { param( [string]$Name, [switch]$ForceStop ) try { $svc = Get-Service -Name $Name -ErrorAction Stop } catch { Write-Log "Service '$Name' niet gevonden; overslaan." return } # Sommige services zijn al gestopt of disabled if ($svc.Status -eq 'Running') { Write-Log "Stoppen service '$Name'..." try { if ($ForceStop) { Stop-Service -Name $Name -Force -ErrorAction Stop } else { Stop-Service -Name $Name -ErrorAction Stop } $svc.WaitForStatus('Stopped','00:00:20') } catch { Write-Log "Kon service '$Name' niet stoppen: $($_.Exception.Message)" } } else { Write-Log "Service '$Name' is niet Running (status=$($svc.Status)); stop stap overslaan." } Write-Log "Starten service '$Name'..." try { Start-Service -Name $Name -ErrorAction Stop (Get-Service -Name $Name).WaitForStatus('Running','00:00:20') Write-Log "Service '$Name' draait." } catch { Write-Log "Kon service '$Name' niet starten: $($_.Exception.Message)" } } # ---------- Main ---------- Write-Log "=== VSS Service Restart Script gestart op $(hostname) ===" Write-Log "Logbestand: $LogPath" $hasVssErrors = Test-VssErrors -Minutes $LookbackMinutes $failedWriters = @() $allWriters = @() $failedWriters, $allWriters = Get-VssWriterStatus if ($failedWriters.Count -gt 0) { Write-Log "VSS-writers in FAILED staat:" $failedWriters | ForEach-Object { Write-Log (" {0} | State={1} | LastError={2}" -f $_.Writer, $_.State, $_.LastError) } } else { Write-Log "Geen FAILED VSS-writers gedetecteerd." } $shouldAct = $hasVssErrors -or ($failedWriters.Count -gt 0) if ($RequireFailedWriter -and $failedWriters.Count -eq 0) { $shouldAct = $false Write-Log "RequireFailedWriter is ingeschakeld en er zijn geen failed writers; geen services herstart." } if ($shouldAct) { Write-Log "Services worden herstart. Aantal in lijst: $($ServiceList.Count)." foreach ($svcName in $ServiceList) { Restart-ServiceSafe -Name $svcName -ForceStop:$ForceEffective } Start-Sleep -Seconds 5 Write-Log "Hercontrole VSS-writers na herstart..." $failedAfter, $allAfter = Get-VssWriterStatus if ($failedAfter.Count -eq 0) { Write-Log "Alle VSS-writers zijn nu OK." exit 0 } else { Write-Log "Nog steeds FAILED VSS-writers na herstart:" $failedAfter | ForEach-Object { Write-Log (" {0} | State={1} | LastError={2}" -f $_.Writer, $_.State, $_.LastError) } exit 2 } } else { Write-Log "Geen actie ondernomen; geen relevante fouten binnen de lookback of policy verhindert actie." exit 0 }