Home
Microsoft
PowerShell
Veeam PRTG Sensor Reloaded
Markus Kraus 21. März 2016 PowerShell, PRTG, Veeam 311 Kommentare
Ich habe mich sehr über das breite Feedback zu meinem Artikelgefreut. Klar wurde mir dabei jedoch auch, dass der Einsatz des Veeam Enterprise Servers mit der freigeschaltetenRESTful APIgar nicht so verbreitet ist.
Daher habe ich mich an eine neue Variante des PRTG Veeam Advanced Sensor gesetzt – den Veeam PRTG Sensor Reloaded.
Veeam PRTG Sensor Reloaded – Channels
Anforderung an neuen Sensor:
- Verwendung der Veeam PowerShell SnapIn
- Ziel Server (Veeam Backup & Replication Server) als Parameter
- Repository Nutzung reporten
- Leichte Erweiterbarkeit
Sehr schnell hat sich allerdings ein grundlegendes Problem des Veeam PowerShell Plugin in Verbindung mit PRTG aufgetan:
Das Veeam PowerShell Plugin ist 64 Bitonly und PRTG führt alle Scripte auf der Probe nur in 32 Bit aus.
Nach etwas Recherche und Tests fand ich das Tool PSx64von PRTG Tools Family(@prtgtoolsfamily) als eine wirklich robuste und gute Lösung des Problems.
Note:
Paessler hat diesen Artikel mittlerweile offiziell in seine Knowledge Base aufgenommen:
Monitoring Veeam Backup & Replication Without Veeam Enterprise Manager
Veeam PRTG Sensor Reloaded – Einrichtung
Um das 64 Bit Problem zu umgehen wird die PSx64 EXE mit dem Veeam PRTG Sensor Reloaded PowerShell Script als Parameter in einem Advanced Sensor eingebunden:
Note:
Es macht in den meisten Umgebungen Sinn den Timeout des Sensors auf mindestens 120 Sekunden zu erhöhen, damit können bestimmte Fehler auch korrekt abgehandelt werden.
Der Aufruf kann auch noch PowerShell Parameter beinhalten (hier der Veeam B&R Server FQDN):
Parameter der PSx64.exe:
- -f= PowerShell Script
- -p= Parameter für das Script – z.B. „-BRHost veeam01.lan.local“
Da die PowerShell Session Credentials zum Verbindungsaufbau zum Veeam Backup & RecoveryServer verwendet werden, sollten hier passende in PRTG eingetragen werden und mit der Option „use Windows credentials of parent device“ genutzt werden.
Veeam PRTG Sensor Reloaded – Das Script
<# .SYNOPSIS PRTG Veeam Advanced Sensor .DESCRIPTION Advanced Sensor will Report Statistics about Backups during last 24 Hours and Actual Repository usage. .EXAMPLE PRTG-VeeamBRStats.ps1 -BRHost veeam01.lan.local .EXAMPLE PRTG-VeeamBRStats.ps1 -BRHost veeam01.lan.local -reportmode "Monthly" -repoCritical 80 -repoWarn 70 -Debug .EXAMPLE PRTG-VeeamBRStats.ps1 -BRHost veeam01.lan.local -reportmode "Monthly" -repoCritical 80 -repoWarn 70 -selChann "BR" .Notes NAME: PRTG-VeeamBRStats.ps1 LASTEDIT: 02/08/2018 VERSION: 1.8 KEYWORDS: Veeam, PRTG CREDITS: Thanks to Shawn, for creating an awsome Reporting Script: Veeam v9 – My Veeam Reportv9.0.1 Thanks to Bernd Leinfelder for the Scalout Repository part! https://github.com/berndleinfelder Thanks to Guy Zuercher for the Endpoint Backup part and a lot of other enhancmeents! https://github.com/gzuercher .Link http://mycloudrevolution.com/ #>#Requires -Version 3[cmdletbinding()]param( [Parameter(Position=0, Mandatory=$false)] [string] $BRHost = "localhost", [Parameter(Position=1, Mandatory=$false)] $reportMode = "24", # Weekly, Monthly as String or Hour as Integer [Parameter(Position=2, Mandatory=$false)] $repoCritical = 10, [Parameter(Position=3, Mandatory=$false)] $repoWarn = 20, [Parameter(Position=4, Mandatory=$false)] $selChann = "BCRE" # Inital channel selection)$includeBackup = $selChann.Contains("B")$includeCopy = $selChann.Contains("C")$includeRepl = $selChann.Contains("R")$includeEP = $selChann.Contains("E")#Disable output of warning to prevent Veeam PS quirks$WarningPreference = "SilentlyContinue"# Big thanks to Shawn, creating an awsome Reporting Script:# http://blog.smasterson.com/2016/02/16/veeam-v9-my-veeam-report-v9-0-1/#region: Start Load VEEAM Snapin (if not already loaded)if (!(Get-PSSnapin -Name VeeamPSSnapIn -ErrorAction SilentlyContinue)) { try { $Trash = Add-PSSnapin -PassThru VeeamPSSnapIn -ErrorAction Stop } catch { Write-Error "Failed to load VeeamPSSnapIn" Write-Output "<prtg>" Write-Output " <error>1</error>" Write-Output " <text>Failed to load VeeamPSSnapIn</text>" Write-Output "</prtg>" Exit }}#endregion#region: FunctionsFunction Get-vPCRepoInfo {[CmdletBinding()] param ( [Parameter(Position=0, ValueFromPipeline=$true)] [PSObject[]]$Repository ) Begin { $outputAry = @() Function New-RepoObject {param($name, $repohost, $path, $free, $total) $repoObj = New-Object -TypeName PSObject -Property @{ Target = $name RepoHost = $repohost Storepath = $path StorageFree = [Math]::Round([Decimal]$free/1GB,2) StorageTotal = [Math]::Round([Decimal]$total/1GB,2) FreePercentage = [Math]::Round(($free/$total)*100) } Return $repoObj | Select-Object Target, RepoHost, Storepath, StorageFree, StorageTotal, FreePercentage } } Process { Foreach ($r in $Repository) { # Refresh Repository Size Info try { [Veeam.Backup.Core.CBackupRepositoryEx]::SyncSpaceInfoToDb($r, $true) } catch { Write-Debug "SyncSpaceInfoToDb Failed" } If ($r.HostId -eq "00000000-0000-0000-0000-000000000000") { $HostName = "" } Else { $HostName = $($r.GetHost()).Name.ToLower() } $outputObj = New-RepoObject $r.Name $Hostname $r.Path $r.info.CachedFreeSpace $r.Info.CachedTotalSpace } $outputAry += $outputObj } End { $outputAry }}#endregion#region: Start BRHost ConnectionWrite-Debug "Starting to Process Connection to $BRHost ..."$OpenConnection = (Get-VBRServerSession).Serverif($OpenConnection -eq $BRHost) { Write-Debug "BRHost is Already Connected..."} elseif ($OpenConnection -eq $null ) { Write-Debug "Connecting BRHost..." try { Connect-VBRServer -Server $BRHost } catch { Write-Error "Failed to connect to Veeam BR Host" Write-Output "<prtg>" Write-Output " <error>1</error>" Write-Output " <text>Failed to connect to Veeam BR Host</text>" Write-Output "</prtg>" Exit }} else { Write-Debug "Disconnection actual BRHost..." Disconnect-VBRServer Write-Debug "Connecting new BRHost..." try { Connect-VBRServer -Server $BRHost } catch { Write-Error "Failed to connect to Veeam BR Host" Write-Output "<prtg>" Write-Output " <error>1</error>" Write-Output " <text>Failed to connect to Veeam BR Host</text>" Write-Output "</prtg>" Exit }}$NewConnection = (Get-VBRServerSession).Serverif ($NewConnection -eq $null ) { Write-Error "Failed to connect to Veeam BR Host" Write-Output "<prtg>" Write-Output " <error>1</error>" Write-Output " <text>Failed to connect to Veeam BR Host</text>" Write-Output "</prtg>" Exit}#endregion#region: Convert mode (timeframe) to hoursIf ($reportMode -eq "Monthly") { $HourstoCheck = 720} Elseif ($reportMode -eq "Weekly") { $HourstoCheck = 168} Else { $HourstoCheck = $reportMode}#endregion#region: Collect and filter Sessions[Array]$repoList = Get-VBRBackupRepository | Where-Object {$_.Type -ne "SanSnapshotOnly"} # Get all Repositories<#Thanks to Bernd Leinfelder for the Scalouts Part!https://github.com/berndleinfelder#>[Array]$scaleouts = Get-VBRBackupRepository -scaleoutif ($scaleouts) { foreach ($scaleout in $scaleouts) { $extents = Get-VBRRepositoryExtent -Repository $scaleout foreach ($ex in $extents) { $repoList = $repoList + $ex.repository } }}$allSesh = Get-VBRBackupSession # Get all Sessions (Backup/BackupCopy/Replica)$allEPSesh = Get-VBREPSession # Get all Sessions of Endpoint Backups$SessionObject = [PSCustomObject] @{ } # Filled for debug option#endregionWrite-Output "<prtg>"#region: Backup Jobsif ($includeBackup) { $seshListBk = @($allSesh | Where-Object{($_.CreationTime -ge (Get-Date).AddHours(-$HourstoCheck)) -and $_.JobType -eq "Backup"}) # Gather all Backup sessions within timeframe $TotalBackupTransfer = 0 $TotalBackupRead = 0 $seshListBk | ForEach-Object{$TotalBackupTransfer += $([Math]::Round([Decimal]$_.Progress.TransferedSize/1GB, 0))} $seshListBk | ForEach-Object{$TotalBackupRead += $([Math]::Round([Decimal]$_.Progress.ReadSize/1GB, 0))} $successSessionsBk = @($seshListBk | Where-Object{$_.Result -eq "Success"}) $warningSessionsBk = @($seshListBk | Where-Object{$_.Result -eq "Warning"}) $failsSessionsBk = @($seshListBk | Where-Object{$_.Result -eq "Failed"}) $runningSessionsBk = @($allSesh | Where-Object{$_.State -eq "Working" -and $_.JobType -eq "Backup"}) $failedSessionsBk = @($seshListBk | Where-Object{($_.Result -eq "Failed") -and ($_.WillBeRetried -ne "True")}) $Count = $successSessionsBk.Count Write-Output "<result>" " <channel>Successful-Backups</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $Count = $warningSessionsBk.Count Write-Output "<result>" " <channel>Warning-Backups</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxWarning>0</LimitMaxWarning>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failsSessionsBk.Count Write-Output "<result>" " <channel>Failes-Backups</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failedSessionsBk.Count Write-Output "<result>" " <channel>Failed-Backups</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $runningSessionsBk.Count Write-Output "<result>" " <channel>Running-Backups</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" Write-Output "<result>" " <channel>TotalBackupRead</channel>" " <value>$TotalBackupRead</value>" " <unit>Custom</unit>" " <customUnit>GB</customUnit>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" Write-Output "<result>" " <channel>TotalBackupTransfer</channel>" " <value>$TotalBackupTransfer</value>" " <unit>Custom</unit>" " <customUnit>GB</customUnit>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $SessionObject | Add-Member -MemberType NoteProperty -Name "Successful Backups" -Value $successSessionsBk.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Successful Backups" -Value $successSessionsBk.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Warning Backups" -Value $warningSessionsBk.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failes Backups" -Value $failsSessionsBk.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failed Backups" -Value $failedSessionsBk.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Running Backups" -Value $runningSessionsBk.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Total Backup Transfer" -Value $TotalBackupTransfer $SessionObject | Add-Member -MemberType NoteProperty -Name "Total Backup Read" -Value $TotalBackupRead}#endregion:#region: Copy Jobsif ($includeCopy) { $seshListBkc = @($allSesh | Where-Object{($_.CreationTime -ge (Get-Date).AddHours(-$HourstoCheck)) -and $_.JobType -eq "BackupSync"}) # Gather all BackupCopy sessions within timeframe $successSessionsBkC = @($seshListBkC | Where-Object{$_.Result -eq "Success"}) $warningSessionsBkC = @($seshListBkC | Where-Object{$_.Result -eq "Warning"}) $failsSessionsBkC = @($seshListBkC | Where-Object{$_.Result -eq "Failed"}) $runningSessionsBkC = @($allSesh | Where-Object{$_.State -eq "Working" -and $_.JobType -eq "BackupSync"}) $IdleSessionsBkC = @($allSesh | Where-Object{$_.State -eq "Idle" -and $_.JobType -eq "BackupSync"}) $failedSessionsBkC = @($seshListBkC | Where-Object{($_.Result -eq "Failed") -and ($_.WillBeRetried -ne "True")}) $Count = $successSessionsBkC.Count Write-Output "<result>" " <channel>Successful-BackupCopys</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $Count = $warningSessionsBkC.Count Write-Output "<result>" " <channel>Warning-BackupCopys</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxWarning>0</LimitMaxWarning>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failsSessionsBkC.Count Write-Output "<result>" " <channel>Failes-BackupCopys</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failedSessionsBkC.Count Write-Output "<result>" " <channel>Failed-BackupCopys</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $runningSessionsBkC.Count Write-Output "<result>" " <channel>Running-BackupCopys</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $Count = $IdleSessionsBkC.Count Write-Output "<result>" " <channel>Idle-BackupCopys</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $SessionObject | Add-Member -MemberType NoteProperty -Name "Warning BackupCopys" -Value $warningSessionsBkC.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failes BackupCopys" -Value $failsSessionsBkC.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failed BackupCopys" -Value $failedSessionsBkC.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Running BackupCopys" -Value $runningSessionsBkC.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Idle BackupCopys" -Value $IdleSessionsBkC.Count}#endregion:#region: Replication Jobsif ($includeRepl) { $seshListRepl = @($allSesh | Where-Object{($_.CreationTime -ge (Get-Date).AddHours(-$HourstoCheck)) -and $_.JobType -eq "Replica"}) # Gather all Replication sessions within timeframe $successSessionsRepl = @($seshListRepl | Where-Object{$_.Result -eq "Success"}) $warningSessionsRepl = @($seshListRepl | Where-Object{$_.Result -eq "Warning"}) $failsSessionsRepl = @($seshListRepl | Where-Object{$_.Result -eq "Failed"}) $runningSessionsRepl = @($allSesh | Where-Object{$_.State -eq "Working" -and $_.JobType -eq "Replica"}) $failedSessionsRepl = @($seshListRepl | Where-Object{($_.Result -eq "Failed") -and ($_.WillBeRetried -ne "True")}) $Count = $successSessionsRepl.Count Write-Output "<result>" " <channel>Successful-Replications</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $Count = $warningSessionsRepl.Count Write-Output "<result>" " <channel>Warning-Replications</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxWarning>0</LimitMaxWarning>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failsSessionsRepl.Count Write-Output "<result>" " <channel>Failes-Replications</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failedSessionsRepl.Count Write-Output "<result>" " <channel>Failed-Replications</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $runningSessionsRepl.Count Write-Output "<result>" " <channel>Running-Replications</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $SessionObject | Add-Member -MemberType NoteProperty -Name "Successful Replications" -Value $successSessionsRepl.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Warning Replications" -Value $warningSessionsRepl.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failes Replications" -Value $failsSessionsRepl.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failed Replications" -Value $failedSessionsRepl.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Running Replications" -Value $RunningSessionsRepl.Count}#endregion:#region: Endpoint Jobsif ($includeEP) { $seshListEP = @($allEPSesh | Where-Object{($_.CreationTime -ge (Get-Date).AddHours(-$HourstoCheck))}) # Gather all Endpoint sessions within timeframe $successSessionsEP = @($seshListEP | Where-Object{$_.Result -eq "Success"}) $warningSessionsEP = @($seshListEP | Where-Object{$_.Result -eq "Warning"}) $failsSessionsEP = @($seshListEP | Where-Object{$_.Result -eq "Failed"}) $runningSessionsEP = @($allEPSesh | Where-Object{$_.State -eq "Working"}) $Count = $successSessionsEP.Count Write-Output "<result>" " <channel>Successful-Endpoints</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $Count = $warningSessionsEP.Count Write-Output "<result>" " <channel>Warning-Endpoints</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxWarning>0</LimitMaxWarning>" " <LimitMode>1</LimitMode>" "</result>" $Count = $failsSessionsEP.Count Write-Output "<result>" " <channel>Failes-Endpoints</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMaxError>0</LimitMaxError>" " <LimitMode>1</LimitMode>" "</result>" $Count = $runningSessionsEP.Count Write-Output "<result>" " <channel>Running-Endpoints</channel>" " <value>$Count</value>" " <showChart>1</showChart>" " <showTable>1</showTable>" "</result>" $SessionObject | Add-Member -MemberType NoteProperty -Name "Seccessful Endpoints" -Value $successSessionsEP.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Warning Endpoints" -Value $warningSessionsEP.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Failes Endpoints" -Value $failsSessionsEP.Count $SessionObject | Add-Member -MemberType NoteProperty -Name "Running Endpoints" -Value $runningSessionsEP.Count}#endregion:#region: Repository$RepoReport = $repoList | Get-vPCRepoInfo | Select-Object @{Name="Repository Name"; Expression = {$_.Target}}, @{Name="Host"; Expression = {$_.RepoHost}}, @{Name="Path"; Expression = {$_.Storepath}}, @{Name="Free (GB)"; Expression = {$_.StorageFree}}, @{Name="Total (GB)"; Expression = {$_.StorageTotal}}, @{Name="Free (%)"; Expression = {$_.FreePercentage}}, @{Name="Status"; Expression = { If ($_.FreePercentage -lt $repoCritical) {"Critical"} ElseIf ($_.FreePercentage -lt $repoWarn) {"Warning"} ElseIf ($_.FreePercentage -eq "Unknown") {"Unknown"} Else {"OK"}}} | ` Sort-Object "Repository Name"foreach ($Repo in $RepoReport){$Name = "REPO - " + $Repo."Repository Name"$Free = $Repo."Free (%)"Write-Output "<result>" " <channel>$Name</channel>" " <value>$Free</value>" " <unit>Percent</unit>" " <showChart>1</showChart>" " <showTable>1</showTable>" " <LimitMinWarning>$repoWarn</LimitMinWarning>" " <LimitMinError>$repoCritical</LimitMinError>" " <LimitMode>1</LimitMode>" "</result>"}#endregionWrite-Output "</prtg>"#region: Debugif ($DebugPreference -eq "Inquire") { $RepoReport | Format-Table * -Autosize $SessionReport += $SessionObject $SessionReport}#endregion# eof
Vielen Dank auch noch einmal an dieser Stelle an Shawn Masterson (@smasterson24) für die Erstellung dieses großartigen Veeam Reports, aus dem ich mich etwas bedient habe.
Neue Versionen
DasVeeam PRTG Sensor Reloaded Skript wird dank des ständigen Inputs der Nutzer (vielen Dank dafür!) von mir immer wieder etwas aktualisiert.
Version 1.2 – 09.08.2016
- Neu: BackupCopy Sessions
- Optimierung: Ausschluss unbenutzter Daten
- Optimierung: PS Region definitions
- Optimierung: PS Required definitions
Getestet mit Veeam B&R Version 9 Update 1 und Update 2
Version 1.3 – 03.11.2016
- Neu: Debug
- Neu: zusätzliche Parameter„-reportmode -repoCritical -repoWarn“
- Optimierung: Reorganisierung der Regions
Veeam PRTG Sensor Reloaded – Debug
Version 1.6 – 06.11.2017
- Neu: Scale Out Repository Extends
- Optimierung: Cmdlet Aliase ersetzt
- Optimierung: SanSnapshotOnly Repositories ausgeschlossen
- Fix: Errorhandling bei nicht verbundenem Repository
Advanced PRTG Sensors GitHub Repository
Wegen der großen Nachfrage, habe ich nun ein GitHub Repositoy der aktuellen Skripte erstellt.
Ich freue mich über jede Teilnahme an diesem kleinen Projekt. Egal ob Pull Request, Bug Report oder Feature Request, alles ist willkommen.
<br>Verwandte Posts:
PRTG - Veeam Cloud Connect Monitoring
Wer zum Veeam Cloud Connect Monitoring keinen eigenenVeeam ONE Server im Einsatz hat, was nicht sehr ungewöhnlichist, muss sich eine eigene Lösungenschaffen. In jedem…
Veeam Backup Validator PowerShell Pester Test
Diese Woche wurde mir wieder einmal ein sehr unterschätztes Tool für Veeam Backup & Replication ins Bewusstsein gerufen, derVeeam Backup Validator. Mit diesem Kommandozeilentool…
Auch wenn Veeam Backup & Replicationv9 eine sehr umfangreiche Email ReportFunktion besitzt,mochte ich mit meinem ArtikelVeeam B&R Monitoring etwas weiter gehen: MehrereVeeam Backup &…