My Veeam Report v1.2

VeeamReport-v1_2Find the latest version here.

My Veeam Report v1.2 has arrived! With it comes a couple of minor tweaks and the addition of successfully backed up VMs. For those backing up hundreds (or thousands) of VMs, this option can be disabled within the User Variables section. In smaller scenarios it’s nice to see at a glance which VMs got backed up last night.

This will most likely be the last update prior to Veeam rolling out v8.  We’ll have to wait and see if any changes are needed for it to continue to work properly.

Original post with screenshot and credits can be found here.

asnp "VeeamPSSnapIn" -ErrorAction SilentlyContinue
#region User-Variables
# Report Title
$rptTitle = "My Veeam Report"
# Report mode valid modes: any number of hours, Weekly or Monthly
# 24, 48, "Weekly", "Monthly"
$reportMode = 24
# File Output path and filename
# When $sendEmail is set to $false, file is created and opened in default browser
$file = "E:\MyVeeamReport.htm"
# Show VMs with no successful backups within time frame ($reportMode)
$showMissing = $true
# Show VMs with successful backups within time frame ($reportMode)
$showSuccess = $true
# vCenter server(s) As seen in VBR server
#$vcenters = "vcenter1","vcenter2"
$vcenters = "vcenter.yourdomain.local"
# To Exclude VMs from Missing and Successful Backups report add VM names to be excluded as follows
# $excludevms = @("vm1","vm2","*_replica")
$excludeVMs = @("")
# Exclude VMs from Missing and Successful Backups report in the following (vcenter) folder
$folderExclude = ""
# Show jobs w/warnings or errors
$jlines = $true
# Show running jobs
$rlines = $true
# Show running Services
$runningSvc = $true
# Location of Veeam executable (Veeam.Backup.Shell.exe)
$veeamExePath = "C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Shell.exe"
# Location of common dll Needed for repository function Get-vPCRepoInfo (Veeam.Backup.Common.dll)
$veeamDllPath = "C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Common.dll"
# Email configuration
# Send Email $true or $false if true, email is sent, if false, output is saved to $file
$sendEmail = $false
$emailHost = "smtprelay.yourdomain.local"
$emailUser = ""
$emailPass = ""
$emailFrom = "MyVeeamReport@yourdomain.local"
$emailTo = "you@yourdomain.local"
# Send report as attachment $true or $false
$emailAttach = $false
# Highlighting Thresholds
# Repository Free Space Remaining %
$repoCritical = 10
$repoWarn = 20
# Replica Target Free Space Remaining %
$replicaCritical = 10
$replicaWarn = 20
# License Days Remaining
$licenseCritical = 30
$licenseWarn = 90
#endregion
#region VersionInfo
$vPCARversion = "1.2"
#
# Version 1.2 SM
# Added option to show VMs successfully backed up
#
# Version 1.1.4 SM
# Misc tweaks/bug fixes
# Reconfigured HTML a bit to help with certain email clients
# Added cell coloring to highlight status
# Added $rptTitle variable to hold report title
# Added ability to send report via email as attachment
#
# Version 1.1.3 SM
# Added Details to Sessions with Warnings or Failures
#
# Version 1.1.2 SM
# Minor tweaks/updates
# Added Veeam version info to header
#
# Version 1.1.1 Shawn Masterson
# Based on vPowerCLI v6 Army Report (v1.1) by Thomas McConnell
# http://www.vpowercli.co.uk/2012/01/23/vpowercli-v6-army-report/
# http://pastebin.com/6p3LrWt7
#
# Tweaked HTML header (color, title)
#
# Changed report width to 1024px
#
# Moved hard-coded path to exe/dll files to user declared variables ($veeamExePath/$veeamDllPath)
#
# Adjusted sorting on all objects
#
# Modified info group/counts
# Modified Total Jobs = Job Runs
# Added Read (GB)
# Added Transferred (GB)
# Modified Warning = Warnings
# Modified Failed = Failures
# Added Failed (last session)
# Added Running (currently running sessions)
#
# Modified job lines
# Renamed Header Sessions with Warnings or Failures
# Fixed Write (GB) Broke with v7
#
# Added support license renewal
# Credit Gavin Townsend http://www.theagreeablecow.com/2012/09/sysadmin-modular-reporting-samreports.html
# Original Credit Arne Fokkema http://ict-freak.nl/2011/12/29/powershell-veeam-br-get-total-days-before-the-license-expires/
#
# Modified Proxy section
# Removed Read/Write/Util Broke in v7 Workaround unknown
#
# Modified Services section
# Added $runningSvc variable to toggle displaying services that are running
# Added Ability to hide section if no results returned (all services are running)
# Added Scans proxies and repositories as well as the VBR server for services
#
# Added VMs Not Backed Up section
# Credit Tom Sightler http://sightunseen.org/blog/?p=1
# http://www.sightunseen.org/files/vm_backup_status_dev.ps1
#
# Modified $reportMode
# Added ability to run with any number of hours (8,12,72 etc)
# Added bits to allow for zero sessions (semi-gracefully)
#
# Added Running Jobs section
# Added ability to toggle displaying running jobs
#
# Added catch to ensure running v7 or greater
#
#
# Version 1.1
# Added job lines as per a request on the website
#
# Version 1.0
# Clean up for release
#
# Version 0.9
# More cmdlet rewrite to improve perfomace, credit to @SethBartlett
# for practically writing the Get-vPCRepoInfo
#
# Version 0.8
# Added Read/Write stats for proxies at requests of @bsousapt
# Performance improvement of proxy tear down due to rewrite of cmdlet
# Replaced 2 other functions
# Added Warning counter, .00 to all storage returns and fetch credentials for
# remote WinLocal repos
#
# Version 0.7
# Added Utilisation(Get-vPCDailyProxyUsage) and Modes 24, 48, Weekly, and Monthly
# Minor performance tweaks
#endregion
#region NonUser-Variables
# Get the B&R Server
$vbrServer = Get-VBRLocalHost
# Get all the VI proxies in your army
$viProxyList = Get-VBRViProxy
# Get all the backup repositories
$repoList = Get-VBRBackupRepository
# Get unique repo servers
$uniqueRepos = @()
$repolist | %{$uniqueRepos += $($_.gethost().realname)}
$uniqueRepos = $uniqueRepos | Sort -unique
# Get all sessions to determine working jobs
$allSesh = Get-VBRBackupSession
# Get all the backup sessions for mode
if ($reportMode -eq "Monthly") {
$HourstoCheck = 720
} elseif ($reportMode -eq "Weekly") {
$HourstoCheck = 168
} else {
$HourstoCheck = $reportMode
}
$seshList = $allSesh | ?{($_.CreationTime -ge (Get-Date).AddHours(-$HourstoCheck)) -and ($_.State -ne "Working")}
if (($reportMode -ne "Weekly") -And ($reportMode -ne "Monthly")) {
$rptTitle = "$rptTitle (Last $reportMode Hrs)"
} else {
$rptTitle = "$rptTitle ($reportMode)"
}
#Get replica jobs
$repList = Get-VBRJob | ?{$_.IsReplica}
# Get the job counts
$totalxfer = $null
$totalRead = $null
$seshList | %{$totalxfer += $([Math]::Round([Decimal]$_.Progress.TransferedSize/1GB, 2))}
$seshList | %{$totalRead += $([Math]::Round([Decimal]$_.Progress.ReadSize/1GB, 2))}
$succesSessions = @($seshList | ?{$_.Result -eq "Success"})
$warningSessions = @($seshList | ?{$_.Result -eq "Warning"})
$failsSessions = @($seshList | ?{$_.Result -eq "Failed"})
$totalSessions = @($seshList | ?{$_.Result -eq "Failed" -Or $_.Result -eq "Success" -Or $_.Result -eq "Warning"})
$runningSessions = @($allSesh | ?{$_.State -eq "Working"})
$failedSessions = @($seshList | ?{($_.Result -eq "Failed") -and ($_.WillBeRetried -ne "True")})
#endregion
#region Functions
function Get-vPCProxyInfo {
[CmdletBinding()]
param (
[Parameter(Position=0)]
[String[]]$Name,
[Parameter(Mandatory=$true, Position=1)]
[PSObject[]]$Sessions
)
Begin {
$vPCObjAry = @()
[Int]$script:jobcount = 0
[Int]$totalObjInJob = 0
$cleanSessions = $Sessions | ?{($_.Result -ne "Failed") -and
($_.State -eq "Stopped") -and ($_.JobType -ne "Copy")}
$cleanSessions | %{$totalObjInJob = $totalObjInJob + $_.Progress.TotalObjects} |
Out-Null
function Build-vPCObj {param ([PsObject]$inputObj)
$ping = new-object system.net.networkinformation.ping
$pinginfo = $ping.send("$($inputObj.Host.RealName)")
if ($pinginfo.Status -eq "Success") {
$hostAlive = "Alive"
} else {
$hostAlive = "Dead"
}
$vPCFuncObject = New-Object PSObject -Property @{
ProxyName = $inputObj.Name
RealName = $inputObj.Host.RealName.ToLower()
Disabled = $inputObj.IsDisabled
Status = $hostAlive
IP = $pinginfo.Address
Responce = $pinginfo.RoundtripTime
ReadData = [Decimal]0.00
WriteData = [Decimal]0.00
UsageCount = 0
ProxiesInSessions = $($totalObjInJob*2)
}
return $vPCFuncObject
}
function Get-vPCProxyName {param ([String]$title)
$titleAry = @($title.Split())
$ai = 3
$bi = $titleAry.count 1
while ($ai -ne $bi) {
$proxyString = $proxyString + " " + $titleAry[$ai]
$ai ++
}
return $proxyString.Trim()
}
function Get-vPCProxyRole {param ([String]$title)
$titleAry = @($title.Split())
$roleString = $titleAry[1]
return $roleString
}
Get-VBRViProxy | %{$vPCObjAry = $vPCObjAry + $(Build-vPCObj $_)}
}
Process {
if ($Name -ne $null) {
$output = $vPCObjAry | ?{$Name -like $_.ProxyName}
}
else {
$output = $vPCObjAry
}
}
End {
$output
}
}
function Get-vPCRepoInfo {
[CmdletBinding()]
param (
[Parameter(Position=0, ValueFromPipeline=$true)]
[PSObject[]]$Repository
)
Begin {
$outputAry = @()
[Reflection.Assembly]::LoadFile($veeamDllPath) | Out-Null
function Build-Object {param($name, $path, $free, $total)
$repoObj = New-Object -TypeName PSObject -Property @{
Target = $name
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 Target, Storepath, StorageFree, StorageTotal, FreePercentage
}
}
Process {
foreach ($r in $Repository) {
if ($r.GetType().Name -eq [String]) {
$r = Get-VBRBackupRepository -Name $r
}
if ($r.Type -eq "WinLocal") {
$Server = $r.GetHost()
$FileCommander = [Veeam.Backup.Core.CRemoteWinFileCommander]::Create($Server.Info)
$storage = $FileCommander.GetDrives([ref]$null) | ?{$_.Name -eq $r.Path.Substring(0,3)}
$outputObj = Build-Object $r.Name $r.Path $storage.FreeSpace $storage.TotalSpace
}
elseif ($r.Type -eq "LinuxLocal") {
$Server = $r.GetHost()
$FileCommander = new-object Veeam.Backup.Core.CSshFileCommander $server.info
$storage = $FileCommander.FindDirInfo($r.Path)
$outputObj = Build-Object $r.Name $r.Path $storage.FreeSpace $storage.TotalSize
}
elseif ($r.Type -eq "CifsShare") {
$fso = New-Object -Com Scripting.FileSystemObject
$storage = $fso.GetDrive($r.Path)
$outputObj = Build-Object $r.Name $r.Path $storage.AvailableSpace $storage.TotalSize
}
$outputAry = $outputAry + $outputObj
}
}
End {
$outputAry
}
}
function Get-vPCReplicaTarget {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)]
[PSObject[]]$InputObj
)
BEGIN {
$outputAry = @()
$dsAry = @()
if (($Name -ne $null) -and ($InputObj -eq $null)) {
$InputObj = Get-VBRJob -Name $Name
}
}
PROCESS {
foreach ($obj in $InputObj) {
if (($dsAry -contains $obj.ViReplicaTargetOptions.DatastoreName) -eq $false) {
$esxi = $obj.GetTargetHost()
$dtstr = $esxi | Find-VBRViDatastore -Name $obj.ViReplicaTargetOptions.DatastoreName
$objoutput = New-Object -TypeName PSObject -Property @{
Target = $esxi.Name
Datastore = $obj.ViReplicaTargetOptions.DatastoreName
StorageFree = [Math]::Round([Decimal]$dtstr.FreeSpace/1GB,2)
StorageTotal = [Math]::Round([Decimal]$dtstr.Capacity/1GB,2)
FreePercentage = [Math]::Round(($dtstr.FreeSpace/$dtstr.Capacity)*100)
}
$dsAry = $dsAry + $obj.ViReplicaTargetOptions.DatastoreName
$outputAry = $outputAry + $objoutput
}
else {
return
}
}
}
END {
$outputAry | Select Target, Datastore, StorageFree, StorageTotal, FreePercentage
}
}
function Get-VeeamVersion {
$veeamExe = Get-Item $veeamExePath
$VeeamVersion = $veeamExe.VersionInfo.ProductVersion
Return $VeeamVersion
}
function Get-VeeamSupportDate {
#Get version and license info
$regBinary = (Get-Item 'HKLM:\SOFTWARE\Veeam\Veeam Backup and Replication\license').GetValue('Lic1')
$veeamLicInfo = [string]::Join($null, ($regBinary | % { [char][int]$_; }))
if($script:VeeamVersion -like "6*"){
$pattern = "Expiration date\=\d{1,2}\/\d{1,2}\/\d{1,4}"
}
elseif($script:VeeamVersion -like "5*"){
$pattern = "EXPIRATION DATE\=\d{1,2}\/\d{1,2}\/\d{1,4}"
}
elseif($script:VeeamVersion -like "7*"){
$pattern = "expiration date\=\d{1,2}\/\d{1,2}\/\d{1,4}"
}
# Convert Binary key
if($script:VeeamVersion -like "5*" -OR $script:VeeamVersion -like "6*" -OR $script:VeeamVersion -like "7*"){
$expirationDate = [regex]::matches($VeeamLicInfo, $pattern)[0].Value.Split("=")[1]
$datearray = $expirationDate -split '/'
$datearray = $datearray[1],$datearray[0],$datearray[2]
$expirationDate = $datearray -join '/'
$totalDaysLeft = ((Get-Date $expirationDate) – (get-date)).Totaldays.toString().split(",")[0]
$totalDaysLeft = [int]$totalDaysLeft
$objoutput = New-Object -TypeName PSObject -Property @{
ExpDate = $expirationDate
DaysRemain = $totalDaysLeft
}
$objoutput
}
else{
$objoutput = New-Object -TypeName PSObject -Property @{
ExpDate = "Failed"
DaysRemain = "Failed"
}
$objoutput
}
}
function Get-VeeamServers {
$vservers=@{}
$outputAry = @()
$vservers.add($($script:vbrserver.realname),"VBRServer")
foreach ($srv in $script:viProxyList) {
If (!$vservers.ContainsKey($srv.Host.Realname)) {
$vservers.Add($srv.Host.Realname,"ProxyServer")
}
}
foreach ($srv in $script:repoList) {
If (!$vservers.ContainsKey($srv.gethost().Realname)) {
$vservers.Add($srv.gethost().Realname,"RepoServer")
}
}
$vservers = $vservers.GetEnumerator() | Sort-Object Name
foreach ($vserver in $vservers) {
$outputAry += $vserver.Name
}
return $outputAry
}
function Get-VeeamServices {
param (
[PSObject]$inputObj)
$outputAry = @()
foreach ($obj in $InputObj) {
$output = Get-Service -computername $obj -Name "*Veeam*" -exclude "SQLAgent*" |
Select @{Name="Server Name"; Expression = {$obj}}, @{Name="Service Name"; Expression = {$_.DisplayName}}, Status
$outputAry = $outputAry + $output
}
$outputAry
}
function Get-VMsBackupStatus {
param (
[String]$vcenter)
$outputary = @()
$vcenterobj = Get-VBRServer -Name $vcenter
$vmobjs = Find-VBRObject -Server $vcenterobj | Where-Object {$_.Type -eq "VirtualMachine" -and $_.VMFolderName -notlike $script:folderExclude}
$jobobjids = [Veeam.Backup.Core.CHierarchyObj]::GetObjectsOnHost($vcenterobj.id) | Where-Object {$_.GetItem().Type -eq "Vm"}
# Convert exclusion list to simple regular expression
$excludevms_regex = (‘(?i)^(‘ + (($script:excludevms | ForEach {[regex]::escape($_)}) –join “|”) + ‘)$’) -replace "\\\*", ".*"
foreach ($vm in $vmobjs) {
$jobobjid = ($jobobjids | Where-Object {$_.ObjectId -eq $vm.Id}).Id
if (!$jobobjid) {
$jobobjid = $vm.FindParent("Datacenter").Id + "\" + $vm.Id
}
$vm | Add-Member -MemberType NoteProperty "JobObjId" -Value $jobobjid
}
# Get a list of all VMs from vCenter and add to hash table, assume Unprotected
$vms=@{}
foreach ($vm in ($vmobjs | where {$_.Name -notmatch $excludevms_regex})) {
if(!$vms.ContainsKey($vm.JobObjId)) {
$vms.Add($vm.JobObjId, @("!", [string]$vm.GetParent("Datacenter"), $vm.Name))
}
}
# Find all backup job sessions that have ended in the last x hours
$vbrjobs = Get-VBRJob | Where-Object {$_.JobType -eq "Backup"}
$vbrsessions = Get-VBRBackupSession | Where-Object {$_.JobType -eq "Backup" -and $_.EndTime -ge (Get-Date).addhours(-$script:HourstoCheck)}
# Find all successfully backed up VMs in selected sessions (i.e. VMs not ending in failure) and update status to "Protected"
if ($vbrsessions) {
foreach ($session in $vbrsessions) {
foreach ($vm in ($session.gettasksessions() | Where-Object {$_.Status -ne "Failed"} | ForEach-Object { $_ })) {
if($vms.ContainsKey($vm.Info.ObjectId)) {
$vms[$vm.Info.ObjectId][0]=$session.JobName
}
}
}
}
$vms.GetEnumerator() | Sort-Object Value
}
function Get-VMsMissingBackup {
param (
$vms)
$outputary = @()
foreach ($vm in $vms) {
if ($vm.Value[0] -eq "!") {
$objoutput = New-Object -TypeName PSObject -Property @{
Datacenter = $vm.Value[1]
Name = $vm.Value[2]
}
$outputAry += $objoutput
}
}
$outputAry | Select Datacenter, Name | Sort Name
}
function Get-VMsSuccessBackup {
param (
$vms)
$outputary = @()
foreach ($vm in $vms) {
if ($vm.Value[0] -ne "!") {
$objoutput = New-Object -TypeName PSObject -Property @{
Datacenter = $vm.Value[1]
Name = $vm.Value[2]
}
$outputAry += $objoutput
}
}
$outputAry | Select Datacenter, Name | Sort Name
}
#endregion
#region Report
# Get Veeam Version
$VeeamVersion = Get-VeeamVersion
# HTML Stuff
$headerObj = @"
<html>
<head>
<title>$rptTitle</title>
<style>
body {font-family: Tahoma; background-color:#fff;width: 1024px;}
table {font-family: Tahoma;width: 1024px;font-size: 12px;border-collapse:collapse;}
<!– table tr:nth-child(odd) td {background: #e2e2e2;} >
th {background-color: #cccc99;border: 1px solid #a7a9ac;border-bottom: none;}
td {background-color: #ffffff;border: 1px solid #a7a9ac;padding: 2px 3px 2px 3px;vertical-align: top;}
</style>
</head>
"@
$bodyTop = @"
<body>
<table cellspacing="0" cellpadding="0">
<tr>
<td style="width: 80%;height: 45px;border: none;backgroundcolor: #003366;color: White;font-size: 24px;vertical-align: bottom;padding: 0px 0px 0px 15px;">$rptTitle</td>
<td style="width: 30%;height: 45px;border: none;backgroundcolor: #003366;color: White;font-size: 12px;vertical-align:text-top;text-align:right;padding: 2px 3px 2px 3px;">v$vPCARversion<br>Veeam v$VeeamVersion</td>
</tr>
<tr>
<td style="width: 80%;height: 35px;border: none;backgroundcolor: #003366;color: White;font-size: 10px;vertical-align: bottom;padding: 0px 0px 2px 3px;">Report generated: $(Get-Date -format g)</font></td>
<td style="width: 30%;height: 35px;border: none;backgroundcolor: #003366;color: White;font-size: 10px;vertical-align:bottom;text-align:right;padding: 2px 3px 2px 3px;">Based on:<br><a href="http://www.vpowercli.co.uk/2012/01/23/vpowercli-v6army-report/" target="_blank"><font color="White">vPowerCLI v6 Army Report</font></a></td>
</tr>
</table>
"@
$subHead01 = @"
<table>
<tr>
<td style="height: 35px;backgroundcolor: #eeeeee;color: #003366;font-size: 16px;font-weight: bold;vertical-align: middle;padding: 5px 0 0 15px;border-top: none;border-bottom: none;">
"@
$subHead01err = @"
<table>
<tr>
<td style="height: 35px;backgroundcolor: #eeeeee;color: #FF0000;font-size: 16px;font-weight: bold;vertical-align: middle;padding: 5px 0 0 15px;border-top: none;border-bottom: none;">
"@
$subHead02 = @"
</td>
</tr>
</table>
"@
$footerObj = @"
</body>
</html>
"@
If ($VeeamVersion -lt 7) {
Write-Host "Script requires VBR v7 or greater"
exit
}
# Get Summary Info
$vbrMasterHash = @{"Coordinator" = "$((gc env:computername).ToLower())"; "Failed" = $failedSessions.Count; "Sessions" = $totalSessions.Count;
"Read" = $totalRead; "Transferred" = $totalXfer; "Successfull" = $succesSessions.Count; "Warning" = $warningSessions.Count;
"Fails" = $failsSessions.Count; "Running" = $runningSessions.Count;}
$vbrMasterObj = New-Object -TypeName PSObject -Property $vbrMasterHash
$bodyMasterT = $vbrMasterObj | Select Coordinator, @{Name="Job Runs"; Expression = {$_.Sessions}},
@{Name="Read (GB)"; Expression = {$_.Read}}, @{Name="Transferred (GB)"; Expression = {$_.Transferred}},
@{Name="Running"; Expression = {$_.Running}}, @{Name="Successfull"; Expression = {$_.Successfull}},
@{Name="Warnings"; Expression = {$_.Warning}}, @{Name="Failures"; Expression = {$_.Fails}},
@{Name="Failed"; Expression = {$_.Failed}} | ConvertTo-HTML -Fragment
#Get VM Backup Status
If ($showMissing -or $showSuccess) {
$vmstatus = @()
foreach ($vcenter in $vcenters) {
$status = Get-VMsBackupStatus $vcenter
$vmstatus += $status
}
}
# Get VMs Missing Backups
$bodyMissing = $null
$missingVMs = @()
If ($showMissing) {
$missingVMs = Get-VMsMissingBackup $vmstatus
If ($missingVMs -ne $null) {
$missingVMs = $missingVMs | Sort Datacenter, Name | ConvertTo-HTML -Fragment
$bodyMissing = $subHead01err + "VMs with no successful backups" + $subHead02 + $missingVMs
}
}
# Get VMs Successfully Backed Up
$bodySuccess = $null
$successVMs = @()
If ($showSuccess) {
$successVMs = Get-VMsSuccessBackup $vmstatus
If ($successVMs -ne $null) {
$successVMs = $successVMs | Sort Datacenter, Name | ConvertTo-HTML -Fragment
$bodySuccess = $subHead01 + "VMs with successful backups" + $subHead02 + $successVMs
}
}
# Get Running Jobs
$bodyrLines = $null
if ($rlines -eq $true) {
if ($runningSessions.count -gt 0) {
$bodyrLines = $runningSessions | Sort Creationtime | Select @{Name="Job Name"; Expression = {$_.Name}},
@{Name="Start Date"; Expression = {$_.Progress.StartTime.ToShortDateString()}},
@{Name="Start Time"; Expression = {$_.Progress.StartTime.ToShortTimeString()}},
@{Name="Duration"; Expression = {Get-Date "$($_.Progress.Duration)" -f HH:mm:ss}},
@{Name="Read (GB)"; Expression = {[Math]::Round([Decimal]$_.Progress.ReadSize/1GB, 2)}},
@{Name="Write (GB)"; Expression = {[Math]::Round([Decimal]$_.Progress.TransferedSize/1GB, 2)}} | ConvertTo-HTML -Fragment
$bodyrLines = $subHead01 + "Running Jobs" + $subHead02 + $bodyrLines
}
}
# Get Jobs with Failures or Warnings
$bodyjLines = $null
if ($jlines -eq $true) {
$counter = @($seshList | ?{($_.Result -eq "Warning") -or ($_.Result -eq "Failed")})
if ($counter.count -gt 0) {
$bodyjLines = $seshList | ?{($_.Result -eq "Warning") -or ($_.Result -eq "Failed")} | Sort Creationtime | Select @{Name="Job Name"; Expression = {$_.Name}},
@{Name="Start Date"; Expression = {$_.Progress.StartTime.ToShortDateString()}},
@{Name="Start Time"; Expression = {$_.Progress.StartTime.ToShortTimeString()}},
@{Name="Stop Time"; Expression = {$_.Progress.StopTime.ToShortTimeString()}},
@{Name="Details"; Expression = {($_.GetDetails()).Replace("<br />"," – ")}},Result | ConvertTo-HTML -Fragment
$bodyjLines = $subHead01 + "Sessions with Warnings or Failures" + $subHead02 + $bodyjLines
}
}
# Get Proxy Info
$bodyProxy = $null
if ($viProxyList -ne $null -And $seshList -ne $null) {
$bodyProxy = Get-vPCProxyInfo -Sessions $seshList | Select @{Name="Proxy Host"; Expression = {$_.RealName}},
Disabled, @{Name="IP Address"; Expression = {$_.IP}}, @{Name="RT (ms)"; Expression = {$_.Responce}}, Status |
Sort "Proxy Host" | ConvertTo-HTML -Fragment
$bodyProxy = $subHead01 + "Proxy Details" + $subHead02 + $bodyProxy
}
# Get Repository Info
$bodyRepo = $null
if ($repoList -ne $null) {
$bodyRepo = $repoList | Get-vPCRepoInfo | Select @{Name="Repository Name"; Expression = {$_.Target}},
@{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"} Else {"OK"}}} | `
Sort "Repository Name" | ConvertTo-HTML -Fragment
$bodyRepo = $subHead01 + "Repository Details" + $subHead02 + $bodyRepo
}
# Get Replica Target Info
$bodyReplica = $null
if ($repList -ne $null) {
$bodyReplica = $repList | Get-vPCReplicaTarget | Select @{Name="Replica Target"; Expression = {$_.Target}}, Datastore,
@{Name="Free (GB)"; Expression = {$_.StorageFree}}, @{Name="Total (GB)"; Expression = {$_.StorageTotal}},
@{Name="Free (%)"; Expression = {$_.FreePercentage}},
@{Name="Status"; Expression = {If ($_.FreePercentage -lt $replicaCritical) {"Critical"} ElseIf ($_.FreePercentage -lt $replicaWarn) {"Warning"} Else {"OK"}}} | `
Sort "Replica Target" | ConvertTo-HTML -Fragment
$bodyReplica = $subHead01 + "Replica Details" + $subHead02 + $bodyReplica
}
# Get Veeam Services Info
$bodyServices = Get-VeeamServers
$bodyServices = Get-VeeamServices $bodyServices
If ($runningSvc -ne $true) {$bodyServices = $bodyServices | ?{$_.Status -ne "Running"}}
If ($bodyServices -ne $null) {
$bodyServices = $bodyServices | Select "Server Name", "Service Name", Status | Sort "Server Name", "Service Name" | ConvertTo-HTML -Fragment
$bodyServices = $subHead01 + "Services" + $subHead02 + $bodyServices
}
# Get License Info
$bodyLicense = Get-VeeamSupportDate | Select @{Name="Expiry Date"; Expression = {$_.ExpDate}}, @{Name="Days Remaining"; Expression = {$_.DaysRemain}}, `
@{Name="Status"; Expression = {If ($_.DaysRemain -lt $licenseCritical) {"Critical"} ElseIf ($_.DaysRemain -lt $licenseWarn) {"Warning"} Else {"OK"}}} | `
ConvertTo-HTML -Fragment
$bodyLicense = $subHead01 + "License/Support Renewal Date" + $subHead02 + $bodyLicense
# Combine HTML Output
$htmlOutput = $headerObj + $bodyTop + $bodyMasterT + $bodyMissing + $bodySuccess + $bodyrLines + $bodyjLines + $bodyRepo + $bodyProxy + $bodyReplica + $bodyServices + $bodyLicense + $footerObj
# Add color to output depending on results
$htmlOutput = $htmlOutput.Replace("<td>Running<","<td style=""background-color: Green;color: White;"">Running<")
$htmlOutput = $htmlOutput.Replace("<td>OK<","<td style=""background-color: Green;color: White;"">OK<")
$htmlOutput = $htmlOutput.Replace("<td>Alive<","<td style=""background-color: Green;color: White;"">Alive<")
$htmlOutput = $htmlOutput.Replace("<td>Warning<","<td style=""background-color: Yellow;"">Warning<")
$htmlOutput = $htmlOutput.Replace("<td>Stopped<","<td style=""background-color: Red;color: White;"">Stopped<")
$htmlOutput = $htmlOutput.Replace("<td>Failed<","<td style=""background-color: Red;color: White;"">Failed<")
$htmlOutput = $htmlOutput.Replace("<td>Critical<","<td style=""background-color: Red;color: White;"">Critical<")
$htmlOutput = $htmlOutput.Replace("<td>Dead<","<td style=""background-color: Red;color: White;"">Dead<")
#endregion
#region Output
if ($sendEmail) {
$emailSubject = $rptTitle
$smtp = New-Object System.Net.Mail.SmtpClient $emailHost
$smtp.Credentials = New-Object System.Net.NetworkCredential($emailUser, $emailPass);
$msg = New-Object System.Net.Mail.MailMessage($emailFrom, $emailTo)
$msg.Subject = $emailSubject
If ($emailAttach) {
$body = "Veeam Report Attached"
$msg.Body = $body
$tempfile = "$env:TEMP\$rptTitle.htm"
$htmlOutput | Out-File $tempfile
$attachment = new-object System.Net.Mail.Attachment $tempfile
$msg.Attachments.Add($attachment)
} Else {
$body = $htmlOutput
$msg.Body = $body
$msg.isBodyhtml = $true
}
$smtp.send($msg)
If ($emailAttach) {
$attachment.dispose()
Remove-Item $tempfile
}
} else {
$htmlOutput | Out-File $file
Invoke-Expression $file
}
#endregion

6 thoughts on “My Veeam Report v1.2

  1. Pingback: My Veeam Report v1.3 with VBR v8 Support | Shawn Masterson's Blog

Leave a Reply

Your email address will not be published. Required fields are marked *