Guide technique ANYSYS · vérifié le 26 octobre 2026
Veeam ONE 13 : API REST et rapport PowerShell en lecture seule

Authentification OAuth, pagination et filtres de l’API REST Veeam ONE 2.3, puis un script PowerShell qui relève, sans rien modifier, les serveurs VBR, les alarmes actives et les VM dont la dernière sauvegarde est trop ancienne. Pour Veeam ONE 13.1.
01 / Périmètre
Périmètre : une API documentée pour la v13
L’API REST de Veeam ONE est documentée officiellement par Veeam pour la version 13 : la référence Veeam ONE REST API 2.3 indique s’appliquer au build 13.1.0.7034. Ce guide cible donc Veeam ONE 13.1 (correctif P0 : 13.1.0.7233) et l’API en version 2.3.
- URL de base :
https://<hostname>:<port>/api/<version>, où hostname est la machine qui héberge Veeam ONE Web Services. - Port : celui choisi à l’installation de Web Services, 1239 par défaut (le même que le Web Client).
- Méthodes : GET lit une ressource ou une collection, POST crée une ressource ou déclenche une action, PATCH modifie une ressource ou exécute une opération (par exemple le planning de collecte ou la mise à jour de licence).
- Une interface Swagger UI est disponible sur
https://<hostname>:<port>/swagger/index.htmlpour explorer l’API.
02 / Authentification
Authentification OAuth 2.0
L’autorisation suit OAuth 2.0 : le client obtient un jeton d’accès et un jeton de rafraîchissement.
- 01
Ouverture :
POST /api/token, corpsapplication/x-www-form-urlencodedavecgrant_type=password,usernameetpassword. Si la MFA est activée sur le compte, le code est passé dans l’en-têteVeeam-Mfa-Code. - 02
Appels : en-tête
Authorization: Bearer <access_token>. - 03
Rafraîchissement :
POST /api/tokenavecgrant_type=refresh_tokenet le jeton de rafraîchissement sauvegardé. - 04
Fermeture :
POST /api/revokeavec le jeton d’accès. Avec le paramètretoken, seul ce jeton est révoqué ; les autres jetons obtenus restent actifs.
# Ouverture de session (aucune modification de configuration)
$cred = Get-Credential
$body = @{ grant_type = 'password'; username = $cred.UserName; password = $cred.GetNetworkCredential().Password }
$tok = Invoke-RestMethod -Method Post -Uri 'https://vone01.contoso.local:1239/api/token' `
-Body $body -ContentType 'application/x-www-form-urlencoded'
$h = @{ Authorization = "Bearer $($tok.access_token)" }
# Lecture
Invoke-RestMethod -Uri 'https://vone01.contoso.local:1239/api/v2.3/about' -Headers $h
# Fermeture de session
Invoke-RestMethod -Method Post -Uri 'https://vone01.contoso.local:1239/api/revoke' -Headers $h `
-Body @{ token = $tok.access_token } -ContentType 'application/x-www-form-urlencoded'03 / Sécurité
Compte, secret et certificat
- Compte dédié à l’automatisation, jamais un administrateur personnel. L’exemple de la documentation utilise un administrateur local (rôle Admin dans la réponse) ; Veeam ONE propose aussi le groupe Veeam ONE Read-Only Users. Le comportement de l’API pour un compte en lecture seule n’est pas décrit dans la référence : à vérifier dans votre version, en testant les appels du script avec ce compte (une réponse
403 Forbiddenest documentée sur les GET). - Secret : pas de mot de passe en clair dans le script ni dans une tâche planifiée. Utilisez
Get-Credentialen interactif, ou le coffre de secrets de votre organisation pour une exécution planifiée. - MFA : si le compte a la MFA, le script accepte
-MfaCode; une exécution sans surveillance impose alors une décision de sécurité explicite sur ce compte. - Certificat : par défaut, l’installation génère un certificat autosigné si aucun certificat adéquat n’est trouvé. Installez un certificat de votre PKI sur Web Services. Le commutateur
-SkipCertificateCheckdu script (PowerShell 7 seulement) est réservé au test.
04 / Requêtes
Pagination, filtres et sélection
Les collections acceptent Offset, Limit, Sort, Filter et Select. Dans la référence 2.3, Limit vaut 100 et Offset 0 par défaut ; Offset s’applique avant Limit quelle que soit leur position. Chaque page renvoie items et totalCount, ce qui permet de boucler jusqu’au total.
Filter prend un objet JSON (property, operation, collation, value), combinable avec and, or, not ou exclusiveOr. Opérateurs : in, contains, subset, superset, equals, notEquals, lessThan, lessThanOrEqual, greaterThan, greaterThanOrEqual. La collation par défaut est ignorecase.
# Exemple de la documentation : tâches de collecte en échec (lecture)
$f = '{"property":"status","operation":"equals","collation":"ignorecase","value":"failed"}'
$uri = 'https://vone01.contoso.local:1239/api/v2.3/dataCollection/tasks?Filter=' + [uri]::EscapeDataString($f)
Invoke-RestMethod -Uri $uri -Headers $h05 / Endpoints
Les endpoints utilisés
| Endpoint (GET) | Contenu | Champs repris par le script |
|---|---|---|
/api/v2.3/about | Informations sur le serveur Veeam ONE et le service de reporting | machine, version |
/api/v2.3/vbr/backupServers | Serveurs VBR connectés | name, version, connectionState (Unknown, Connected, NotResponding), isConfigurationBackupEnabled, bestPracticeCheckStatus |
/api/v2.3/alarms/triggeredAlarms | Toutes les alarmes déclenchées | status (Success, Resolved, Information, Warning, Error, Acknowledged, Remediated, Unknown), name, alarmSource, triggeredTime |
/api/v2.3/protectedData/virtualMachines | Toutes les VM protégées | name, platform, jobName, lastProtectedDate (date du dernier point de restauration) |
06 / Script
Le script de relevé en lecture seule
Get-VeeamOneHealthReport.ps1 ouvre une session, lit les quatre endpoints page par page, garde par défaut les alarmes en Error et Warning, marque comme Stale les VM protégées dont le dernier point a plus de 24 heures (paramétrable), puis révoque le jeton. Il renvoie un objet PowerShell et peut écrire trois CSV.
<#
.SYNOPSIS
Read-only health report from the Veeam ONE REST API (v2.3, Veeam ONE 13.x).
.DESCRIPTION
Authenticates against the Veeam ONE REST API (OAuth 2.0 password grant on /api/token),
then reads, with GET requests only:
- /api/v2.3/about Veeam ONE server information
- /api/v2.3/vbr/backupServers connected Veeam Backup & Replication servers
- /api/v2.3/alarms/triggeredAlarms triggered alarms (Error/Warning kept by default)
- /api/v2.3/protectedData/virtualMachines protected VMs and their latest restore point
Collections are read page by page with the documented Offset and Limit query parameters.
At the end the access token is revoked (/api/revoke). Nothing is changed in Veeam ONE.
.PARAMETER Server
DNS name or IP address of the machine running Veeam ONE Web Services.
.PARAMETER Port
REST API port chosen during setup. Veeam documents 1239 as the default.
.PARAMETER Credential
Account allowed to sign in to Veeam ONE. Prefer a dedicated, least-privileged account.
.PARAMETER MfaCode
One-time code, only if multi-factor authentication is enabled for the account
(sent in the Veeam-Mfa-Code header documented for /api/token).
.PARAMETER StaleHours
A protected VM whose latest restore point is older than this is flagged as stale. Default 24.
.PARAMETER IncludeAllAlarmStates
Keep every triggered alarm (Resolved, Acknowledged, Information...). Default: Error and Warning only.
.PARAMETER PageSize
Items per request (Limit). Default 100, the documented default value.
.PARAMETER OutputFolder
Optional folder: one CSV per section is written there (semicolon separated, UTF-8).
.PARAMETER SkipCertificateCheck
PowerShell 7 only. Accepts a self-signed Veeam ONE certificate for this session.
Prefer installing a trusted certificate on Veeam ONE Web Services instead.
.EXAMPLE
$cred = Get-Credential
.\Get-VeeamOneHealthReport.ps1 -Server vone01.contoso.local -Credential $cred
.EXAMPLE
.\Get-VeeamOneHealthReport.ps1 -Server vone01.contoso.local -Credential $cred -StaleHours 36 -OutputFolder C:\Reports\VeeamONE
.NOTES
Read-only: GET requests on data endpoints; POST only on /api/token (sign-in) and /api/revoke (sign-out).
Requires Windows PowerShell 5.1 or PowerShell 7. Endpoints and fields from the Veeam ONE 13 REST API
reference (API version 2.3). Test against a non-production Veeam ONE server first.
Source: ANYSYS ICT, https://www.anysys.be/articles/
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$Server,
[ValidateRange(1, 65535)]
[int]$Port = 1239,
[Parameter(Mandatory)]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential,
[string]$MfaCode,
[ValidateRange(1, 8760)]
[int]$StaleHours = 24,
[switch]$IncludeAllAlarmStates,
[ValidateRange(1, 1000)]
[int]$PageSize = 100,
[string]$OutputFolder,
[switch]$SkipCertificateCheck
)
$ErrorActionPreference = 'Stop'
$baseUri = 'https://{0}:{1}' -f $Server, $Port
$apiRoot = "$baseUri/api/v2.3"
# Common parameters for every Invoke-RestMethod call
$irmCommon = @{}
if ($SkipCertificateCheck) {
if ($PSVersionTable.PSVersion.Major -lt 7) {
throw '-SkipCertificateCheck requires PowerShell 7. Install a trusted certificate on Veeam ONE Web Services instead.'
}
$irmCommon['SkipCertificateCheck'] = $true
}
if ($PSVersionTable.PSVersion.Major -lt 6) {
# Windows PowerShell 5.1: make sure TLS 1.2 is allowed for this session only
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
}
function Get-VoneCollection {
<# Reads every page of a collection endpoint using Offset/Limit and returns the items. #>
param(
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][hashtable]$Headers,
[Parameter(Mandatory)][int]$Limit
)
$offset = 0
$all = New-Object System.Collections.Generic.List[object]
do {
$uri = '{0}{1}?Offset={2}&Limit={3}' -f $apiRoot, $Path, $offset, $Limit
$page = Invoke-RestMethod -Method Get -Uri $uri -Headers $Headers @irmCommon
$items = @($page.items)
foreach ($i in $items) { $all.Add($i) }
$offset += $items.Count
$total = [int]$page.totalCount
} while ($items.Count -gt 0 -and $offset -lt $total)
return $all.ToArray()
}
# 1. Sign in: OAuth 2.0 password grant (documented on /api/token)
$tokenHeaders = @{}
if ($MfaCode) { $tokenHeaders['Veeam-Mfa-Code'] = $MfaCode }
$tokenBody = @{
grant_type = 'password'
username = $Credential.UserName
password = $Credential.GetNetworkCredential().Password
}
$token = Invoke-RestMethod -Method Post -Uri "$baseUri/api/token" -Headers $tokenHeaders `
-Body $tokenBody -ContentType 'application/x-www-form-urlencoded' @irmCommon
$tokenBody = $null
$headers = @{ Authorization = "Bearer $($token.access_token)" }
Write-Verbose ("Signed in as {0} (role: {1})" -f $token.user, $token.user_role)
try {
# 2. Read-only data collection
$about = Invoke-RestMethod -Method Get -Uri "$apiRoot/about" -Headers $headers @irmCommon
$servers = Get-VoneCollection -Path '/vbr/backupServers' -Headers $headers -Limit $PageSize
$alarms = Get-VoneCollection -Path '/alarms/triggeredAlarms' -Headers $headers -Limit $PageSize
$vms = Get-VoneCollection -Path '/protectedData/virtualMachines' -Headers $headers -Limit $PageSize
$backupServers = foreach ($s in $servers) {
[pscustomobject]@{
Name = $s.name
Version = $s.version
Platform = $s.platform
ConnectionState = $s.connectionState
ConnectionError = $s.connectionError
ConfigBackupEnabled = $s.isConfigurationBackupEnabled
BestPracticeStatus = $s.bestPracticeCheckStatus
LastBestPracticeCheck = $s.lastBestPracticeCheckDate
IntelligentDiagnostics = $s.intelligentDiagnosticsEnabled
}
}
$keptStates = @('Error', 'Warning')
$activeAlarms = foreach ($a in $alarms) {
if (-not $IncludeAllAlarmStates -and ($keptStates -notcontains [string]$a.status)) { continue }
[pscustomobject]@{
Status = $a.status
Name = $a.name
Object = $a.alarmSource.objectName
ObjectType = $a.alarmSource.objectType
Triggered = $a.triggeredTime
RepeatCount = $a.repeatCount
Description = $a.description
}
}
$activeAlarms = @($activeAlarms | Sort-Object Status, Triggered)
$staleLimit = (Get-Date).ToUniversalTime().AddHours(-$StaleHours)
$protectedVms = foreach ($v in $vms) {
$last = $null
if ($v.lastProtectedDate) { $last = ([datetime]$v.lastProtectedDate).ToUniversalTime() }
[pscustomobject]@{
Name = $v.name
Platform = $v.platform
Host = $v.parentHostName
BackupServer = $v.backupServerName
Job = $v.jobName
LastRestorePoint = $last
Stale = ($null -eq $last) -or ($last -lt $staleLimit)
}
}
$protectedVms = @($protectedVms)
$staleVms = @($protectedVms | Where-Object Stale)
# 3. Optional CSV export
if ($OutputFolder) {
$null = New-Item -ItemType Directory -Path $OutputFolder -Force
$csv = @{ NoTypeInformation = $true; Delimiter = ';'; Encoding = 'UTF8' }
$backupServers | Export-Csv -Path (Join-Path $OutputFolder 'vone-backup-servers.csv') @csv
$activeAlarms | Export-Csv -Path (Join-Path $OutputFolder 'vone-alarms.csv') @csv
$protectedVms | Export-Csv -Path (Join-Path $OutputFolder 'vone-protected-vms.csv') @csv
}
[pscustomobject]@{
VeeamOneServer = $about.machine
VeeamOneVersion = $about.version
CollectedAtUtc = (Get-Date).ToUniversalTime()
BackupServers = $backupServers
ServersNotOk = @($backupServers | Where-Object { $_.ConnectionState -ne 'Connected' }).Count
Alarms = $activeAlarms
AlarmErrors = @($activeAlarms | Where-Object { $_.Status -eq 'Error' }).Count
AlarmWarnings = @($activeAlarms | Where-Object { $_.Status -eq 'Warning' }).Count
ProtectedVms = $protectedVms
StaleVms = $staleVms
StaleThresholdH = $StaleHours
}
}
finally {
# 4. Sign out: revoke the access token (documented on /api/revoke)
try {
Invoke-RestMethod -Method Post -Uri "$baseUri/api/revoke" -Headers $headers `
-Body @{ token = $token.access_token } -ContentType 'application/x-www-form-urlencoded' @irmCommon | Out-Null
}
catch {
Write-Warning "Token revocation failed: $($_.Exception.Message)"
}
}$cred = Get-Credential # compte dédié, voir section 03
$r = .\Get-VeeamOneHealthReport.ps1 -Server vone01.contoso.local -Credential $cred -StaleHours 26 `
-OutputFolder 'D:\Reports\VeeamONE'
$r | Select-Object VeeamOneServer, VeeamOneVersion, ServersNotOk, AlarmErrors, AlarmWarnings, StaleThresholdH
$r.Alarms | Format-Table Status, Name, Object, Triggered
$r.StaleVms | Sort-Object LastRestorePoint | Format-Table Name, Job, LastRestorePoint07 / Exploitation
Exploiter le résultat
Exemple de sortie (illustratif), valeurs fictives :
VeeamOneServer : VONE01
VeeamOneVersion : 13.1.0.7233
ServersNotOk : 1
AlarmErrors : 1
AlarmWarnings : 3
StaleThresholdH : 26- ServersNotOk > 0 : un serveur VBR n’est pas en Connected. Tant que la collecte est coupée, les alarmes de ce serveur ne sont plus fiables : à traiter en premier.
- StaleVms : à rapprocher du rapport Protected VMs. Une VM peut apparaître une fois par job (le champ
jobNameest porté par chaque élément) : dédoublonnez avant de compter. - Alarms : la liste brute ; la priorisation et le réglage des alarmes sont traités dans alarmes et notifications.
- Pour une exécution quotidienne, planifiez le script sur une machine d’administration et envoyez les CSV vers votre outil de ticket ou de supervision. Le pack de rapports à destination de la direction est dans rapports et Business View.
08 / Pièges
Pièges et limites
- Version d’API dans l’URL : le script appelle
/api/v2.3. Après une mise à niveau, consultez le changelog de la référence REST avant de changer de version. - Durée du jeton : la réponse de
/api/tokencontientexpires_in. Le script est court et ne rafraîchit pas le jeton ; pour une extraction très longue, ajoutez le rafraîchissement documenté. - Windows PowerShell 5.1 : le script active TLS 1.2 pour la session et refuse
-SkipCertificateCheck, qui n’existe qu’en PowerShell 7. - Révocation : si le script est interrompu avant la fin, le jeton n’est pas révoqué et expire de lui-même.
- Volumes :
-PageSizerègle la taille de page ; restez raisonnable sur une instance chargée et planifiez hors des fenêtres de rapports lourds.
09 / Références
Sources
- Veeam ONE 13 REST API Reference : Overview (URL, autorisation, paramètres)
- Veeam ONE 13 REST API Reference : Authentication
- Veeam ONE 13 REST API Reference : Alarms
- Veeam ONE 13 REST API Reference : Veeam Backup & Replication Protected Data
- Veeam ONE 13 REST API Reference : Veeam Backup & Replication Infrastructure
- Veeam ONE 13 REST API Reference : About
- Veeam ONE : Security Groups
- Veeam ONE : Specify Connection Ports
- Veeam ONE 13.1 Release Notes
- Veeam KB4357 : versions et builds de Veeam ONE