<# .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) = "; 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"