PowerShell

Creating Colorful Emails with PowerShell

color-aspect-hero

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 = @"
<Title>$ReportTitle</Title>
<style>
body { background-color:#FFFFFF;
font-family:Tahoma;
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 }
</style>
<br>
<H1>$ReportTitle</H1>
"@


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

Sponsored Content

What is “Inside Microsoft Teams”?

“Inside Microsoft Teams” is a webcast series, now in Season 4 for IT pros hosted by Microsoft Product Manager, Stephen Rose. Stephen & his guests comprised of customers, partners, and real-world experts share best practices of planning, deploying, adopting, managing, and securing Teams. You can watch any episode at your convenience, find resources, blogs, reviews of accessories certified for Teams, bonus clips, and information regarding upcoming live broadcasts. Our next episode, “Polaris Inc., and Microsoft Teams- Reinventing how we work and play” will be airing on Oct. 28th from 10-11am PST.

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
$html.table.tr[$_]
}

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[$_]
$td.childnodes
}

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[$_]
$td.childnodes.item(3)
}

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:

BECOME A PETRI MEMBER:

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

Register
Comments (1)

One response to “Creating Colorful Emails with PowerShell”

Leave a Reply

External Sharing and Guest User Access in Microsoft 365 and Teams

This eBook will dive into policy considerations you need to make when creating and managing guest user access to your Teams network, as well as the different layers of guest access and the common challenges that accompany a more complicated Microsoft 365 infrastructure.

You will learn:

  • Who should be allowed to be invited as a guest?
  • What type of guests should be able to access files in SharePoint and OneDrive?
  • How should guests be offboarded?
  • How should you determine who has access to sensitive information in your environment?

Sponsored by: