Subscribe to Petri Newsletters Office 365 Insider Our Petri Office 365 Insider is dedicated to sharing detailed knowledge from top Office 365 experts. Delivered once a month to your inbox. All Newsletters Petri.com may use your contact information to provide updates, offers and resources that may be of interest to you. You can unsubscribe at any time. To learn more about how we manage your data, you can read our Privacy Policy and Terms of Service. !Already a Petri.com member? Login here for 1-click registration.

Everybody loves a nice HTML report. Am I right? Creating these reports in PowerShell is not that difficult. I thought I would offer up some tips and tricks you may not be aware of, including a few that I use all the time when I am creating reports. Some of these are documented in the help for ConvertTo-HTML. You do read the help, correct? Remember that ConvertTo-HTML does not create an actual file, just the HTML code. This is good for us. This means that we can modify the HTML on the fly and save the file when finished.

Be Selective

The first, and perhaps most important tip, is to be selective. Let’s take a simple command and output like this one.

A Simple PowerShell Command (Image credit: Jeff Hicks)

You want to create an HTML version of this, so you run a command like this:



1 Get-EventLog -list | convertto-html | out-file d : \ temp \ a . htm



When you open the file in your browser, things are not quite what you expected.

Converted Output (Image credit: Jeff Hicks)

This is because Convertto-Html, like Export-CSV and Export-Clixml, take the entire object. This is not just the default result you see on the screen. Remember, everything will be treated as a string. In my example, if I want a similar HTML file, I will have to recreate the output with Select-Object. This might require piping the original result to Get-Member to discover the “real” property names.



1 2 3 4 Get-Eventlog -List | Select @ { Name = "Max(K)" ; Expression = { $_ . MaximumKilobytes } } , @ { Name = "Retain" ; Expression = { $_ . MinimumRetentionDays } } , OverFlowAction , @ { Name = "Entries" ; Expression = { $_ . entries . count } } , @ { Name = "Log" ; Expression = { $_ . LogDisplayname } }



I always test without converting first.

Recreating Output (Image credit: Jeff Hicks)

I get a list instead of a table but at least the properties are correct. Let’s recreate the HTML file by piping the above to Convert-HTML and then Out-File overwriting the original and useless file.

The Revised File (Image credit: Jeff Hicks)

This is much better compared to what I had originally. Although, since everything is being treated as a string, I can format the numeric values to look more like the original PowerShell output.



1 2 3 4 Get-Eventlog -List | Select @ { Name = "Max(K)" ; Expression = { "{0:n0}" -f $_ . MaximumKilobytes } } , @ { Name = "Retain" ; Expression = { $_ . MinimumRetentionDays } } , OverFlowAction , @ { Name = "Entries" ; Expression = { "{0:n0}" -f $_ . entries . count } } , @ { Name = "Log" ; Expression = { $_ . LogDisplayname } } | convertto-html -Title "Event Log Report" | out-file d : \ temp \ a . htm



I also went and added a title, so I get something more useful than HTML TABLE.

A Better Formatted Report (Image credit: Jeff Hicks)

Use Pre/Post Content

We are starting to build something with a bit more visual appeal. This leads me to another suggestion, take advantage of the pre and post content parameters.

When you pipe something to ConvertTo-HTML, the cmdlet generally creates a table. But you can insert additional HTML directives for things to put in before the main code and after. You can use as much html code as you want.



1 2 3 4 5 6 Get-Eventlog -List | Select @ { Name = "Max(K)" ; Expression = { "{0:n0}" -f $_ . MaximumKilobytes } } , @ { Name = "Retain" ; Expression = { $_ . MinimumRetentionDays } } , OverFlowAction , @ { Name = "Entries" ; Expression = { "{0:n0}" -f $_ . entries . count } } , @ { Name = "Log" ; Expression = { $_ . LogDisplayname } } | convertto-html -Title "Event Log Report" -PreContent "<H1>$($env:COMPUTERNAME)</H1>" -PostContent "<H5><i>$(get-date)</i></H5>" | out-file d : \ temp \ a . htm



I added an intro element using the H1 tag to display the computer name. Following the content, I am inserting the current date and time formatted with the H5 heading and italic tags.

Report with Pre and Post Content (Image credit: Jeff Hicks)

Of course, you can always specify the path to a CSS file.



1 2 3 4 5 6 Get-Eventlog -List | Select @ { Name = "Max(K)" ; Expression = { "{0:n0}" -f $_ . MaximumKilobytes } } , @ { Name = "Retain" ; Expression = { $_ . MinimumRetentionDays } } , OverFlowAction , @ { Name = "Entries" ; Expression = { "{0:n0}" -f $_ . entries . count } } , @ { Name = "Log" ; Expression = { $_ . LogDisplayname } } | convertto-html -Title "Event Log Report" -PreContent "<H1>$($env:COMPUTERNAME)</H1>" -PostContent "<H5><i>$(get-date)</i></H5>" -CssUri C : \ scripts \ text . css | out-file d : \ temp \ a . htm



With a Style Sheet (Image credit: Jeff Hicks)

If you want to play along at home, this is the CSS code I am using:



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 body { background-color : #E5E4E2 ; font-family : Monospace ; font-size : 10pt ; } td, th { border : 0px solid black ; border-collapse : collapse ; white-space : pre ; } th { color : white ; background-color : black ; } table, tr, td, th { padding : 0px ; margin : 0px ; white-space : pre ; } table { margin-left : 25px ; } h2 { font-family : Tahoma ; color : #6D7B8D ; } .footer { color : green ; margin-left : 25px ; font-family : Tahoma ; font-size : 8pt ; }





I am using a file on my hard drive. This means that if anyone else were to look at the file, they would not get the same formatting. The solution is to use a CSS file path that everyone can reach. Check back later for the next article in this series.