
close
close
I have been having a lot of fun with this series of articles demonstrating a variety of tips, tricks, and techniques to generate killer HTML reports with PowerShell and ConvertTo-HTML. By all means, use as little or as much as you want. If you missed the previous articles, get caught up before continuing. I will not explain the previously covered material.
I will confess right up front that I am not a web developer or even close. I know some basic HTML techniques and like you, have gleaned ideas from searching the Internet. One of those techniques is the use of javascript. While I probably could not write a javascript function from scratch, I do know how to use it in my PowerShell scripts. At some point in the past, I found some functions to create expandable sections. This is great for a long HTML document because you can collapse one or more sections.
In my header here string, where I define my CSS, I am going to insert this code.
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'> </script> <script type='text/javascript'> function toggleDiv(divId) { `$("#"+divId).toggle(); } function toggleAll() { var divs = document.getElementsByTagName('div'); for (var i = 0; i < divs.length; i++) { var div = divs[i]; `$("#"+div.id).toggle(); } }
The code assumes you will have a named DIV section that you want to collapse or expand. Let’s revise the example from the last article.
advertisment
$computername = $env:COMPUTERNAME $fragments = @() #insert a graphic $ImagePath = "c:\scripts\db.png" $ImageBits = [Convert]::ToBase64String((Get-Content $ImagePath -Encoding Byte)) $ImageFile = Get-Item $ImagePath $ImageType = $ImageFile.Extension.Substring(1) #strip off the leading . $ImageTag = "<Img src='data:image/$ImageType;base64,$($ImageBits)' Alt='$($ImageFile.Name)' style='float:left' width='120' height='120' hspace=10>" $top = @" <table> <tr> <td class='transparent'>$ImageTag</td><td class='transparent'><H1>System Report - $Computername</H1></td> </tr> </table> "@ $fragments+=$top
Most of this should look familiar to you by now. One thing I am doing differently is putting the graphic in a table with the document title. I do not want this table to follow the same style as other tables. Therefore, I am defining a style called ‘transparent’ that sets the cell background color to the same as the document background color.
.transparent { background-color:#E5E4E2; }
Now, let’s add the new stuff. I want to define some section headings that when clicked, will toggle between expanded and collapsed. I also want to include a link at the beginning to toggle all sections. I will add the necessary script code to my array of fragments.
$fragments+="<a href='javascript:toggleAll();' title='Click to toggle all sections'>+/-</a>"
This will insert a link with the text “+/-“. When clicked, this will invoke the toggleAll javascript function. Now, we wll add the first section.
$Text = "Operating System" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">"
I am calling the DIV section the same as the text but I need to remove any spaces for the DIV id. After this section heading, I need to insert my content and add the closing DIV tag.
advertisment
$fragments+= Get-Ciminstance -ClassName win32_operatingsystem -ComputerName $computername | Select @{Name="Operating System";Expression= {$_.Caption}},Version,InstallDate | ConvertTo-Html -Fragment -As List $fragments+="</div>"
I repeat the process as needed.
$Text = "System Information" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">" $fragments+= Get-systeminfo -Computername $computername| ConvertTo-Html -Fragment -As List $fragments+="</div>" $Text = "Disk Information" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">" #highlight low free space in red [xml]$html = Get-DiskInfo -Computername $computername| ConvertTo-Html -Fragment for ($i=1;$i -le $html.table.tr.count-1;$i++) { if ($html.table.tr[$i].td[-1] -le 20) { $class = $html.CreateAttribute("class") $class.value = 'alert' $html.table.tr[$i].childnodes[3].attributes.append($class) | out-null } } $fragments+= $html.InnerXml $fragments+="</div>"
When finished, I can create my final document from the collection of fragments. For your convenience, here is a script with all of my final code.
[cmdletbinding()] Param( [string]$computername = $env:COMPUTERNAME, #the path to the final htm report [string]$Path = "d:\temp\systemreport.htm", #set your own default graphic or delete default value [string]$ImagePath = "c:\scripts\db.png" ) #region helper functions Function Get-SystemInfo { [cmdletbinding()] Param([string]$Computername = $env:COMPUTERNAME) $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 } Function Get-DiskInfo { [cmdletbinding()] Param([string]$Computername = $env:COMPUTERNAME) Get-CimInstance -ClassName win32_logicaldisk -filter "drivetype=3" -ComputerName $Computername | Select DeviceID, @{Name="SizeGB";Expression = {$_.size/1gb -as [int]}}, @{Name="FreeGB";Expression={ [math]::round($_.Freespace/1gb,2)}}, @{Name="PctFree";Expression={[math]::round(($_.freespace/$_.size)*100,2)}} } #endregion $fragments = @() if (Test-Path $ImagePath) { #insert a graphic $ImageBits = [Convert]::ToBase64String((Get-Content $ImagePath -Encoding Byte)) $ImageFile = Get-Item $ImagePath $ImageType = $ImageFile.Extension.Substring(1) #strip off the leading . $ImageTag = "<Img src='data:image/$ImageType;base64,$($ImageBits)' Alt='$($ImageFile.Name)' style='float:left' width='120' height='120' hspace=10>" } else { Write-Warning "Could not find image file $ImagePath" } $top = @" <table> <tr> <td class='transparent'>$ImageTag</td><td class='transparent'><H1>System Report - $Computername</H1></td> </tr> </table> "@ $fragments+=$top $fragments+="<a href='javascript:toggleAll();' title='Click to toggle all sections'>+/-</a>" $Text = "Operating System" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">" $fragments+= Get-Ciminstance -ClassName win32_operatingsystem -ComputerName $computername | Select @{Name="Operating System";Expression= {$_.Caption}},Version,InstallDate | ConvertTo-Html -Fragment -As List $fragments+="</div>" $Text = "System Information" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">" $fragments+= Get-systeminfo -Computername $computername| ConvertTo-Html -Fragment -As List $fragments+="</div>" $Text = "Disk Information" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">" #highlight low free space in red [xml]$html = Get-DiskInfo -Computername $computername| ConvertTo-Html -Fragment for ($i=1;$i -le $html.table.tr.count-1;$i++) { if ($html.table.tr[$i].td[-1] -le 20) { $class = $html.CreateAttribute("class") $class.value = 'alert' $html.table.tr[$i].childnodes[3].attributes.append($class) | out-null } } $fragments+= $html.InnerXml $fragments+="</div>" $Text = "EventLog Info" $div = $Text.Replace(" ","_") $fragments+= "<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><h2>$Text</h2></a><div id=""$div"">" [xml]$html = Get-Eventlog -List -ComputerName $computername | 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+="</div>" $fragments+= "<p class='footer'>$(get-date)</p>" $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; } .transparent { background-color:#E5E4E2; } </style> <script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'> </script> <script type='text/javascript'> function toggleDiv(divId) { `$("#"+divId).toggle(); } function toggleAll() { var divs = document.getElementsByTagName('div'); for (var i = 0; i < divs.length; i++) { var div = divs[i]; `$("#"+div.id).toggle(); } } </script> "@ $convertParams = @{ head = $head body = $fragments } convertto-html @convertParams | out-file -FilePath $Path Get-Item -Path $Path
I have added my default values. You would want to change them for yourself. When I run the script, I end up with a file like this.
A Collapsed HTML Report (Image Credit: Jeff Hicks)
Expanded Sections (Image Credit: Jeff Hicks)
More from Jeff Hicks
advertisment
Petri Newsletters
Whether it’s Security or Cloud Computing, we have the know-how for you. Sign up for our newsletters here.
advertisment
More in PowerShell
Microsoft’s New PowerShell Crescendo Tool Facilitates Native Command-Line Wraps
Mar 21, 2022 | Rabia Noureen
Most popular on petri
Log in to save content to your profile.
Article saved!
Access saved content from your profile page. View Saved
Join The Conversation
Create a free account today to participate in forum conversations, comment on posts and more.
Copyright ©2019 BWW Media Group