Last Update: Sep 04, 2024 | Published: Feb 11, 2016
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
Why? Because I can now “walk” the document.
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[$_] }
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 }
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) }
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.
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.
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:workDCSvcs.htm -Encoding asci
The end result is an HTML report that looks like this:
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.
$mailParams=@{ 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.
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.