diff --git a/Misc/Fix-VSSBackup.ps1 b/Misc/Fix-VSSBackup.ps1 new file mode 100644 index 0000000..12a51d7 --- /dev/null +++ b/Misc/Fix-VSSBackup.ps1 @@ -0,0 +1,217 @@ +<# +.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) + ) +) + +# ---------- 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:$Force.IsPresent + } + + 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 +} \ No newline at end of file