Background
Jocha work with a lot of startup companies and small-business owners, which is great in so many ways. While it gives us the possibility to design and set everything up from scratch, with all the best practices, it usually means working with a smaller budget compared to the larger corporations.
Windows Backup is a great built-in feature in Windows Server, however it lacks a useful reporting feature. We’ve built a PowerShell-script that will give you a nice report summary of the last backup job. As always we recommend using the last version of Windows Management Framework for this script.
Requirements
– Elevated PowerShell-session.
– Windows Server Backup feature installed.
– At least Windows Management Framework 3.0
Solution
By using built-in functions and leveraging scripts and third-party products you can save a lot of money.
This PowerShell-script will retrieve the last backup job send an email with a report of the results.
<#
.SYNOPSIS
Windows Backup Mail Report
Written by Joakim, http://jocha.se
.DESCRIPTION
Version 4.1 - Updated 2016-05-31
This script will mail a report from the latest Windows Backup job, can also fetch and generate reports from remote servers. The script requires at least PowerShell v3.
.EXAMPLE
To automate this script, setup a scheduled task.
Name: Backup Email Task
Description: Notifies backup admin of scheduled backup status
Run whether user is logged on or not
Trigger > On event > Log=Microsoft-Windows-Backup/Operational > Source=Backup > Event ID(s)= 4,5,8,9,17,22,49,50,52,100,517,518,521,527,528,544,545,546,561,564,612
Action: Start a Program
Program: Powershell
Arguments: -Command "C:\Scripts\WBJobReport.ps1" -ExecutionPolicy Bypass
#>
Add-PSSnapin Windows.ServerBackup -ErrorAction SilentlyContinue
#######################################
#-------- Variables to change --------#
# Uncomment the two rows below and row 207 to enable "Remote Report" generation.
#$Servers = New-PSSession -Computername Server01, Server02, Server03
#Invoke-Command -Session $Servers {
# Set your Company name
$Company = "MyCompany"
# Set the recipient/sender email-address
$MailTo = "[email protected]"
$MailFrom = "$Company Backup <[email protected]>"
# SMTP user account password
$MailUser = "MyUser"
$MailPassword = "MyPassword"
# SMTP Server
$MailServer = "smtpserver.company.com"
# SMTP Port
$MailPort = 587
# If your server uses SSL, otherwise set to $false
$UseSSL = $true
#---- Don't change anything below ----#
#######################################
Try {
$CurrentTime = (Get-Date).ToString("yyyy-MM-dd HH:mm")
$Computer = Get-Content env:computername
$WBJob = Get-WBJob -Previous 1
$WBSummary = Get-WBSummary
$WBLastSuccess = ($WBSummary.LastSuccessfulBackupTime).ToString("yyyy-MM-dd HH:mm")
$WBResult = $WBSummary.LastBackupResultHR
$WBErrorMsg = $WBJob.ErrorDescription + "`n" + $WBSummary.DetailedMessage
$WBStartTime = $WBJob.StartTime
$WBEndTime = $WBJob.EndTime
$WBDuration = (New-TimeSpan -Start $WBStartTime -End $WBEndTime)
$Password = ConvertTo-SecureString $MailPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($MailUser, $Password)
Function FormatBytes
{
Param
(
[System.Int64]$Bytes
)
[string]$BigBytes = ""
#Convert to TB
If ($Bytes -ge 1TB) {$BigBytes = [math]::round($Bytes / 1TB, 2); $BigBytes += " TB"}
#Convert to GB
ElseIf ($Bytes -ge 1GB) {$BigBytes = [math]::round($Bytes / 1GB, 2); $BigBytes += " GB"}
#Convert to MB
ElseIf ($Bytes -ge 1MB) {$BigBytes = [math]::round($Bytes / 1MB, 2); $BigBytes += " MB"}
#Convert to KB
ElseIf ($Bytes -ge 1KB) {$BigBytes = [math]::round($Bytes / 1KB, 2); $BigBytes += " KB"}
#If smaller than 1KB, leave at bytes.
Else {$BigBytes = $Bytes; $BigBytes += " Bytes"}
Return $BigBytes
}
Function Log-BackupItems
{
Param
(
[System.String]$Name,
[System.String]$Status,
[System.Int64]$Bytes
)
$Item = New-Object System.Object;
$Item | Add-Member -Type NoteProperty -Name "Name" -Value $Name;
$Item | Add-Member -Type NoteProperty -Name "Status" -Value $Status;
$Item | Add-Member -Type NoteProperty -Name "Size" -Value (FormatBytes -Bytes $Bytes);
Return $Item;
}
$results=@()
$WBJob | % {
$_.JobItems | % {
$BackupItem = $null
If ($_.Name -eq 'VolumeList') {
$_ | % {$_.SubItemList | % {
$BackupItem = Log-BackupItems -Name $_.Name -Status $_.State -Bytes $_.TotalBytes
$results += $BackupItem
}}
}
Else {
$_ | % {
$BackupItem = Log-BackupItems -Name $_.Name -Status $_.State -Bytes $_.TotalBytes
$results += $BackupItem
}
}
}
}
# Change Result of 0 to Success in green text and any other result as Failure in red text
If ($WBResult -eq 0) { $WBResult = "Successful"}
Else {$WBResult = "Failed"}
# Assemble the HTML Report
$HTMLMessage = @"
<!DOCTYPE html>
<html>
<head>
<title>$Company Backup Report for $Computer</title>
<style>
body { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 12px }
h3{ clear: both; font-size: 150%; margin-left: 20px;margin-top: 30px; }
table { padding: 15px 0 20px; width: 500px; text-align: left; }
td, th { padding: 0 20px 0 0; margin 0; text-align: left; }
th { margin-top: 15px }
a, a:visited { color: #2ea3f2; text-decoration: none; }
#Report { width: 600px; }
#Successful { color: green }
#Failed { color: red }
</style>
</head>
<body>
<div id="Report">
<p><h3><a href="http://jocha.se">$Company Backup Report for $Computer</a></p></h3>
<table id="summary"><tbody>
<tr><td>Todays date:</td>
<td>$CurrentTime</td></tr>
<tr><td>Last Successful Backup:</td>
<td>$WBLastSuccess</td></tr>
<tr><td>Start time last backup:</td>
<td>$WBStartTime</td></tr>
<tr><td>End time last backup:</td>
<td>$WBEndTime</td></tr>
<tr><td>Duration last backup:</td>
<td>$WBDuration</td></tr>
<tr><td>Backup Result:</td>
<td><b id="$WBResult">$WBResult</b></td></tr>
<tr><td>Error Message (if applicable):</td>
<td>$WBErrorMsg</td></tr></tbody></table>
$(
$html = $results | ConvertTo-HTML -Fragment
$xml=[xml]$html
$attr=$xml.CreateAttribute('id')
$attr.Value='items'
$xml.table.Attributes.Append($attr) | out-null
$html=$xml.OuterXml | out-string
$html
)
</div>
</body>
</html>
"@
$email = @{
SMTPServer = $MailServer
UseSSL = $UseSSL
BodyAsHtml = $true
Port = $MailPort
Credential = $Credentials
Encoding = ([System.Text.Encoding]::UTF8)
To = $MailTo
From = $MailFrom
Subject = "$WBResult Backup on $Computer"
Body = $HTMLMessage
}
Send-MailMessage @email
}
Catch {
$email = @{
SMTPServer = $MailServer
BodyAsHtml = $true
UseSSL = $UseSSL
# Port is a PowerShell v3 variable
Port = $MailPort
Credential = $Credentials
Encoding = ([System.Text.Encoding]::UTF8)
To = $MailTo
From = $MailFrom
Subject = "Failed Backup on $Computer"
Body = "The backup script failed to run!"
}
Send-MailMessage @email
}
# Uncomment below to enable "Remote Report".
#}
We hope you’ve found this article helpful, feel free to share it on your social platforms.
Please let us know if you have any questions!


Hi bro
The script is excellent to me.
Need help on add-on "Destination" backup location.
Thanks bro
On Server 2008 need to install it first, see https://technet.microsoft.com/en-us/library/cc732081.aspx
Adding that feature works perfectly.
Script stopped workink on several servers since middle feb aprox. I wonder if it was due some change om the Office 365 service I use to send e-mail, maybe regarding to STARTTLS encryption method.
Erros message received, if it helps: "Client was not authenticated to send anonymous mail during MAIL FROM [CP2PR80CA0206.lamprd80.prod.outlook.com]"
Thanks for this great script.
I would like to add an information.
When you edit the trigger for the task you need to choose "Custom Settings" otherwise you cannnot choose all the different event IDs.
In the "Event Filter" you have to check all the "Event levels".
Maybe you can adopt the script with this information in the example area.
Well it worked first time! Sweet!
One question, is it possible to place multiple server results in a single email?
Consolidating to a single email would be nice!
Thanks!
Hi Andy,
Yes. Check the commented section at "Variables to change". You can define the servers to collect data from there.
This was exactly what I was looking for. Thank you so much.
I created the Scheduled Task to just run at a time of day instead of triggering from the event log. I also modified the email output a little to fit my needs. Solid work, thanks!
I wanted to send to multiple recipients, and a little googling led me to this change:
On line 32, enter multiple recipients separated by a semi-colon:
$MailTo = "[email protected];[email protected]"
Then revise lines 182 and 199 like such:
To = $MailTo.Split(';')
I tested that second change with and without multiple recipients, and it seems to deal with it both ways just fine.
I hope this helps anyone looking for that modification!
it works well for me. The economy is not good and business is difficult. I don't want my boss to spend 2000USD to purchase server backup software just becos of failure notification.