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]>
69 lines
3.2 KiB
PowerShell
69 lines
3.2 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Installs the Veeam collector on a VBR server as a SYSTEM scheduled task.
|
|
|
|
.DESCRIPTION
|
|
- Copies Send-VeeamBackupStatus.ps1 to Program Files (only admins can modify it, which
|
|
matters because it runs as SYSTEM).
|
|
- Writes the config to ProgramData\BackupDashboard and restricts that folder to SYSTEM and
|
|
Administrators, since it contains the API key.
|
|
- Registers a scheduled task that runs every IntervalMinutes under PowerShell 7 (pwsh.exe),
|
|
which the Veeam module on VBR 13 expects. Install PowerShell 7 machine-wide (MSI or winget)
|
|
first: Microsoft Store installs can't be run by SYSTEM.
|
|
Safe to re-run to change settings or update the script.
|
|
|
|
.EXAMPLE
|
|
.\Install-VeeamCollector.ps1 -ApiUrl https://backups.example.com -Tenant "Acme Corp"
|
|
(prompts for the API key)
|
|
#>
|
|
#Requires -RunAsAdministrator
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)][string]$ApiUrl,
|
|
[Parameter(Mandatory)][string]$Tenant,
|
|
[string]$SourceSystem = 'Veeam B&R',
|
|
[ValidateRange(5, 1440)][int]$IntervalMinutes = 60,
|
|
[ValidateRange(1, 720)][int]$LookbackHours = 48,
|
|
[string]$InstallDir = (Join-Path $env:ProgramFiles 'BackupDashboard'),
|
|
# Defaults to the machine-wide PowerShell 7 install
|
|
[string]$PwshPath
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# Find PowerShell 7 before changing anything, so a missing install fails cleanly
|
|
if (-not $PwshPath) {
|
|
$PwshPath = Join-Path $env:ProgramFiles 'PowerShell\7\pwsh.exe'
|
|
if (-not (Test-Path $PwshPath)) {
|
|
$onPath = Get-Command pwsh.exe -ErrorAction SilentlyContinue
|
|
if ($onPath) { $PwshPath = $onPath.Source }
|
|
}
|
|
}
|
|
if (-not (Test-Path $PwshPath)) {
|
|
throw "PowerShell 7 not found at '$PwshPath'. Install it machine-wide (e.g. winget install Microsoft.PowerShell) or pass -PwshPath."
|
|
}
|
|
if ($PwshPath -match '\\WindowsApps\\') {
|
|
throw "'$PwshPath' is a Microsoft Store install, which the SYSTEM account can't run. Install the MSI or winget version instead."
|
|
}
|
|
$pwshVersion = & $PwshPath -NoProfile -NonInteractive -Command '$PSVersionTable.PSVersion.ToString()'
|
|
$pwshMajor = & $PwshPath -NoProfile -NonInteractive -Command '$PSVersionTable.PSVersion.Major'
|
|
if ($LASTEXITCODE -or ($pwshMajor -as [int]) -lt 7) {
|
|
throw "'$PwshPath' isn't a working PowerShell 7 (reported '$pwshVersion')."
|
|
}
|
|
|
|
# Shared installer code: in the repo it's in ..\common, so copy the whole collectors folder
|
|
$sharedModule = @(
|
|
(Join-Path $PSScriptRoot 'BackupDashboard.Collector.psm1'),
|
|
(Join-Path (Join-Path (Join-Path $PSScriptRoot '..') 'common') 'BackupDashboard.Collector.psm1')
|
|
) | Where-Object { Test-Path $_ } | Select-Object -First 1
|
|
if (-not $sharedModule) {
|
|
throw "BackupDashboard.Collector.psm1 not found. Copy the whole collectors folder, including common."
|
|
}
|
|
Import-Module $sharedModule -Force
|
|
|
|
$settings = [ordered]@{ Tenant = $Tenant; SourceSystem = $SourceSystem; LookbackHours = $LookbackHours }
|
|
Install-CollectorTask -Name 'veeam' -ScriptPath (Join-Path $PSScriptRoot 'Send-VeeamBackupStatus.ps1') `
|
|
-TaskName 'Backup Dashboard - Veeam collector' `
|
|
-TaskDescription 'Sends Veeam job results to the Backup Dashboard' `
|
|
-Shell $PwshPath -ApiUrl $ApiUrl -IntervalMinutes $IntervalMinutes -InstallDir $InstallDir -Settings $settings
|