Skip to main content
TechNet

Windows PowerShell: Revisiting Reports

Text-based reports can be dull and less informative, so why not use Windows PowerShell to generate HTML reports?

Don Jones

If you’re going to generate reports with Windows PowerShell, self-contained HTML reports are a much better option than text-based reports. My preference comes from the fact that HTML reports are significantly easier to create, look so much nicer than plain text, and are still easy to attach to an e-mail and send around the office.

Several months ago in this column, I gave you some tips for producing HTML reports in Windows PowerShell. This month, let’s look at how you can enhance those reports.

Let’s just jump straight to the code, which is shown in Figure 1. It should be saved into a script file, such as C:\Report.ps1.

Figure 1 Enhance those HTML Windows PowerShell reports.

param([string]$computername)

$b =  Get-WmiObject -class Win32_ComputerSystem -ComputerName $computername |
      Select-Object -Property Manufacturer,Model,
                              @{n='Memory(GB)';e={$_.TotalPhysicalMemory / 1GB -as [int]}},
                              @{n='Architecture';e={$_.SystemType}},
                              @{n='Processors';e={$_.NumberOfProcessors}} |
      ConvertTo-HTML -Fragment -As LIST -PreContent "<h2>Computer Hardware:</h2>" | 
Out-String

$b += Get-WmiObject -class Win32_LogicalDisk -ComputerName $computername |
      Select-Object -Property @{n='DriveLetter';e={$_.DeviceID}},
                               @{n='Size(GB)';e={$_.Size / 1GB -as [int]}},
                               @{n='FreeSpace(GB)';e={$_.FreeSpace / 1GB -as [int]}} |
      ConvertTo-Html -Fragment -PreContent "<h2>Disks:</h2>" | 
Out-String

$b += Get-WmiObject -class Win32_NetworkAdapter -ComputerName $computername | 
Where { $_.PhysicalAdapter } |
      Select-Object -Property MACAddress,AdapterType,DeviceID,Name |
      ConvertTo-Html -Fragment -PreContent "<h2>Physical Network Adapters:</h2>" | 
Out-String

$head = @'
<style>
body { background-color:#dddddd;
       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 { margin-left:50px; }
</style>
'@

ConvertTo-HTML -head $head -PostContent $b -Body "<h1>Hardware Inventory for $ComputerName</h1>"

You’d run the report in Figure 1 as follows:

C:\Report –computername localhost > output.htm

Here’s what I’ve done—you can see I’m using three calls to Get-WmiObject to retrieve different bits of information. Each time, I’m using Select-Object to select the properties in which I’m interested. In most cases, I’m creating customized columns so values like memory are displayed in a more convenient unit of measurement.

At the end of each, I’m using ConvertTo-HTML to produce an HTML fragment. This means I’m just getting the HTML needed to produce a table with my desired properties.

There’s a trick here that took me a long time to figure out. ConvertTo-HTML produces some weird stuff. Basically, it will produce collections of strings. Try feeding that to the final ConvertTo-HTML and you’ll get an error.

I worked around the problem using Out-String. You can see this in each of the first three blocks, where I’m piping the HTML fragment to Out-String. This ensures that each fragment is just a bunch of simple strings. As I create each HTML fragment, I append it into the $b variable.

You’ll also notice I’m using ConvertTo-HTML to apply section headers to those HTML fragments. Normally, ConvertTo-HTML just inserts that “pre content” as plain text. I’ve added <h2> HTML tags so my section headers appear as headings within the HTML.

After constructing the three blocks, I create an embedded HTML style sheet. This is where you can play with styles to get the look you want for the final report. Check the reference to the Cascading Style Sheet (CSS) language for more on style sheets. As long as you can live with relatively simple styling, CSS isn’t too complicated.

The last line of my script uses a final ConvertTo-HTML. I insert the stylesheet into the HTML page header, add an overall heading for the page and insert the contents of $b. The final HTML in Internet Explorer can be seen in Figure 2.

After modifying the style sheets and converting output to HTML, this is the result

Figure 2 After modifying the style sheets and converting output to HTML, this is the result.

Here are a few other tricks I want to point out:

  1. In my first two Select-Object commands, notice I’ve used a hashtable syntax to construct custom output properties. In most cases, I’m just creating a better-looking name for the output columns. In three cases, though, I’m doing some math to convert bytes to gigabytes.
  2. In the first block where I query Win32_ComputerSystem, I’m having ConvertTo-HTML format the information in a list instead of the default table style (the –As LIST parameter). Because the output will only cover a single computer system, I thought the list looked nicer.
  3. I had to fool around with the stylesheet quite a bit to get it looking like I wanted. CSS is powerful, but it can take a bit of tweaking to get the exact style you want.

You might wonder why the script itself doesn’t redirect the final output to a file, and that would be a good question. My script leaves the HTML in the Windows PowerShell pipeline, which means I don’t have to put it into a file if I’d rather do something else.

For example, I’ve written a custom function that lets me pipe in the HTML. It constructs an HTML-formatted e-mail message from that content. By having my script leave the HTML in the pipeline, I can either pipe the HTML to my mail-sending function, pipe the HTML to a file, or do whatever else I want with it. Simply outputting HTML leaves me with the greatest number of options.

Above all, I didn’t use Write-Host. Write-Host sends output directly to the screen. It gives you no options to redirect that to a file, turn it into an e-mail message or anything else.

Because I’m using ConvertTo-HTML, Windows PowerShell is doing all the work of actually formatting my output. I didn’t have to fool with that, either. By simply messing with the CSS, I can easily change the look of the final output.

You can even insert a style sheet for on-screen display, and a separate style sheet for printed output. That way, if someone prints your report, they can have formatting that’s appropriate for hardcopy. To do so, just build your style sheet like Figure 3.

Figure 3 Different style sheets allow for on-screen display and printed output.

$head = @'
<style media='screen'>
body { background-color:#dddddd;
       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 { margin-left:50px; }
</style>
<style media='print'>
// Put alternate hardcopy styles here
</style>
'@

This is a great way to build reports because it really leverages the patterns and techniques of Windows PowerShell. It’s easy to extend a report to include additional information. The script that produces the report is relatively easy to follow for someone else who might need to do the maintenance. And each section of the report is produced by a single (albeit lengthy) Windows PowerShell command line, so they’re easy to rearrange, repurpose and reuse.

Don Jones

Don Jones is a Microsoft MVP Award recipient and author of “Learn Windows PowerShell in a Month of Lunches” (Manning Publications, 2011), a book designed to help any administrator become effective with Windows PowerShell. Jones also offers public and on-site Windows PowerShell training. Contact him through his Web site at ConcentratedTech.com.

Related Content