2021 Annual Petri Reader Survey - We want to know what's important to you! 2021 Annual Petri Reader Survey - We want to know what's important to you!

Creating Colorful Emails with PowerShell


In the comments on a recent article about creating a color coded report of domain controller service statuses, there was a question in the comments about sending the same type of information, presumably colorized, in an email message. PowerShell makes it very easy to send email with the Send-MailMessage cmdlet. You can even send HTML messages, which is the key to answering this question.

As in the previous articles, I need to get the service information from my domain controllers. Of course, this could be other data that you want to report.

$dcs = "chi-dc01","chi-dc02","chi-dc04"
$svcs = "adws","dns","kdc","netlogon"
$data = Get-Service -name $svcs -ComputerName $dcs

I’ll also define a title for the report.
$ReportTitle = "Domain Controller Services"

Now for the first tricky part. When we create HTML documents in PowerShell, typically with ConvertTo-HTML, style is applied separately, usually through a CSS file. But you can also embed style information in the head of an HTML document. I’ll create a here-string with an embedded style sheet.
$head = @"
body { background-color:#FFFFFF;
font-size:12pt; }
td, th { border:1px solid black;
border-collapse:collapse; }
th { color:white;
background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
table { width:95%;margin-left:5px; margin-bottom:20px;}
.stopped {color: Red }
.running {color: Green }
.pending {color: #DF01D7 }
.paused {color: #FF8000 }
.other {color: Black }

The relevant parts for dynamically colorizing our output is in lines 13 to 17. These settings will be used to define a new style class. The settings inside the curly brackets will be applied for each match. All I’m doing is setting the font color. I’m using a mix of color names like red and HTML color codes. The better practice would probably be to use color codes for everything. Now we’re ready to start generating some HTML.

I only need a few properties, so I’ll select them and pipe to Convertto-Html. I don’t want a complete document yet, because I’m going to have to adjust it first to account for the different service statues. I have found the easiest solution is to create an HTML fragment, but treat it as an XML document.

[xml]$html = $data |
Select @{Name="DomainController";Expression={$_.MachineName.ToUpper()}},Name,Displayname,Status |
ConvertTo-Html -Fragment

Why? Because I can now “walk” the document.

HTML as an XML document
HTML as an XML document (Image Credit: Jeff HIcks)

It will be much easier to reference specific rows and columns. I’ll skip the first row since it is the table header.

1..($html.table.tr.count-1) | foreach {
#enumerate each TD

Enumerating the table
Enumerating the table (Image Credit: Jeff Hicks)

What I’m really seeing, remember this is an XML document, is a collection of child nodes.

1..($html.table.tr.count-1) | foreach {
#enumerate each TD
$td = $html.table.tr[$_]

Expanding the table rows
Expanding the table rows (Image Credit: Jeff Hicks)

Because I know the Status column is the last row, I can select just that node.

1..($html.table.tr.count-1) | foreach {
#enumerate each TD
$td = $html.table.tr[$_]

Listing text values
Listing text values (Image Credit: Jeff HIcks)

My intention is to add a style class to this column based on the text value.

1..($html.table.tr.count-1) | foreach {
#enumerate each TD
$td = $html.table.tr[$_]
#create a new class attribute
$class = $html.CreateAttribute("class")

#set the class value based on the item value
Switch ($td.childnodes.item(3).'#text') {
"Running" { $class.value = "running"}
"Stopped" { $class.value = "stopped"}
"Pending" { $class.value = "pending"}
"paused" { $class.value = "paused"}
Default { $class.value = "other"}
#append the class
$td.childnodes.item(3).attributes.append($class) | Out-Null

If I look again, I’ll now see the class attribute.

The new class attribute
The new class attribute (Image Credit: Jeff Hicks)

At this point my HTML is complete, and I can see it as the InnerXML property of my XML document. I’ve highlighted a few of the changes.

The updated HTML code
The updated HTML code (Image Credit: Jeff Hicks)

All that remains now is to create the final HTML report. If I wanted to create a stand-alone report I can use ConvertTo-Html and send the results to a file.

ConvertTo-HTML -Head $head -Body $html.InnerXml -PostContent “<h6>Created $(Get-Date)</h6>” |
Out-File -filepath c:\work\DCSvcs.htm -Encoding asci

The end result is an HTML report that looks like this:

Sample HTML report
Sample HTML report (Image Credit: Jeff HIcks)

Or if I want to send this as an email message, I’ll convert to HTML and save the results to a variable.

[string]$body = ConvertTo-HTML -Head $head -Body $html.InnerXml -PostContent "<h6>Created $(Get-Date)</h6>"

The body needs to be a string, which is why I am explicitly telling PowerShell to treat it as a string. I can define a hashtable of parameter values for Send-MailMessage.
[email protected]{
To = "[email protected]"
From = "[email protected]"
Subject = "Domain Controller Status Report"
SMTPServer = "smtp.mycompany.com"
Body = $Body
BodyAsHTML = $True
Port = 587
UseSSL = $True
Credential = $mailCred

You will have different needs depending on your mail server. I splat the parameters:
Send-MailMessage @mailparams

And the mail is sent.

Sample HTML email
Sample HTML email (Image Credit: Jeff Hicks)

So the long answer to the original question is that you can send a colorized email, but you’ll need an HTML document that has been dynamically modified with some styling. I use many of these techniques for a lot of my HTML reporting needs. If I lost you anywhere in the process, please feel free to post a question in the comments.

Related Topics:


Don't have a login but want to join the conversation? Sign up for a Petri Account

Comments (1)

One response to “Creating Colorful Emails with PowerShell”

  1. asa75asa

    Can't see the images in the article :(

Leave a Reply

Register for the Hybrid Identity Protection (HIP) Europe Conference!

Hybrid Identity Protection (HIP) Europe 2021 - Virtual Conference

Mobile workforces, cloud applications, and digitalization are changing every aspect of the modern enterprise. And with radical transformation come new business risks. Hybrid Identity Protection (HIP) is the premier educational forum for identity-centric practitioners. At the inaugural HIP Europe, join your local IAM experts and Microsoft MVPs to learn all the latest from the Hybrid Identity world.