Tuesday, 20 March 2012

Sending SharePoint system notification e-mails using PowerShell

The script in this article demonstrates an example of how you could use PowerShell to send system notification e-mails to administrators on a scheduled basis. Of course, there are a number of ways to do this sort of thing, including SharePoint workflows, Microsoft SCOM, and custom code. I’m not saying PowerShell is necessarily better than these methods, but I like the flexibility it brings, and as you have full access to the Object Model, you could send notifications from all sorts of areas – for example, successes and errors from the crawl logs, information from the User Profile service application, timer jobs with last run times, list items, site users, etc.

The example I have chosen here is to send an HTML e-mail listing the currently active items from the SharePoint Health Analyzer. This information is effectively just stored in a SharePoint list on the Central Administration site, so I will need to access the list, query the active items and send this information using the SMTP mail server and reply addresses specified in the farm outbound e-mail settings.


First of all we need to get the Central Administration web application and site objects from the farm. Note that we do not need to specify any URLs here - The command will automatically find Central Administration using options provided in the SharePoint 2010 cmdlets:

#Get Central Admin Web Application and Web objects
$caWebApp = (Get-SPWebApplication -IncludeCentralAdministration) | ? { $_.IsAdministrationWebApplication -eq $true }
$caWeb = Get-SPWeb -Identity $caWebApp.Url

Next we can specify the user or group e-mail address that will receive the message, followed by the sender’s e-mail address and the name of the SMTP server sending the message, which I am taking from the farm outbound e-mail settings stored in the Central Administration web application. If you want to send the message to more than one user or group, you could set up an array and walk through each item.

#Set up from, to and server addresses
$toAddress = "svc_installsp2010@domain2010.lab"
$fromAddress = $caWebApp.OutboundMailReplyToAddress
$serverAddress = $caWebApp.OutboundMailServiceInstance.Server.Address

The following part of the script gets the Health Analyzer list (internal name “HealthReports”) and the default display form URL. We need this URL later when configuring hyperlinks in the HTML, so that users can click on a health report directly from the e-mail to show it in the browser.

#Get Health Analyzer list on Central Admin site
$healthList = $caWeb.GetList("\Lists\HealthReports")
$displayFormUrl = $caWeb.Url + ($healthList.Forms | where { $_.Type -eq "PAGE_DISPLAYFORM" }).ServerRelativeUrl

This is probably the trickiest part of the script as it uses a CAML query to find all items in the Health Analyzer, except for those with the Severity column set to “4 – Success”. In other words, it queries any item that the Health Analyzer considers to be a problem on the farm. The CAML itself is specified in the first line below – I’m not going to go into how to write this stuff as there are quite a number of references available on the Internet already.

$queryString = "<Where><Neq><FieldRef Name='HealthReportSeverity' /><Value Type='Text'>4 - Success</Value></Neq></Where>"
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = $queryString
$items = $healthList.GetItems($query)

This next section creates the subject and HTML body for the e-mail message. If you know HTML then you will see what is happening, and if you don’t then that’s another subject for you to learn! The key part from a SharePoint perspective is the foreach ($item in $items) routine, as this is where the script walks through each list item found from the query above and injects the column values into the HTML. Note where the $displayFormUrl variable is used from earlier to set up the URL used for the hyperlink. I’m also using the built-in ConvertTo-Html PowerShell cmdlet to format the HTML.

#Set up e-mail message subject and HTML body
$msgTitle = "Health Analyzer results for farm " + $caWebApp.Farm.Name + " - " + (Get-Date)
#HTML head
$head = "<style type=`"text/css`">.tableStyle { border: 1px solid #000000; }</style>"
$head = $head + "<Title>$msgTitle</Title>"
#Create HTML body by walking through each item and adding it to a table
$body = "<H2>$msgTitle</H2><table cellspacing=`"0`" class=`"tableStyle`" style=`"width: 100%`">"
foreach ($item in $items)
    $itemUrl = $displayFormUrl + "?id=" + $item.ID
    [array]$itemValues = @($item["Severity"], $item["Category"], $item["Explanation"], $item["Modified"])
    $body = $body + "<tr>"
    $body = $body + "<td class=`"tableStyle`"><a href=`"" + $itemUrl + "`">" + $item.Title + "</a></td>"
    $itemValues | ForEach-Object {
        $body = $body + "<td class=`"tableStyle`">$_</td>"
    $body = $body + "</tr>"
$body = $body + "</table>"
#Create message body using the ConvertTo-Html PowerShell cmdlet
$msgBody = ConvertTo-Html -Head $head -Body $body

Finally, the commands below use the System.Net.Mail .NET class to send the e-mail, using the IsBodyHtml boolean property to ensure it goes as an HTML message.

#Create e-mail message object using System.Net.Mail class
$msg = New-Object System.Net.Mail.MailMessage($fromAddress, $toAddress, $msgTitle, $msgBody)
$msg.IsBodyHtml = $true
#Send message
$smtpClient = New-Object System.Net.Mail.SmtpClient($serverAddress)

That’s it! The e-mail will be sent when the script is run and should look similar to the one shown below. As you can see, the items in the e-mail match up to the items shown in the Health Analyzer screenshot at the beginning of this article.


You can use Task Scheduler in Windows if you want to send the e-mail on a scheduled basis. Please see this article for more details on how to use Task Scheduler for running PowerShell scripts with SharePoint.