I hope you have been enjoying this little series on tips and tricks for doing more with ConvertTo-HTML and creating great looking reports in PowerShell. Today, I want to continue where we left off. I am assuming you have been following along. If not, take some time to start at the beginning or you may be a bit lost.

Often, I create reports from a number of HTML fragments. Usually, I have multiple pieces of information that I want to display. Perhaps, I want to parse the HTML, so I can do things, such as dynamically add style classes as I did last time. I am going to repeat that process today by reusing the core code from the previous article. In addition to event log information, I want to get some other system information as well. Let’s begin with it empty:



1 $fragments = @ ( )



The first thing I want to do is embed a graphic file in the document. The easy way would be to use the <IMG> tag and specify the path to a graphic file. However, I like making my HTML files portable or self-contained. The first step is to convert the file to a Base64 string.



1 2 $ImagePath = "c:\scripts\db.png" $ImageBits = [ Convert ] :: ToBase64String ( ( Get-Content $ImagePath -Encoding Byte ) )



When I create the IMG tag, I want to include an ALT attribute for the file name. I also need to know the file type.



1 2 $ImageFile = Get-Item $ImagePath $ImageType = $ImageFile . Extension . Substring ( 1 ) #strip off the leading .



All that remains is to create the IMG tag.



1 $ImageTag = "<Img src='data:image/$ImageType;base64,$($ImageBits)' Alt='$($ImageFile.Name)' style='float:left' width='120' height='120' hspace=10>"



The only thing you really need is the src value. You can experiment with style settings or other IMG attributes. Since I want the graphic at the top of the file, I will add it to the array of fragments.



1 $fragments += $ImageTag



I know that I am going to include some operating system information, so I might as well add a header for it.



1 2 3 #adjust spacing - takes trial and error $fragments += "<br><br>" $fragments += "<H2>OS Info</H2>"



I plan on using Get-CimInstance to retrieve operating system information. I only need a few properties converted to an HTML fragment.<p>



1 2 3 $fragments += Get-Ciminstance -ClassName win32_operatingsystem | Select @ { Name = "Operating System" ; Expression = { $_ . Caption } } , Version , InstallDate | ConvertTo-Html -Fragment -As List



You should notice that I did something different here. By default, fragments are created as HTML tables. For this section, I wanted a list. You can mix and match lists and tables as you see fit.

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.

Next up is some system information, which will come from this function:



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Function Get-SystemInfo { [ cmdletbinding ( ) ] Param ( [ string ] $Computername = $env : COMPUTERNAME ) #this function has no real error handling $cs = Get-CimInstance -ClassName Win32_computersystem -ComputerName $Computername #this assumes a single processor $proc = Get-CimInstance -ClassName win32_processor -ComputerName $Computername $data = [ ordered ] @ { TotalPhysicalMemGB = $cs . TotalPhysicalMemory / 1GB -as [ int ] NumProcessors = $cs . NumberOfProcessors NumLogicalProcessors = $cs . NumberOfLogicalProcessors HyperVisorPresent = $cs . HypervisorPresent DeviceID = $proc . DeviceID Name = $proc . Name MaxClock = $proc . MaxClockSpeed L2size = $proc . L2CacheSize L3Size = $proc . L3CacheSize } New-Object -TypeName PSObject -Property $data }



Remember, you always want to convert objects to HTML. In this situation, I want the system information displayed as a list too.



1 2 $fragments += "<H2>System Info</H2>" $fragments += Get -systeminfo -Computername $env : COMPUTERNAME | ConvertTo-Html -Fragment -As List



From here, I will reuse my code from last time to get and process event log information, highlighting empty logs with red text. I will also include my standard footer.





1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $fragments += "<H2>EventLog Info</H2>" [ xml ] $html = 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 -Fragment for ( $i = 1 ; $i -le $html . table . tr . count -1 ; $i ++ ) { if ( $html . table . tr [ $i ] . td [ 3 ] -eq 0 ) { $class = $html . CreateAttribute ( "class" ) $class . value = 'alert' $html . table . tr [ $i ] . attributes . append ( $class ) | out-null } } $fragments += $html . InnerXml $fragments += "<p class='footer'>$(get-date)</p>"



The last part is to define my hashtable of parameters for ConvertTo-HTML and create the final document.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $convertParams = @ { head = @" <Title>System Report - $($env:computername)</Title> <style> 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 : 2px ; margin : 0px ; white-space : pre ; } tr:nth-child(odd) { background-color : lightgray } table { width : 95% ; margin-left : 5px ; margin-bottom : 20px ; } h2 { font-family : Tahoma ; color : #6D7B8D ; } .alert { color : red ; } .footer { color : green ; margin-left : 10px ; font-family : Tahoma ; font-size : 8pt ; font-style : italic ; } </style> "@ body = $fragments } convertto-html @ convertParams | out-file d : \ temp \ sysreport . htm



I moved the computer name to the report title. Here is the final result.

A Mixed HTML Report Built with PowerShell (Image Credit: Jeff Hicks)

Of course, all of this code is something you would put into a script or function to make it easier to use. Not that the example I have been working with is especially compelling, but I hope you will pay more attention to the techniques I used. That is the real takeaway. If you get stuck with your own PowerShell scripts creating HTML reports, I encourage you to use the PowerShell forums.

Before we leave this topic, I want to come back one more time and show you a technique I think you will find useful.