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!
It works with a few corrections :
a)Port = $MailPort only works when Powershell version is 3.
I had to comment #Port = $MailPort
b)Also in version 2, i had to swap the parameters like so : -ExecutionPolicy Bypass -Command "C:\Scripts\WBJobReport.ps1", or I would get the error : "execution of the script is disabled on this system"
c) I had to use $UseSSL = $false, to bypass a certifacte error
Hi Bogdan,
Thank you for your feedback. Updated the script to clarify.
Best regards,
Joakim
If I comment port=$Mailport on PSv2 (sbs2011,) I then get an authentication error when sending to gmail.
Anyone else have this problem?
Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at
At C:\Scripts\WBJobReport.ps1:193 char:21
+ Send-MailMessage <<<< @email
+ CategoryInfo : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpException
+ FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage
In order to get this to work with gmail in PSv2, I commented out the $Password and $Credentials variables in 39 and 40, then replaced the Send-MailMessage cmdlets (everything below line 163) with:
$smtpClient = new-object system.net.mail.smtpClient
$smtpClient.Host = $MailServer
$smtpClient.EnableSsl = $UseSSL
$smtpClient.Port = $MailPort
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "P@ssW0rd!");
$emailto = $MailTo
$emailfrom = $MailFrom
$subject = "$WBResult Backup on $Computer"
$body = $HTMLMessage
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = $EmailFrom
$emailMessage.To.Add($EmailTo)
$emailMessage.Subject = $Subject
$emailMessage.IsBodyHTML = $true
$emailMessage.BodyEncoding = ([system.Text.Encoding]::UTF8)
$emailMessage.Body = $Body
$SMTPClient.Send($emailMessage)
}
Catch {
$smtpClient = new-object system.net.mail.smtpClient
$smtpClient.Host = $MailServer
$smtpClient.EnableSsl = $UseSSL
$smtpClient.Port = $MailPort
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "P@ssW0rd!");;
$emailto = $MailTo
$emailfrom = $MailFrom
$subject = "$WBResult Backup on $Computer"
$body = "The backup script failed to run!"
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = $EmailFrom
$emailMessage.To.Add($EmailTo)
$emailMessage.Subject = $Subject
$emailMessage.IsBodyHTML = $true
$emailMessage.BodyEncoding = ([system.Text.Encoding]::UTF8)
$emailMessage.Body = $Body
$SMTPClient.Send($emailMessage)
}
PS : I used Windows 2008 R2 Standard
PS2 : In case of error I only get an email body with : "The backup script failed to run!"
Hi Bogdan,
If you would like to know where the script fails:
Remove row 44 and 178. Then remove everything between row 180 and 195.
Run the script again and you'll receive the proper error message.
Best regards,
It appears that these instructions were for a previous build of your script. Can you please provide the instructions for v4.1? Thanks
Hi there,
Have used this script on sever servers and works great, but unable to get it working on 2012 r2 Essentials, seems to use PS v4. Any thoughts or advice?
Hi,
Are there any specific reasons that you have not implemented Windows Management Framework 4.0 in your environment yet?
Best regards,
Joakim
The "PowerShell ISE" (not installed by default sometimes and needs adding as a feature first) needs to have the policy bypass ran on it Set-ExecutionPolicy RemoteSigned and say yes to the massage. Once done the script should run OK.
You can also use the PS ISE to edit the script easy and run it manually from it too.
Great script!
Isn't it supposed to trigger on event id 4 as well?
Possibly, I usually trigger the task on a set time (not a big fan of getting e-mails in the middle of the night).
Best regards,
Joakim
Hello,
I have also the error "The backup script failed to run!"
I'm testing in a Windows 2008 SP" PSv3
I tried as you respond to @Bogdan but with no luck
This is awesome and works very well but is there a way to make this run for a list of servers?
i.e. $computers = @("SVR1","SVR2","SVR3")
foreach ($computer in $computers)
I've tried myself but I'm not nearly PS savvy enough.
Hi Paighton,
I've updated the script so it can be run on one server and generate reports on several remote servers. Uncomment row 22, 23 and 200.
Regards,
Joakim
Nice thanks for sharing, works perfectly with 2012r2
Hi,
Running great on Win 2012, but on Win 2008 R2 I just get failure messages even if the job has run successfully.
Thanks for the script, it's great for our System State backups. Much appreciated
Hi Neil,
Try the new version 4.1, updated today. Don't forget to change the variables. Please make sure you're running at least Windows Management Framework 3.0 (https://www.microsoft.com/en-us/download/details.aspx?id=34595).
Best regards,
Joakim
Thank you Joakim for this awesome script!!
since I ran this on my Hyper-V server, I added the following lines after line 111 to show my VMs instead of volumes:
ElseIf ($_.Name -eq 'VirtualMachineList') {
$_ | % {$_.SubItemList | % {
$BackupItem = Log-BackupItems -Name $_.Name -Status $_.State -Bytes $_.TotalBytes
$results += $BackupItem
}}
}
Thanks for providing this! I'm having a slight problem that maybe you could assist with?
Everytime I run a backup the only notification I get is the "backup failed to run" but I watched the wbadmin process and it completed successfully.
Maybe it would help to know where the script pulls the reports from? I looked over it but couldn't determine where they're located.
Thanks for you help!
Hi Rob,
It could be that the mailing part is failing. Doesn't necessarily mean that the "backup log" part fails.
If you comment out row 51, and then delete row 188 and everything below it. This will show you the errors if you run the script in a prompt.
See my comment below
I have 3 servers (2 2012 r2 and one 2008 r2 all standards) script works really well in the 2 2012 r2 and I get this error on 2008 r2:
Send-MailMessage : Mailbox unavailable. The server response was: 5.7.1 Unable to relay for user@domain (replaced real email with this)
At C:\Users\administrator.TLPNET\Desktop\WBJobReport.ps1:204 char:5
+ Send-MailMessage @email
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpFailedRecip
ientException
+ FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage
I tried locally and running the script remotely and same results 2 ok and one failing…..
Thanks
Humberto
I get a message saying unable to connect to remote server. Any help would be great.
Hi Joachim, this script is a lifesaver and works great on Server 2012 R2 but gives me the following when run on Server 2008 R2 (both servers are using gmail as smtp):
Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The server response
was: 5.5.1 Authentication Required. Learn more at
At C:\Admin\Backups\Backup.ps1:204 char:5
+ Send-MailMessage @email
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpException
+ FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage
Any help is greatly appreciated!!!
Hi, I have written a post about an HTML reporting module that can help generate HTML reports very easily from within your Powershell scripts.
Check it out here
http://www.azurefieldnotes.com/2016/08/04/powershellhtmlreportingpart1/
Thanks for writing the script. I've set it up on one of my 2012 R2 servers and the script runs with no errors. However when I set up a Task Schedule, run the backup job, I do not get an email on either a failure or success. Do I need to set up any mail services on the 2012 server?
TIA
Hi Mike,
Yes, you need to have a mail server. Local or cloud doesn't matter as long as you set the script up to use the right port and protocol.
Best regards,
Joakim
On Server 2012R2 I can manually run the script and it works fine after I enter admin username and password in the login prompt. When I set it as a scheduled task using the same credentials the script fails to run. What could be happening?
Hi Shawn,
You shouldn't be getting a login prompt. Are you using the latest version of the script, with the variables properly filled in?
Best regards,
Joakim
Joakim,
Version 4.1 of the script is now working for me on Server 2012 R2. Thank you so much for sharing your work!
I have this same problem on Win Server 2012
Try checking if the snapins are installed with Add-PSSnapin Windows.ServerBackup
at the PS prompt. I got credentials prompt on Server 2008r2 with the powershell backup scripts not installed
i changed this line:
$Password = ConvertTo-SecureString $MailPassword -AsPlainText -Force
to:
$Password = Get-Content C:\scripts\EmailPassword.txt | ConvertTo-SecureString
So i dont have to insert my mail Passwort in this script.
I only have to run this line once on this Server:
"myPassword" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "C:\scripts\EmailPassword.txt"
But this is a nice clean script, thanks for the work.
script works fine on SBS2011, when i setup automation i get an error by Event ID(s)= 4,5,8,9,17,22,49,50,52,100,517,518,521,527,528,544,545,546,561,564,612
only numbers allowed, any idea?
Is there a simple way to modify the script so that it only sends an email when a backup fails?
Thanks
Hi Ben,
If you set it to trigger on a timer it will send a "failed report". If you set it to trigger by event simply add the ID for failed windows backup.
Best regards,
Joakim