<# .SYNOPSIS PRTG Sensor script to monitor a Veeam Backup & Replication environment THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER. .DESCRIPTION .PARAMETER PrtgDevice Name des Servers, auf dem die NoSpamProxy Intranet Rolle installiert ist. .PARAMETER VeeamBRJobName Name des Jobs, der innerhalb von Veeam Backup & Replication abgefragt werden soll. .INPUTS None .OUTPUTS Output exit code and a description .NOTES File: paessler-prtg_monitor-veeam-backupand-replication-job.ps1 Version: 1.3 Author: Daniel Wydler Creation Date: 10.03.2019, 10:54 Uhr Purpose/Change: Date Comment ----------------------------------------------- 10.03.2019, 10:54 Uhr Initial community release 18.09.2019, 21:39 Uhr Code base revised 19.09.2019, 00:11 Uhr Added informations to the header 27.09.2019, 09:49 Uhr Fixed query of JobId 31.01.2021, 12:19 Uhr Added parameter to Set-PrtgResult 31.01.2021, 13:45 Uhr Fixed if query in Set-PrtgResult 31.01.2021, 17:23 Uhr Code base revised 27.03.2021, 19:45 Uhr Added Connection test for remote computer 27.03.2021, 20:03 Uhr Fixed error handling in Invoke-Command 27.03.2021, 20:22 Uhr Fixed query for computer backup jobs 28.03.2021, 18;44 Uhr Fixed query for computer backup jobs 28.03.2021, 18:54 Uhr Fixed evaluation of job status 06.01.2022, 16:33 Uhr Changed Veeam PsSnapIn to Import-Module .COMPONENT Veeam Backup & Replication Powershell-Module .LINK www.vmbaggum.nl/2015/03/monitor-veeam-backup-jobs-with-prtg/ github.com/dwydler/Powershell-Skripte/blob/master/Paessler/PRTG/paessler-prtg_monitor-veeam-backupand-replication-job.ps1 .EXAMPLE .\paessler-prtg_monitor-veeam-backupand-replication-job.ps1 -PrtgDevice "localhost" -VeeamBRJobName "Job1" .\paessler-prtg_monitor-veeam-backupand-replication-job.ps1 "localhost" "Job1" #> #---------------------------------------------------------[Initialisations]-------------------------------------------------------- Param ( [Parameter( ValueFromPipelineByPropertyName, Position=0, Mandatory=$true )] [ValidateNotNullOrEmpty()] [string] $PrtgDevice, [Parameter( ValueFromPipelineByPropertyName, Position=1, Mandatory=$true )] [ValidateNotNullOrEmpty()] [string] $VeeamBRJobName ) Clear-Host #----------------------------------------------------------[Declarations]---------------------------------------------------------- [string] $strXmlOutput = "" [System.Object] $objQueryResult = $null #-----------------------------------------------------------[Functions]------------------------------------------------------------ function Set-PrtgError { Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$PrtgErrorText ) $strXmlOutput = "`n" $strXmlOutput += "`t1`n" $strXmlOutput += "`t$PrtgErrorText`n" $strXmlOutput += "" # Output Xml $strXmlOutput exit } function Set-PrtgResult { Param ( [Parameter(mandatory=$True,Position=0)] [string]$Channel, [Parameter(mandatory=$True,Position=1)] [string]$Value, [Parameter(mandatory=$False,Position=2)] [string]$Unit = "Custom", [Parameter(mandatory=$False)] [string]$CustomUnit, [Parameter(mandatory=$False)] [alias('mw')] [string]$MaxWarn, [Parameter(mandatory=$False)] [alias('minw')] [string]$MinWarn, [Parameter(mandatory=$False)] [alias('me')] [string]$MaxError, [Parameter(mandatory=$False)] [alias('wm')] [string]$WarnMsg, [Parameter(mandatory=$False)] [alias('em')] [string]$ErrorMsg, [Parameter(mandatory=$False)] [alias('mo')] [string]$Mode, [Parameter(mandatory=$False)] [alias('sc')] [switch]$ShowChart, [Parameter(mandatory=$False)] [alias('ss')] [ValidateSet('One','Kilo','Mega','Giga','Tera','Byte','KiloByte','MegaByte','GigaByte','TeraByte','Bit','KiloBit','MegaBit','GigaBit','TeraBit')] [string]$SpeedSize, [Parameter(mandatory=$False)] [ValidateSet('One','Kilo','Mega','Giga','Tera','Byte','KiloByte','MegaByte','GigaByte','TeraByte','Bit','KiloBit','MegaBit','GigaBit','TeraBit')] [string]$VolumeSize, [Parameter(mandatory=$False)] [ValidateSet('Second','Minute','Hour','Day')] [string]$SpeedTime, [Parameter(mandatory=$False)] [alias('dm')] [ValidateSet('Auto','All')] [string]$DecimalMode, [Parameter(mandatory=$False)] [alias('w')] [switch]$Warning, [Parameter(mandatory=$False)] [string]$ValueLookup ) $StandardUnits = @('BytesBandwidth','BytesMemory','BytesDisk','Temperature','Percent','TimeResponse','TimeSeconds','Custom','Count','CPU','BytesFile','SpeedDisk','SpeedNet','TimeHours') $LimitMode = $false $Result = "`t`n" $Result += "`t`t$Channel`n" $Result += "`t`t$Value`n" if ($StandardUnits -contains $Unit) { $Result += "`t`t$Unit`n" } if ( ($Unit -eq "Custom") -and ($CustomUnit) ) { $Result += "`t`t$CustomUnit`n" } if (!($Value -match "^\d+$")) { $Result += "`t`t1`n" } if ($Mode) { $Result += "`t`t$Mode`n" } if ($MaxWarn) { $Result += "`t`t$MaxWarn`n"; $LimitMode = $true } if ($MinWarn) { $Result += "`t`t$MinWarn`n"; $LimitMode = $true } if ($MaxError) { $Result += "`t`t$MaxError`n"; $LimitMode = $true } if ($WarnMsg) { $Result += "`t`t$WarnMsg`n"; $LimitMode = $true } if ($ErrorMsg) { $Result += "`t`t$ErrorMsg`n"; $LimitMode = $true } if ($LimitMode) { $Result += "`t`t1`n" } if ($SpeedSize) { $Result += "`t`t$SpeedSize`n" } if ($VolumeSize) { $Result += "`t`t$VolumeSize`n" } if ($SpeedTime) { $Result += "`t`t$SpeedTime`n" } if ($DecimalMode) { $Result += "`t`t$DecimalMode`n" } if ($Warning) { $Result += "`t`t1`n" } if ($ValueLookup) { $Result += "`t`t$ValueLookup`n" } if (!($ShowChart)) { $Result += "`t`t0`n" } $Result += "`t`n" return $Result } #------------------------------------------------------------[Modules]------------------------------------------------------------- #-----------------------------------------------------------[Execution]------------------------------------------------------------ ### Check if the remote device is reachable over PowerShell Remoting If (-not (Test-NetConnection $PrtgDevice -port 5985 -InformationLevel Quiet)) { Set-PrtgError "Gerät nicht erreichbar. PowerShell Remoting ativiert?" } ### The following commands will be executed on the remote computer $objQueryResult = Invoke-command –ComputerName $PrtgDevice -Args $VeeamBRJobName -ScriptBlock { ### Declarations param( [string] $strVeeamBackupJobName ) [array] $aVBRSession=@() [string] $strErrorMessage = $null [string] $strTrace = $null ### Fuege das Veeam Powershell Module zu aktuellen Sitzung hinzu try { Import-Module Veeam.Backup.PowerShell -ErrorAction Stop } catch { $strErrorMessage = $_.Exception.Message $objReturnData = "" | Select-Object -Property strErrorMessage, strTrace $objReturnData.strErrorMessage = $strErrorMessage $objReturnData.strTrace = $strTrace return $objReturnData } ### Ueberpruefung, ob es bei dem Jobname um ein Computer Backup Objekt handelt. if (Get-VBRComputerBackupJob -Name $strVeeamBackupJobName -ErrorAction SilentlyContinue) { ### Auslesen des letzten Ausfuehrungsergebnis vom dem angegebenen Veeam Backup Job $strVeeamBackupJobId = Get-VBRComputerBackupJob -Name $strVeeamBackupJobName | Select -ExpandProperty Id $aVBRSession = Get-VBRComputerBackupJobSession $obVBRSession = $aVBRSession | Where-Object { $_.JobId -eq $strVeeamBackupJobId } | Sort -Descending -Property "CreationTime" | Select -First 1 } # Ueberpruefung, ob es bei dem Jobname um ein Backup & Replication Entpoint Objekt handelt. elseif (Get-VBREPJob -Name $strVeeamBackupJobName -ErrorAction SilentlyContinue) { $strVeeamBackupJobId = Get-VBREPJob -Name $strVeeamBackupJobName | Select -ExpandProperty Id $obVBRSession = Get-VBREPSession | Where-Object { $_.JobId -eq $strVeeamBackupJobId } | Sort -Descending -Property "CreationTime" | Select -First 1 } ### Ueberpruefung, ob es bei dem Jobname um ein Backup & Replication Objekt handelt. elseif (Get-VBRJob -Name $strVeeamBackupJobName -ErrorAction SilentlyContinue) { ### Auslesen des letzten Ausfuehrungsergebnis vom dem angegebenen Veeam Backup Job $strVeeamBackupJobId = Get-VBRJob -Name $strVeeamBackupJobName | Select -ExpandProperty Id $obVBRSession = Get-VBRBackupSession | Where-Object { $_.JobId -eq $strVeeamBackupJobId } | Sort -Descending -Property "CreationTime" | Select -First 1 } ### If no previous condition matched else { $strErrorMessage = "Keinen Veeam Job mit dem Namen `"$strVeeamBackupJobName`" gefunden!" $objReturnData = "" | Select-Object -Property strErrorMessage, strTrace $objReturnData.strErrorMessage = $strErrorMessage $objReturnData.strTrace = $strTrace return $objReturnData } ### return $obVBRSession } ### If an error occurred set prtg sensor to error state ### Else no error occurred the return values will be processed If($objQueryResult.strErrorMessage) { Set-PrtgError $objQueryResult.strErrorMessage } else { ### switch ($objQueryResult.Result) { "Success" { $intVeeamBackupJobResult = 0 } "Warning" { $intVeeamBackupJobResult = 1 } "Failed" { $intVeeamBackupJobResult = 2 } "None" { $intVeeamBackupJobResult = 0 } Default { $intVeeamBackupJobResult = 1 } } ### Metadata des Veeam Backup Jobs in eine Variable einlesen [xml] $xmlVeeamBackupJobAuxDetails = $objQueryResult.AuxData ### Generate PRTG Output $xmlOutput = "`n" $xmlOutput += "`n" $xmlOutput += Set-PrtgResult -Channel "Job Result" -Value $intVeeamBackupJobResult -Unit Count -ShowChart -WarnMsg "Job wurde mit Warnungen ausgefuehrt." -ErrorMsg "Job wurde mit Fehler ausgefuehrt." -MaxWarn 0 -MaxError 1 if ($objQueryResult.EndTime -and $objQueryResult.CreationTime) { $xmlOutput += Set-PrtgResult -Channel "LaufzeitHour" -Value $( ($objQueryResult.EndTime - $objQueryResult.CreationTime).Hours) -CustomUnit "Std." -ShowChart $xmlOutput += Set-PrtgResult -Channel "LaufzeitMinutes" -Value $( ($objQueryResult.EndTime - $objQueryResult.CreationTime).Minutes) -CustomUnit "Min." -ShowChart $xmlOutput += Set-PrtgResult -Channel "LaufzeitSeconds" -Value $( ($objQueryResult.EndTime - $objQueryResult.CreationTime).Seconds) -CustomUnit "Sek." -ShowChart } if ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.BackupSize) { $xmlOutput += Set-PrtgResult -Channel "Job BackupSize" -Value ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.BackupSize) -VolumeSize GigaByte -ShowChart } if ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.DataSize) { $xmlOutput += Set-PrtgResult -Channel "Job DataSize" -Value ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.DataSize) -VolumeSize GigaByte -ShowChart } if ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.DedupRatio) { $xmlOutput += Set-PrtgResult -Channel "Job DedupRatio" -Value ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.DedupRatio) -ShowChart } if ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.CompressRatio) { $xmlOutput += Set-PrtgResult -Channel "Job CompressRatio" -Value ($xmlVeeamBackupJobAuxDetails.AuxData.CBackupstats.CompressRatio) -ShowChart } if ($objQueryResult.CreationTime) { $xmlOutput += "`tStart: "+ $(get-date $objQueryResult.CreationTime -Format "dd.MM.yyyy HH:mm:ss") +", Ende: "+ $(get-date $objQueryResult.EndTime -Format "dd.MM.yyyy HH:mm:ss") +"`n" } else { $xmlOutput += "`tJob ist bisher nicht gelaufen.`n" } $xmlOutput += "" ### Return Xml $xmlOutput }