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 | |
# vCenter server(s) - As seen in VBR server | |
#$vcenters = "vcenter1","vcenter2" | |
$vcenters = "vcenter.yourdomain.local" | |
# To Exclude VMs from Missing Backups report add VM names to be excluded as follows | |
# $excludevms = @("vm1","vm2","*_replica") | |
$excludeVMs = @("") | |
# Exclude VMs from Missing 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 = $false | |
# Location of Veeam executable (Veeam.Backup.Manager.exe) | |
$veeamExePath = "C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Shell.exe" | |
# Location of common dll - Needed for repository function - Get-vPCRepoInfo | |
$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.1.4" | |
# | |
# 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-VMsMissingBackup { | |
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 = $vms.GetEnumerator() | Sort-Object Value | |
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 | |
} | |
#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;background-color: #003366;color: White;font-size: 24px;vertical-align: bottom;padding: 0px 0px 0px 15px;">$rptTitle</td> | |
<td style="width: 30%;height: 45px;border: none;background-color: #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;background-color: #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;background-color: #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-v6-army-report/" target="_blank"><font color="White">vPowerCLI v6 Army Report</font></a></td> | |
</tr> | |
</table> | |
"@ | |
$subHead01 = @" | |
<table> | |
<tr> | |
<td style="height: 35px;background-color: #eeeeee;color: #003366;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 VMs Missing Backups | |
$bodyMissing = $null | |
If ($showMissing) { | |
$missingVMs = @() | |
foreach ($vcenter in $vcenters) { | |
$missing = Get-VMsMissingBackup $vcenter | Select Datacenter, Name | |
$missingVMs += $missing | |
} | |
If ($missingVMs -ne $null) { | |
$missingVMs = $missingVMs | Sort Datacenter, Name | ConvertTo-HTML -Fragment | |
$bodyMissing = $subHead01 + "VMs with no successful backups" + $subHead02 + $missingVMs | |
} | |
} | |
# 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 + $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<") | |
$htmlOutput = $htmlOutput.Replace("<th>Datacenter</th><th>","<th style=""background-color: Red;"">Datacenter<th style=""background-color: Red;"">") | |
#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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment