PowerShell script for servers using Windows Server Backup, run hourly as a SYSTEM scheduled task under Windows PowerShell 5.1. Each server is one dashboard job. - Backup jobs from Get-WBJob (in progress and -Previous) within the lookback window; restores are ignored. WSB jobs have no ID, so runs are keyed on start time, which also merges a Running report with the finished one - Error HRESULT -> failed; detailed error or a failed item -> warning; messages include the error description, codes as 0x8XXXXXXX, failed items and the failure log path - Next run from Get-WBSummary's NextBackupTime - Get-WsbCollectorDiagnostics.ps1 dumps the cmdlets' real objects and recent Microsoft-Windows-Backup events (to check whether job times are local or UTC); installer adapted from the MARS one Not yet run against a real server. Co-Authored-By: Claude Opus 5.5 <[email protected]>
104 lines
3.8 KiB
PowerShell
104 lines
3.8 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Read-only dump of what the Windows Server Backup cmdlets return, for troubleshooting the collector.
|
|
|
|
.DESCRIPTION
|
|
The collector reads properties of Get-WBJob / Get-WBSummary results whose names and time zones
|
|
aren't fully documented. This prints those objects' real structure (property names, types and
|
|
values, a few levels deep), plus recent events from the Microsoft-Windows-Backup log, whose
|
|
timestamps are reliable local times to compare against. Nothing is changed. Output is also
|
|
saved to a text file.
|
|
|
|
.EXAMPLE
|
|
.\Get-WsbCollectorDiagnostics.ps1
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[int]$Jobs = 3,
|
|
[int]$Events = 15,
|
|
[string]$OutFile = (Join-Path $env:TEMP 'wsb-collector-diagnostics.txt')
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$MaxDepth = 6
|
|
|
|
if (-not (Get-Command Get-WBJob -ErrorAction SilentlyContinue)) {
|
|
Import-Module WindowsServerBackup
|
|
}
|
|
|
|
function Test-Scalar($Value) {
|
|
return $null -eq $Value -or $Value -is [string] -or $Value -is [ValueType] -or $Value -is [guid]
|
|
}
|
|
|
|
# Recursive "name (type) = value" listing. Collections show their first 3 items.
|
|
function Show-Object($Value, [string]$Indent = ' ', [int]$Depth = 0) {
|
|
if (Test-Scalar $Value) { return }
|
|
if ($Depth -ge $MaxDepth) { "$Indent..."; return }
|
|
if ($Value -is [Collections.IEnumerable]) {
|
|
$items = @($Value)
|
|
"$Indent[$($items.Count) item(s)]"
|
|
$i = 0
|
|
foreach ($item in $items | Select-Object -First 3) {
|
|
"$Indent[$i] ($($item.GetType().FullName))$(if (Test-Scalar $item) { " = $item" })"
|
|
Show-Object $item "$Indent " ($Depth + 1)
|
|
$i++
|
|
}
|
|
return
|
|
}
|
|
foreach ($p in $Value.PSObject.Properties) {
|
|
try { $v = $p.Value } catch { "$Indent$($p.Name) = <error: $($_.Exception.Message)>"; continue }
|
|
$type = if ($null -eq $v) { 'null' } else { $v.GetType().FullName }
|
|
if (Test-Scalar $v) {
|
|
"$Indent$($p.Name) ($type) = $v"
|
|
} else {
|
|
$text = [string]$v
|
|
if ($text.Length -gt 100) { $text = $text.Substring(0, 97) + '...' }
|
|
"$Indent$($p.Name) ($type) = $text"
|
|
Show-Object $v "$Indent " ($Depth + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
function Show-Section([string]$Title, [scriptblock]$Get) {
|
|
"== $Title"
|
|
try {
|
|
$result = @(& $Get)
|
|
if ($result.Count -eq 0 -or ($result.Count -eq 1 -and $null -eq $result[0])) { ' (nothing returned)' }
|
|
$n = 0
|
|
foreach ($item in $result) {
|
|
if ($null -eq $item) { continue }
|
|
" [$n] ($($item.GetType().FullName))"
|
|
Show-Object $item ' '
|
|
$n++
|
|
}
|
|
} catch {
|
|
" error: $($_.Exception.Message)"
|
|
}
|
|
''
|
|
}
|
|
|
|
$report = & {
|
|
"Generated $(Get-Date -Format o) on $env:COMPUTERNAME, PowerShell $($PSVersionTable.PSVersion)"
|
|
"Local time zone: $([TimeZoneInfo]::Local.Id), UTC offset now $([TimeZoneInfo]::Local.GetUtcOffset((Get-Date)))"
|
|
''
|
|
Show-Section 'Get-WBSummary' { Get-WBSummary }
|
|
Show-Section 'Get-WBJob (in progress)' { Get-WBJob }
|
|
Show-Section "Get-WBJob -Previous $Jobs" { Get-WBJob -Previous $Jobs }
|
|
Show-Section 'Get-WBPolicy | Get-WBSchedule' {
|
|
$policy = Get-WBPolicy
|
|
if ($policy) { Get-WBSchedule -Policy $policy } else { '(no scheduled backup policy)' }
|
|
}
|
|
"== Microsoft-Windows-Backup event log (last $Events, local times)"
|
|
try {
|
|
Get-WinEvent -LogName 'Microsoft-Windows-Backup' -MaxEvents $Events |
|
|
Select-Object TimeCreated, Id, LevelDisplayName, @{ n = 'Message'; e = { ($_.Message -split "`r?`n")[0] } } |
|
|
Format-Table -AutoSize -Wrap | Out-String -Width 300
|
|
} catch {
|
|
" error: $($_.Exception.Message)"
|
|
}
|
|
} | Out-String -Width 300
|
|
|
|
$report
|
|
$report | Set-Content -Path $OutFile -Encoding UTF8
|
|
Write-Host "Saved to $OutFile"
|