Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
July 8, 2025

Creating HTML Reports with PowerShell Part 2

Last time, we kicked off our journey into HTML reporting with PowerShell, exploring the basics of creating HTML content, primarily using ConvertTo-Html. What I've shown you thus far is probably enough if you only need to the output from a single command. For more complex reports, I think you will want to take advantage of HTML fragments. We'll also look at other reporting features you might want to take advantage of.

> I am using PowerShell 7 for my examples. The ConvertTo-Html cmdlet in PowerShell 7 has a few more features than the one in Windows PowerShell, so if you are still using Windows PowerShell, you will have to adjust the examples slightly.

Using Fragments

I have always found fragments feature of ConvertTo-Html to be incredibly useful. Using fragments I can create an HTML document with a mix of tables and lists. Although, I should point out that if you prefer a list, you can use the -As parameter with ConvertTo-Html to create a list from any object.

$file = Join-Path -path $env:temp -childpath "winsvc.html"
Get-Service win* | Select-Object Name,Status,DisplayName,StartUpType,Description |
ConvertTo-Html -title "Win Service Report" -As List | Out-File -filepath $file
Creating List Output
figure 1

The -Fragment parameter is a separate feature. Instead of creating a complete HTML document, it creates a fragment that can be inserted into an existing HTML document. The default format is a table, but you can use -As to change the format to a list.

I often build reports and use fragments to insert headings. Create an array or generic list to hold the fragments. Add each fragment to the list or array, and use the fragments as the body.

$Computername = $env:COMPUTERNAME
$cimParam = @{
    OutVariable = 'c'
    ComputerName = $Computername
    ClassName = "Win32_OperatingSystem"
}
$fragments = @()

#save the operating system name
$os = Get-CimInstance @cimParam -Property Caption

#ComputerSystem
$cimParam.ClassName = 'Win32_ComputerSystem'
$cs = Get-CimInstance @cimParam |
Select-Object Manufacturer, Model, SystemFamily, SystemSKUNumber, SystemType, NumberOf*, TotalPhysicalMemory
#capture the computername from the CimInstance
$computerName = $c.CimSystemProperties.ServerName

#split the class name and use the second part as the heading,
#e.g. Win32_ComputerSystem becomes ComputerSystem
$fragments += "<h3>$($c.CimClass.CimClassName.split('_')[1])</h3>"
$fragments += $cs | ConvertTo-Html -Fragment -As List

#volumes
$cimParam.ClassName = 'Win32_Volume'
$vol = Get-CimInstance @cimParam -filter "DriveType=3" |
Select-Object Name, Label, FreeSpace, Capacity
$fragments += "<h3>$($c.CimClass.CimClassName.split('_')[1])</h3>"
$fragments += $vol | ConvertTo-Html -Fragment -As Table

#processor
$cimParam.ClassName = 'Win32_Processor'
$cpu = Get-CimInstance @cimParam |
Select-Object DeviceID, Name, Caption, MaxClockSpeed, *CacheSize, NumberOf*, SocketDesignation, *Width, Manufacturer
$fragments += "<h3>$($c.CimClass.CimClassName.split('_')[1])</h3>"
$fragments += $cpu | ConvertTo-Html -Fragment -As List

#memory
$cimParam.ClassName = 'Win32_PhysicalMemory'
$mem = Get-CimInstance @cimParam | Select-Object BankLabel, Capacity, DataWidth, Speed
$fragments += "<h3>$($c.CimClass.CimClassName.split('_')[1])</h3>"
$fragments += $mem | ConvertTo-Html -Fragment -As Table

$title = "System Configuration Report"

#embedding the CSS
#preContent is out of order when using fragments so I'll move it to the head
$head = @"
<title>$title</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 }
tr:nth-child(odd) {background-color: LightGray}
table { width:95%;margin-left:5px; margin-bottom:20px;}
</style>
<h1>$Title</h1>
<h2>$computerName | $($os.caption)</h2>
"@

$post = "<h5><i>Report run $(Get-Date)</i></h5>"
$splat = @{
    PostContent = $post
    Head        = $head
    Body        = $Fragments
}

$report = Join-Path -Path $env:temp -ChildPath "SystemReport-$Computername.html"
ConvertTo-Html @splat | Out-File $report
Want to read the full issue?
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.