The Veeam, MARS, WSB and VB365 collectors each carried identical copies
of logging, ISO time conversion, property lookup, posting to the API,
config loading, TLS setup, the sent-runs state file and the 401 check,
and their installers repeated the same key prompt, locked-down config,
file copy and scheduled-task registration. These now live in
collectors/common/BackupDashboard.Collector.psm1:
- Initialize-Collector / Test-RunSent / Send-JobReport /
Test-AuthRejected / Complete-Collector for collector runs
- Write-Log, Get-ErrorText, ConvertTo-IsoTime, Get-FirstValue
- Install-CollectorTask for the shared half of each installer
Collectors find the module next to themselves (installed) or in
..\common (repo); installers copy it into Program Files beside the
collector. The diagnostic scripts stay standalone single files.
No behavior change: a harness ran each collector against its mock
(12 scenarios: dry run, two real runs against a stub API, state file,
logs, exit codes, rejected key, en-GB, backfill) before and after, and
all 84 outputs are identical. Installers, run with stand-ins for the
Windows-only commands, write identical configs and tasks; the only
differences are the module being copied and the summary line naming
the shell's path.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Checked with Get-Vb365CollectorDiagnostics.ps1 output from a VB365 8.4
server (GDC-VEEAM-04, 11 organizations, Windows PowerShell 5.1). Times
(session CreationTime/EndTime, job NextRun) are local, and property
names matched. Two fixes:
- Session log items carry their status as a Title prefix ("[Warning]
...") with no separate status property. Match on the prefix and strip
it, instead of matching words in the text, which would have pulled in
lines like "[Success] Processing site: .../error-reports"
- Retries are separate sessions (MainSessionId -> the retried session,
which has JobWillBeRetried = True). Mark them in details (retry_of,
will_retry) and say "Veeam will retry this job." on a pending retry
Mock rebuilt on the real shapes, including a warning + retry pair.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PowerShell script for the VB365 server, run hourly as a SYSTEM scheduled
task (Windows PowerShell 5.1 by default, -PwshPath for PowerShell 7).
One dashboard job per VB365 backup job and backup copy job.
- Sessions from Get-VBOJobSession (and Get-VBOCopyJobSession where
available) within the lookback window; status from session Status,
message from the session log's warning/error lines, size from
Statistics.TransferredData ("1.5 GB" -> bytes)
- One VB365 server can protect several Microsoft 365 organizations, so
the dashboard company is chosen per job: OrganizationTenants mapping,
else Tenant, else the organization's name
- Next run from the job's NextRun; empty for disabled jobs
- Get-Vb365CollectorDiagnostics.ps1 dumps jobs and sessions, showing
each DateTime's Kind (local vs UTC); installer adapted from MARS
Not yet run against a real server.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On VBR 13 a job's ScheduleOptions property is a stale snapshot: NextRun
is empty (and its LatestRunLocal years old), so every Veeam job showed
no next run and could never be flagged Overdue. GetScheduleOptions() /
Get-VBRJobScheduleOptions return the live schedule ("2026-10-09
12:15:00 AM"). Use GetScheduleOptions(), falling back to the property.
Immediate-mode backup copy jobs (IsContinuous) have a live NextRun too,
but it's a stale date months in the past, which would show as Overdue;
keep reporting no next run for them.
Parsing tries the current culture, then invariant; VBR 13's format
parsed correctly under en-CA, en-US, fr-CA and en-GB. Mock updated to
VBR 13's schedule shape.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Veeam jobs on a VBR 13 server show no next run on the dashboard. The
diagnostics script gains a section dumping each job's schedule
properties (ScheduleOptions, GetScheduleOptions(),
Get-VBRJobScheduleOptions) and the current culture, to find where VBR 13
keeps the next run.
The dashboard showed "Never" for a missing next run, which reads as
"this job will never run"; it now says "Not scheduled" (e.g. immediate
mode copy jobs).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Get-WBJob -Previous only accepts 1-100, so asking for 200 failed
collector setup on every run ("The 200 argument is greater than the
maximum allowed range of 100"). 100 still covers a 30-day backfill at
up to 3 backups a day. The mock now enforces the same range.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Checked with Get-WsbCollectorDiagnostics.ps1 output from a Server 2019
Hyper-V host (AAOG-EDM-HVR1):
- WBJob StartTime/EndTime are culture-formatted local-time strings
("10/6/2026 9:00 PM"). Parse them with the current culture: the
[datetime] cast uses the invariant (US) format and would misread
dd/MM dates, e.g. on en-CA/en-GB servers. Confirmed local, not UTC,
against the Microsoft-Windows-Backup event log
- Hyper-V backups nest VMs under a VirtualMachineList item's
SubItemList; failures, names and the items list now come from the
leaf items, falling back to a parent's SubItemFailed count
- Report size from the top-level items' BytesProcessed
- FailureLogPath is set even on success: running backups get no
message, and the log is only cited for warnings/failures
- HRESULTs are strings; conversion tolerates hex and bad values
- Mock rebuilt on the real shapes; tested under en-US and en-GB
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>
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]>
PowerShell script for servers running the MARS agent, run as a SYSTEM
scheduled task (hourly) under Windows PowerShell 5.1, which the
agent's MSOnlineBackup module targets. Each server is one dashboard job.
- Backup jobs from Get-OBJob (in progress and -Previous) within the
lookback window; restores are ignored. Completed with failed bytes
or an error reports as warning
- Next run computed from the backup and System State policy schedules;
left empty for every-N-weeks schedules to avoid false Overdue alarms
- Property reads tolerate unknown names, since the agent's object
model isn't documented; Get-MarsCollectorDiagnostics.ps1 dumps the
real structure for checking
- Install-MarsCollector.ps1 mirrors the Veeam installer; tests/MockMars.ps1
provides stand-in cmdlets
Not yet run against a real MARS agent.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The merge of add-backend-api into main committed unresolved conflicts
and corrupted uploads; the API could not import on main.
- backend/app/settings.py, deploy/backup-dashboard-api.service,
collectors/veeam/README.md: remove conflict markers, restoring the
add-backend-api versions
- backend/app/__init__.py, backend/tests/__init__.py: were 1024 null
bytes ("source code string cannot contain null bytes"); now empty
- Remove the accidental Backup-Dashboard gitlink at the repo root and a
duplicate collectors/veeam/MockVeeam.ps1 (identical to tests/)
- Restore the 60-minute collector interval from 17ee303, which the
merge reverted to 15, and update the docs to match
Co-Authored-By: Claude Opus 5.5 <[email protected]>
VBR 13's Veeam PowerShell module expects PowerShell 7, but the scheduled
task ran powershell.exe (Windows PowerShell 5.1).
- The installer finds a machine-wide pwsh.exe (Program Files, then
PATH, or -PwshPath), checks it reports major version 7+, and rejects
Microsoft Store installs, which SYSTEM can't run. All checks run
before anything is changed
- The scheduled task and printed next steps use that pwsh.exe
Co-Authored-By: Claude Opus 5.5 <[email protected]>
VBR 12+ backup copy jobs showed as Unknown. Get-VBRJob returns the copy
(policy) job, but Get-VBRBackupSession only returns sessions of its
hidden worker jobs, whose JobId matches no listed job, so they were
dropped. Confirmed on a VBR 13.0.2 server with the new diagnostics
script.
- File worker sessions under their policy job via
Session.GetJob().PolicyJobId (looked up once per worker job), and
record the source job in details.copied_from
- Add Get-VeeamCollectorDiagnostics.ps1, a read-only report of jobs,
unmatched sessions and their link properties
- Mock: backup copy policy/worker case and a session from a deleted job
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PowerShell script for the VBR server, run as a SYSTEM scheduled task.
Each run reports every Get-VBRJob job's next scheduled run and any
sessions from the lookback window (default 48h) not yet delivered in
their final state; running sessions are resent until they finish.
- Session result maps to success/warning/failed; non-Stopped states
report as running; message combines the session reason, objects that
didn't succeed, and warning/error lines from the session log
- Delivered sessions are tracked in a state file; failures are retried
next run, and a rejected API key stops the run immediately
- Install-VeeamCollector.ps1 writes an ACL-restricted config, copies
the script to Program Files and registers the task
- tests/MockVeeam.ps1 provides stand-in cmdlets for testing without VBR
Co-Authored-By: Claude Opus 5.5 <[email protected]>
manage.py only found the database via BACKUP_DASH_DB, which is set in
the systemd unit and not in an admin's shell, so it silently created a
new backup-dashboard.db in the current directory. API keys created
there were never seen by the service.
- Settings now come from /etc/backup-dashboard/backup-dashboard.env,
which both the systemd unit (EnvironmentFile=) and manage.py read;
real environment variables still take precedence
- manage.py prints the database it uses and refuses to create a new
one unless --create is passed; --db overrides the path
Co-Authored-By: Claude Opus 5.5 <[email protected]>