Add Misc/Fix-VSSBackup.ps1
This commit is contained in:
217
Misc/Fix-VSSBackup.ps1
Normal file
217
Misc/Fix-VSSBackup.ps1
Normal file
@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user