Files
Backup-Dashboard/collectors/mars/Get-MarsCollectorDiagnostics.ps1
kyleandClaude Opus 5.5 5982fc9434 Fix MARS collector against a real agent's object model
Checked with Get-MarsCollectorDiagnostics.ps1 output from MARS agent
2.0.9274 (VA-FS-01):

- JobStatus.StartTime/EndTime are UTC values not marked as UTC
  (DisplayTime is the local one); they were read as local, putting
  runs 6 hours off. Lookback filtering now compares in UTC too
- ErrorInfo is always present with ErrorCode 0 on success; every
  completed backup would have been a warning. Only non-zero error
  codes count
- Schedule times are TimeSpans; casting them to DateTime failed, so
  next_run_at was always empty
- DatasourceStatus.Datasource is an object; use its DataSourceName
- Also report FileProgress.Failed file counts and FailedFileLog
- Mock rebuilt on the real shapes; diagnostics handle no System State
  policy

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 15:40:08 -06:00

103 lines
3.7 KiB
PowerShell

<#
.SYNOPSIS
Read-only dump of what the MARS agent's cmdlets return, for troubleshooting the collector.
.DESCRIPTION
The collector reads properties of Get-OBJob / Get-OBPolicy / Get-OBSchedule results whose names
aren't documented. This prints those objects' real structure (property names, types and values,
a few levels deep) so mismatches can be fixed. Nothing is changed. Output is also saved to a
text file.
.EXAMPLE
.\Get-MarsCollectorDiagnostics.ps1
#>
[CmdletBinding()]
param(
[int]$Jobs = 3,
[string]$OutFile = (Join-Path $env:TEMP 'mars-collector-diagnostics.txt')
)
$ErrorActionPreference = 'Stop'
$MaxDepth = 6
if (-not (Get-Command Get-OBJob -ErrorAction SilentlyContinue)) {
if (Get-Module -ListAvailable -Name MSOnlineBackup) {
Import-Module MSOnlineBackup
} else {
Import-Module (Join-Path $env:ProgramFiles 'Microsoft Azure Recovery Services Agent\bin\Modules\MSOnlineBackup')
}
}
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 = & {
$agent = try {
(Get-Item (Join-Path $env:ProgramFiles 'Microsoft Azure Recovery Services Agent\bin\cbengine.exe')).VersionInfo.ProductVersion
} catch { 'unknown' }
"Generated $(Get-Date -Format o) on $env:COMPUTERNAME, MARS agent $agent, PowerShell $($PSVersionTable.PSVersion)"
''
Show-Section 'Get-OBJob (in progress)' { Get-OBJob }
Show-Section "Get-OBJob -Previous $Jobs" { Get-OBJob -Previous $Jobs }
Show-Section 'Get-OBPolicy' { Get-OBPolicy }
Show-Section 'Get-OBPolicy | Get-OBSchedule' { Get-OBSchedule -Policy (Get-OBPolicy) }
if (Get-Command Get-OBSystemStatePolicy -ErrorAction SilentlyContinue) {
Show-Section 'Get-OBSystemStatePolicy | Get-OBSchedule' {
$ssPolicy = Get-OBSystemStatePolicy
if ($ssPolicy) { Get-OBSchedule -Policy $ssPolicy } else { '(no System State policy configured)' }
}
}
} | Out-String -Width 300
$report
$report | Set-Content -Path $OutFile -Encoding UTF8
Write-Host "Saved to $OutFile"