Create zabbix_vbr_job.ps1
This commit is contained in:
255
zabbix_vbr_job.ps1
Normal file
255
zabbix_vbr_job.ps1
Normal file
@@ -0,0 +1,255 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Position = 0, Mandatory = $false)]
|
||||
[ValidateSet("RepoInfo", "JobsInfo", "TotalJob")]
|
||||
[System.String]$Operation
|
||||
)
|
||||
|
||||
# Загрузка библиотеки Npgsql
|
||||
Add-Type -Path "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Npgsql\v4.0_4.0.12.0__5d8b90d52f46fda7\Npgsql.dll"
|
||||
|
||||
########### Adjust the following variables to match your configuration ###########
|
||||
$veeamserver = 'localhost' # Machine name where Veeam is installed
|
||||
$SQLServer = 'localhost' # Database server where Veeam database is located
|
||||
$SQLIntegratedSecurity = $false # Use Windows integrated security?
|
||||
$SQLuid = 'zabbixveeam' # SQL Username when using SQL Authentication - ignored if using Integrated security
|
||||
$SQLpwd = 'CHANGEME' # SQL user password
|
||||
$SQLveeamdb = 'VeeamBackup' # Name of Veeam database. VeeamBackup is the default
|
||||
|
||||
$typeNames = @{
|
||||
0 = "Job";
|
||||
1 = "Replication";
|
||||
2 = "File";
|
||||
28 = "Tape";
|
||||
51 = "Sync";
|
||||
63 = "Copy";
|
||||
4030 = "RMAN";
|
||||
12002 = "Agent backup policy";
|
||||
12003 = "Agent backup job";
|
||||
13000 = "NAS";
|
||||
14000 = "Proxmox";
|
||||
}
|
||||
|
||||
# $jobtypes is used in SQL queries. Built automatically from the enumeration above.
|
||||
$jobTypes = "($(($typeNames.Keys | Sort-Object) -join ", "))"
|
||||
|
||||
########### DO NOT MODIFY BELOW ###########
|
||||
function Get-ConnectionString() {
|
||||
$builder = New-Object Npgsql.NpgsqlConnectionStringBuilder
|
||||
$builder.Host = $SQLServer
|
||||
$builder.IntegratedSecurity = $SQLIntegratedSecurity
|
||||
$builder.Database = $SQLveeamdb
|
||||
$builder.Username = $SQLuid
|
||||
$builder.Password = $SQLpwd
|
||||
Write-Debug "Connection String: $($builder.ConnectionString)"
|
||||
return $builder.ConnectionString
|
||||
}
|
||||
|
||||
function Start-Connection() {
|
||||
$connectionString = Get-ConnectionString
|
||||
|
||||
# Create a connection to PostgreSQL
|
||||
Write-Debug "Opening SQL connection"
|
||||
$connection = New-Object Npgsql.NpgsqlConnection
|
||||
$connection.ConnectionString = $connectionString
|
||||
$connection.Open()
|
||||
if ($connection.State -notmatch "Open") {
|
||||
# Connection open failed. Wait and retry connection
|
||||
Start-Sleep -Seconds 5
|
||||
$connection = New-Object Npgsql.NpgsqlConnection
|
||||
$connection.ConnectionString = $connectionString
|
||||
$connection.Open()
|
||||
}
|
||||
Write-Debug "SQL connection state: $($connection.State)"
|
||||
return $connection
|
||||
}
|
||||
|
||||
function Get-SqlCommand {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Position = 0, Mandatory = $true)]
|
||||
[System.String]$Command
|
||||
)
|
||||
|
||||
$Connection = $null
|
||||
# Use try-catch to avoid exceptions if connection to SQL cannot be opened or data cannot be read
|
||||
# It either returns the data read or $null on failure
|
||||
try {
|
||||
$Connection = Start-Connection
|
||||
$SqlCmd = New-Object Npgsql.NpgsqlCommand
|
||||
$SqlCmd.CommandText = $Command
|
||||
$SqlCmd.Connection = $Connection
|
||||
$SqlCmd.CommandTimeout = 0
|
||||
$SqlAdapter = New-Object Npgsql.NpgsqlDataAdapter
|
||||
Write-Debug "Executing SQL query: ##$Command##"
|
||||
$SqlAdapter.SelectCommand = $SqlCmd
|
||||
$DataSet = New-Object System.Data.DataSet
|
||||
$SqlAdapter.Fill($DataSet)
|
||||
$retval = $DataSet.Tables[0]
|
||||
}
|
||||
catch {
|
||||
$retval = $null
|
||||
# We output the error message. This gets sent to Zabbix.
|
||||
Write-Output $_.Exception.Message
|
||||
}
|
||||
finally {
|
||||
# Make sure the connection is closed
|
||||
if ($null -ne $Connection) {
|
||||
$Connection.Close()
|
||||
}
|
||||
}
|
||||
return $retval
|
||||
}
|
||||
|
||||
function ConvertTo-Unixtimestamp {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.DateTime]$date
|
||||
)
|
||||
# Unix epoch
|
||||
[System.DateTime]$unixepoch = (get-date -date "01/01/1970 00:00:00Z")
|
||||
|
||||
# Handle empty dates
|
||||
# We make this one second less than $unixepoch.
|
||||
# This makes the time calculation below return -1 to Zabbix, making the item "unsupported" while the job is running (or before it ran for the first time)
|
||||
if ($null -eq $date -or $date -lt $unixepoch) {
|
||||
$date = $unixepoch.AddSeconds(-1);
|
||||
}
|
||||
|
||||
# Return the seconds elapsed between the reference date and the epoch
|
||||
return [int]((New-TimeSpan -Start $unixepoch -end $date).TotalSeconds)
|
||||
}
|
||||
|
||||
function Get-SessionInfo {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Object]$BackupSession
|
||||
)
|
||||
|
||||
# Return $null if there is no session data
|
||||
if (!$BackupSession) {
|
||||
return $null
|
||||
}
|
||||
|
||||
# Get reason for the job failure/warning
|
||||
# We get all jobs reasons from both table column and log_xml
|
||||
$Log = (([Xml]$BackupSession.log_xml).Root.Log | Where-Object { $_.Status -eq 'EFailed' }).Title
|
||||
$reason = $BackupSession.reason
|
||||
foreach ($logreason in $Log) {
|
||||
$reason += "`r`n$logreason"
|
||||
}
|
||||
|
||||
# Build the output object
|
||||
Write-Debug "Building object for job: $($BackupSession.job_name)"
|
||||
$Object = [PSCustomObject]@{
|
||||
JOBID = $BackupSession.job_id
|
||||
JOBTYPEID = $BackupSession.job_type
|
||||
JOBTYPENAME = $typeNames[$BackupSession.job_type]
|
||||
JOBNAME = ([System.Net.WebUtility]::HtmlEncode($BackupSession.job_name))
|
||||
JOBRESULT = $BackupSession.result
|
||||
JOBRETRY = $BackupSession.is_retry
|
||||
JOBREASON = ([System.Net.WebUtility]::HtmlEncode($reason))
|
||||
JOBPROGRESS = $BackupSession.progress
|
||||
JOBSTART = (ConvertTo-Unixtimestamp $BackupSession.creation_time.ToUniversalTime())
|
||||
JOBEND = (ConvertTo-Unixtimestamp $BackupSession.end_time.ToUniversalTime())
|
||||
}
|
||||
return $Object
|
||||
}
|
||||
|
||||
function Get-JobInfo() {
|
||||
Write-Debug "Entering Get-JobInfo()"
|
||||
|
||||
# Get all active jobs
|
||||
$BackupJobs = Get-SqlCommand "SELECT id, name, options FROM ""bjobs"" WHERE schedule_enabled = 'true' AND type IN $jobTypes ORDER BY type, name"
|
||||
Write-Debug "Job count: $($BackupJobs.Count)"
|
||||
$return = @()
|
||||
# Get information for each active job
|
||||
foreach ($job in $BackupJobs) {
|
||||
if (([Xml]$job.options).JobOptionsRoot.RunManually -eq "False") {
|
||||
Write-Debug "Getting data for job: $($job.name)"
|
||||
# Get backup jobs session information
|
||||
$LastJobSessions = Get-SqlCommand "SELECT job_id, job_type, job_name, result, is_retry, progress, creation_time, end_time, log_xml, reason
|
||||
FROM ""backup.model.jobsessions""
|
||||
INNER JOIN ""backup.model.backupjobsessions""
|
||||
ON ""backup.model.jobsessions"".id = ""backup.model.backupjobsessions"".id
|
||||
WHERE job_id='$($job.id)'
|
||||
ORDER BY creation_time DESC
|
||||
LIMIT 2"
|
||||
$LastJobSession = $LastJobSessions | Sort-Object end_time -Descending | Select-Object -First 1
|
||||
# Exception BackupSync continuous state
|
||||
if ($LastJobSession.job_type -like '51' -and $LastJobSession.state -like '9') {
|
||||
$LastJobSession = $LastJobSessions | Sort-Object end_time -Descending | Select-Object -Last 1
|
||||
}
|
||||
$sessionInfo = Get-SessionInfo $LastJobSession
|
||||
$return += $sessionInfo
|
||||
}
|
||||
}
|
||||
Write-Verbose "Got job information. Number of jobs: $($return.Count)"
|
||||
# Convert data to JSON
|
||||
$return = ConvertTo-Json -Compress -InputObject @($return)
|
||||
Write-Output $return
|
||||
}
|
||||
|
||||
function Get-RepoInfo() {
|
||||
Write-Debug "Entering Get-RepoInfo()"
|
||||
Write-Debug "Veeam server: $veeamserver"
|
||||
# Get data from WIM class
|
||||
$repoinfo = Get-CimInstance -Class Repository -ComputerName $veeamserver -Namespace ROOT\VeeamBS
|
||||
|
||||
$return = @()
|
||||
# Build the output object
|
||||
foreach ($item in $repoinfo) {
|
||||
Write-Debug "Repository $($item.NAME)"
|
||||
$Object = [PSCustomObject]@{
|
||||
REPONAME = ([System.Net.WebUtility]::HtmlEncode($item.NAME))
|
||||
REPOCAPACITY = $item.Capacity
|
||||
REPOFREE = $item.FreeSpace
|
||||
REPOOUTOFDATE = $item.OutOfDate
|
||||
}
|
||||
$return += $Object
|
||||
}
|
||||
Write-Debug "Repository count: $($return.Count)"
|
||||
|
||||
# Convert data to JSON
|
||||
$return = ConvertTo-Json -Compress -InputObject @($return)
|
||||
Write-Output $return
|
||||
}
|
||||
|
||||
function Get-Totaljob() {
|
||||
$BackupJobs = Get-SqlCommand "SELECT COUNT(jobs.name) as JobCount
|
||||
FROM JobsView jobs
|
||||
WHERE Schedule_Enabled = 'true' AND type IN $jobTypes"
|
||||
Write-Debug $BackupJobs.ToString()
|
||||
if ($null -ne $BackupJobs) {
|
||||
Write-Output $BackupJobs.JobCount
|
||||
}
|
||||
else {
|
||||
Write-Output "-- ERROR -- : No data available. Check configuration"
|
||||
}
|
||||
}
|
||||
|
||||
If ($PSBoundParameters['Debug']) {
|
||||
$DebugPreference = 'Continue'
|
||||
}
|
||||
|
||||
Write-Debug "Job types: $jobTypes"
|
||||
Write-Debug "Veeam server: $veeamserver"
|
||||
Write-Debug "SQL server: $SQLServer"
|
||||
switch ($Operation) {
|
||||
"RepoInfo" {
|
||||
Get-RepoInfo
|
||||
}
|
||||
"JobsInfo" {
|
||||
Get-JobInfo
|
||||
}
|
||||
"TotalJob" {
|
||||
Get-Totaljob
|
||||
}
|
||||
default {
|
||||
Write-Output "-- ERROR -- : Need an option !"
|
||||
Write-Output "Valid options are: RepoInfo, JobsInfo or TotalJob"
|
||||
Write-Output "This script is not intended to be run directly but called by Zabbix."
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user