Veeam v13: Monitoring Integration with External Tools
Veeam v13 Series | Component: VBR v13, Veeam ONE v13 | Audience: Enterprise Architects, MSP Engineers, Security and Compliance Teams
Veeam ONE is a solid monitoring layer for people who live in the Veeam console. But most operations teams do not. NOC engineers work in Grafana dashboards. Security teams work in Splunk. Infrastructure teams have Zabbix or a similar platform watching everything. And when a backup job fails at 3am, the fastest path to an engineer is usually a Teams or Slack message, not a Veeam ONE email that sits unread until morning.
This article covers how to push Veeam data outward into the tools your team already uses. Grafana dashboards via Prometheus, Splunk ingestion via HTTP Event Collector, Zabbix external check integration, and Teams/Slack webhook alerts from Veeam ONE alarm actions.
1. Integration Architecture Overview
There are three ways to get data out of Veeam and into external tools. The right choice depends on what you need and what your external tool supports.
| Method | Best For | Data Type | Latency |
|---|---|---|---|
| Veeam ONE alarm script action | Real time alert delivery to chat tools, ticketing systems | Alarm events only | Near real time (seconds after alarm fires) |
| SNMP traps from Veeam ONE | Network management platforms (Zabbix, PRTG, SolarWinds) | Alarm events only | Near real time |
| PowerShell polling via VBR API | Grafana, Splunk, custom dashboards needing metrics | Job status, repository capacity, session data, any VBR metric | Polling interval (typically 1 to 5 minutes) |
For real time alerting, use the alarm script action or SNMP. For metrics and dashboards, use PowerShell polling. For security event ingestion, use PowerShell polling into Splunk or a syslog forwarder. Most mature environments use all three.
2. Teams and Slack Webhook Integration
This is the fastest win and the one most teams implement first. Veeam ONE fires an alarm, a PowerShell script runs, and a formatted message lands in your Teams or Slack channel within seconds.
Setup: Create an Incoming Webhook
In Teams: go to the channel you want alerts delivered to, click the three dot menu, select Connectors, search for Incoming Webhook, configure it, and copy the webhook URL.
In Slack: go to api.slack.com/apps, create a new app, enable Incoming Webhooks, add a webhook to your workspace, select the target channel, and copy the webhook URL.
Veeam ONE Alarm Script: Teams
# Parameters passed by Veeam ONE:
# %1 = Alarm name
# %2 = Affected object (node) name
# %3 = Alarm summary
# %4 = Date/time triggered
# %5 = Current status
# %6 = Previous status
param(
[string]$AlarmName,
[string]$NodeName,
[string]$Summary,
[string]$TriggeredAt,
[string]$Status,
[string]$PrevStatus
)
$webhookUrl = "https://your-org.webhook.office.com/webhookb2/YOUR-WEBHOOK-URL"
$color = switch ($Status) {
"Error" { "FF0000" }
"Warning" { "FFA500" }
"Resolved"{ "00AA00" }
default { "808080" }
}
$body = @{
"@type" = "MessageCard"
"@context" = "https://schema.org/extensions"
"themeColor" = $color
"summary" = "Veeam Alert: $AlarmName"
"sections" = @(
@{
"activityTitle" = "Veeam ONE Alert: $Status"
"activitySubtitle" = $AlarmName
"facts" = @(
@{ "name" = "Object"; "value" = $NodeName }
@{ "name" = "Summary"; "value" = $Summary }
@{ "name" = "Status"; "value" = "$PrevStatus to $Status" }
@{ "name" = "Triggered"; "value" = $TriggeredAt }
)
}
)
} | ConvertTo-Json -Depth 10
Invoke-RestMethod -Uri $webhookUrl -Method Post -Body $body -ContentType "application/json"
The MessageCard format used above is the legacy Teams connector format. It works across all current Microsoft 365 tenants and does not require an app registration. Microsoft has announced future deprecation of the Incoming Webhook connector in Teams in favor of the Power Automate based workflow connector, but as of early 2026 MessageCard webhooks remain functional. If your tenant has already disabled legacy connectors, use a Power Automate flow with an HTTP trigger as the webhook endpoint instead.
Veeam ONE Alarm Script: Slack
param(
[string]$AlarmName,
[string]$NodeName,
[string]$Summary,
[string]$TriggeredAt,
[string]$Status,
[string]$PrevStatus
)
$webhookUrl = "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
$emoji = switch ($Status) {
"Error" { ":red_circle:" }
"Warning" { ":warning:" }
"Resolved" { ":white_check_mark:" }
default { ":grey_question:" }
}
$body = @{
text = "$emoji *Veeam ONE Alert: $Status*"
blocks = @(
@{
type = "section"
text = @{
type = "mrkdwn"
text = "$emoji *$AlarmName*`n*Object:* $NodeName`n*Status:* $PrevStatus to $Status`n*Summary:* $Summary`n*Triggered:* $TriggeredAt"
}
}
)
} | ConvertTo-Json -Depth 10
Invoke-RestMethod -Uri $webhookUrl -Method Post -Body $body -ContentType "application/json"
Registering the Script in Veeam ONE
Scripts must be wrapped in a .cmd launcher because Veeam ONE requires a direct executable path. Create a wrapper:
@echo off pwsh.exe -NonInteractive -ExecutionPolicy Bypass ^ -File "C:\VeeamONE\Scripts\Send-TeamsAlert.ps1" ^ -AlarmName "%1" ^ -NodeName "%2" ^ -Summary "%3" ^ -TriggeredAt "%4" ^ -Status "%5" ^ -PrevStatus "%6"
In Veeam ONE, edit the target alarm, go to the Notifications tab, add a Run Script action, and set the executable path to the .cmd file. Set the condition to Errors and Warnings or Errors Only depending on your noise tolerance.
3. Grafana Integration via Prometheus
Grafana does not have a native Veeam data source. The integration path is: PowerShell exporter script collects VBR metrics and exposes them as a Prometheus endpoint, Prometheus scrapes the endpoint, Grafana queries Prometheus. This gives you full time series dashboards for backup job success rates, repository capacity trends, proxy throughput, and more.
Setting Up the Veeam Prometheus Exporter
The community maintained veeam-exporter project (available on GitHub) is the most widely used approach. It connects to the VBR REST API (port 9419 by default in v12 and v13), collects job, session, and repository metrics, and exposes them as a Prometheus metrics endpoint on a configurable local port. Run it on the VBR server itself or on any host with network access to the VBR REST API.
# Install the Veeam PowerShell snap-in if not already present # (included with VBR console installation) # Download and extract veeam-exporter # https://github.com/veeamhub/veeam-exporter # Configure veeam-exporter.yaml veeamserver: localhost veeamport: 9419 veeamuser: svc-veeam-exporter veeampassword: "your-service-account-password" port: 9100 # veeamport 9419 is the VBR REST API default port in v12 and v13 # port 9100 is the metrics endpoint veeam-exporter exposes for Prometheus to scrape
Key Metrics Exposed
| Metric | Description | Dashboard Use |
|---|---|---|
| veeam_jobs_status | Last job run result per job (0=success, 1=warning, 2=error) | Job health overview panel |
| veeam_repositories_capacity_gb | Total capacity per repository in GB | Repository capacity gauge |
| veeam_repositories_free_gb | Free space per repository in GB | Repository free space trend |
| veeam_jobs_duration_seconds | Last job duration in seconds | Backup window compliance chart |
| veeam_protected_vms | Count of protected VMs | Coverage summary panel |
| veeam_failed_jobs_last24h | Count of failed jobs in the last 24 hours | Daily failure count alert panel |
Prometheus Scrape Configuration
scrape_configs:
- job_name: 'veeam'
scrape_interval: 60s
scrape_timeout: 30s
static_configs:
- targets:
- 'vbr-server.domain.local:9100'
relabel_configs:
- source_labels: [__address__]
target_label: instance
regex: '([^:]+).*'
replacement: '${1}'
Recommended Grafana Dashboard Panels
- Job Success Rate (24h). Stat panel showing percentage of jobs that completed successfully in the last 24 hours. Alert threshold at 95%.
- Repository Capacity by Repo. Bar gauge showing used vs free per repository. Alert at 80% used.
- Failed Jobs (7 days). Time series showing daily failure count. Spike detection for ransomware correlation.
- Backup Window Compliance. Table showing job duration vs expected window per job. Highlights overrunning jobs.
- Protected VM Count Trend. Time series showing total protected VM count over time. Drops indicate coverage loss.
4. Splunk Integration
Splunk ingestion gives your security team visibility into Veeam events alongside the rest of your infrastructure. Backup job failures, repository access, configuration changes, and Veeam ONE alarms all become searchable events in Splunk. For SOC teams, unusual backup patterns (jobs suddenly failing after running cleanly for months, large unexpected data changes) are early ransomware indicators.
HTTP Event Collector Setup
In Splunk: Settings, Data Inputs, HTTP Event Collector, New Token. Set a source type of json and note the token. The HEC endpoint is https://splunk-server:8088/services/collector/event.
PowerShell: Push Veeam Job Sessions to Splunk HEC
Connect-VBRServer -Server "vbr-server.domain.local"
$splunkHEC = "https://splunk-server.domain.local:8088/services/collector/event"
$splunkToken = "YOUR-HEC-TOKEN"
$cutoff = (Get-Date).AddMinutes(-20)
# Get recent job sessions
$sessions = Get-VBRBackupSession | Where-Object { $_.EndTime -gt $cutoff -or $_.State -eq "Working" }
foreach ($session in $sessions) {
$event = @{
time = [DateTimeOffset]::new($session.EndTime).ToUnixTimeSeconds()
sourcetype = "veeam:backup:session"
source = "vbr-powershell"
host = $env:COMPUTERNAME
event = @{
job_name = $session.JobName
job_type = $session.JobType.ToString()
state = $session.State.ToString()
result = $session.Result.ToString()
start_time = $session.CreationTime.ToString("o")
end_time = $session.EndTime.ToString("o")
duration_s = [int]($session.EndTime - $session.CreationTime).TotalSeconds
total_size_gb = [math]::Round($session.BackupStats.TotalSize / 1GB, 2)
transferred_gb = [math]::Round($session.BackupStats.BackupSize / 1GB, 2)
}
} | ConvertTo-Json -Depth 5
$headers = @{ Authorization = "Splunk $splunkToken" }
Invoke-RestMethod -Uri $splunkHEC -Method Post -Body $event `
-Headers $headers -ContentType "application/json" `
-SkipCertificateCheck
}
Disconnect-VBRServer
Two notes on the script above: the -SkipCertificateCheck parameter on Invoke-RestMethod requires PowerShell 6 or later (pwsh.exe). If you are running Windows PowerShell 5.1, remove that parameter and configure certificate trust through your certificate store instead. The Unix timestamp conversion uses [DateTimeOffset]::new() which works reliably on all PowerShell versions on Windows, avoiding the -UFormat %s pattern which is inconsistently supported outside Linux environments.
Useful Splunk Searches for Veeam Data
sourcetype="veeam:backup:session" result="Failed" earliest=-24h | table job_name, start_time, end_time, duration_s, result | sort start_time desc
sourcetype="veeam:backup:session" earliest=-7d | eval change_ratio = transferred_gb / total_size_gb | where change_ratio > 0.5 | table job_name, start_time, total_size_gb, transferred_gb, change_ratio | sort change_ratio desc
5. Zabbix Integration
Zabbix integration works via two approaches: SNMP traps from Veeam ONE for real time alarm events, and external check scripts that Zabbix runs periodically to collect VBR metrics.
SNMP Trap Integration
Configure Veeam ONE to send SNMP traps to your Zabbix server (Settings, Server Settings, SNMP Settings, enter Zabbix server IP on port 162). In Zabbix, configure an SNMP trap receiver item on the host representing your Veeam ONE server. Import the Veeam ONE MIB file to decode trap content into readable alarm data.
External Check Script for Zabbix
Zabbix external checks run a script on the Zabbix server and return a value. Create a PowerShell script that connects to VBR and returns the metric Zabbix is polling for.
# Called by Zabbix as: veeam-check.ps1 [metric_name]
# Returns a single value that Zabbix stores as an item
param([string]$Metric)
Connect-VBRServer -Server "vbr-server.domain.local" -Credential (
New-Object PSCredential("svc-zabbix", (ConvertTo-SecureString "password" -AsPlainText -Force))
)
$result = switch ($Metric) {
"failed_jobs_24h" {
$cutoff = (Get-Date).AddHours(-24)
(Get-VBRBackupSession | Where-Object {
$_.EndTime -gt $cutoff -and $_.Result -eq "Failed"
}).Count
}
"repo_free_pct" {
$repos = Get-VBRBackupRepository
$totalFree = ($repos | Measure-Object -Property FreeSpace -Sum).Sum
$totalCap = ($repos | Measure-Object -Property Capacity -Sum).Sum
[math]::Round(($totalFree / $totalCap) * 100, 1)
}
"protected_vm_count" {
(Get-VBRProtectedVM).Count
}
"last_job_result" {
$lastSession = Get-VBRBackupSession | Sort-Object EndTime -Descending | Select-Object -First 1
switch ($lastSession.Result) {
"Success" { 0 }
"Warning" { 1 }
"Failed" { 2 }
default { 3 }
}
}
}
Disconnect-VBRServer
Write-Output $result
Zabbix Item Configuration
| Item Key | Script Call | Value Type | Trigger Threshold |
|---|---|---|---|
| veeam.failed.jobs | veeam-check.ps1[failed_jobs_24h] | Numeric unsigned | Warning at 1, High at 3 |
| veeam.repo.free.pct | veeam-check.ps1[repo_free_pct] | Numeric float | Warning at 20%, High at 10% |
| veeam.protected.vms | veeam-check.ps1[protected_vm_count] | Numeric unsigned | Change detection trigger |
| veeam.last.job.result | veeam-check.ps1[last_job_result] | Numeric unsigned | High at 2 (Failed) |
6. Service Account Best Practices
All of these integrations require a service account with access to VBR. Do not use a full administrator account for monitoring integrations. Create a dedicated read only account.
- Create a dedicated service account: svc-veeam-monitoring or similar
- Assign the Veeam Backup Viewer role in VBR. This grants read only access to job status, sessions, repository data, and infrastructure inventory without the ability to modify anything.
- Store credentials in your secrets manager, not in plain text in scripts. Use Windows Credential Manager, HashiCorp Vault, or similar.
- Restrict the account to log on only from the monitoring host. Group Policy or local policy can enforce this.
- Rotate the password on your standard service account rotation schedule and update all integration scripts at the same time.
Key Takeaways
- Use Veeam ONE alarm script actions for real time alert delivery to Teams and Slack. Scripts run under the Veeam ONE service account and receive 8 parameters including alarm name, object, status, and timestamp.
- Teams and Slack webhooks accept JSON payloads. The MessageCard format works for Teams. Blocks format works for Slack. Color code by severity so engineers can triage at a glance.
- Grafana integration requires a Prometheus exporter. The community veeam-exporter connects to the VBR REST API and exposes job status, repository capacity, and session metrics as Prometheus metrics. Prometheus scrapes the exporter endpoint; Grafana queries Prometheus.
- Splunk HEC ingestion via PowerShell polling gives your security team Veeam job session data as searchable events. Unusual change ratios (transferred GB vs total size) are an early ransomware indicator worth alerting on.
- Zabbix integration works via SNMP traps from Veeam ONE for events and external check scripts for metric polling. Both approaches are supported natively without additional plugins.
- All monitoring integrations should use a dedicated service account with the Veeam Backup Viewer role, not an administrator account. Credentials should be stored in a secrets manager, not in plain text.