Weekend Scripter: Create an HTML Server Report with PowerShell

Doctor Scripto

Summary: Guest blogger, Matthew Kerfoot, talks about using Windows PowerShell to create an HTML server report.

Microsoft Scripting Guy, Ed Wilson, is here. Today I would like to welcome a new guest blogger, Matthew Kerfoot…

Photo of Matthew Kerfoot

I’m a Windows PowerShell enthusiast with strong interests in automating systems administration. I write a blog called The Overnight Admin where I like to share Windows PowerShell scripts, tips, and functions. I also tweet about Windows PowerShell at @mkkerfoot                         

The following function utilizes WMI to retrieve various information from local and remote machines and then outputs that data into a nicely formatted HTML file for easy viewing: Write-HTML.

Keep in mind that PSRemoting must be enabled, and a proper execution policy must be set to run scripts:

Enable-PSRemoting –Force ; Set-ExecutionPolicy RemoteSigned -Force

My Write-HTML function is about 60 lines of code, and I will not be able to touch on everything. My goal is to make the whole script as readable as possible for someone who has little to no experience with Windows PowerShell.

The first line turns this script into a function by bundling all the code into the function Write-HTML{}, which has a Help file. Because this is bundled into a function, all we have to do (after pasting the code into an elevated Windows PowerShell command prompt) is type “Write-HTML” to produce the following report about your local machine:

Image of report

function Write-HTML{



Creates an HTML file on the Desktop of the local machine full of detailed   system information.


    Write-HTML utilizes WMI to retrieve information related to the physical hardware of the machine(s), the available `

disk space, when the machine(s) last restarted and bundles all that information up into a colored HTML report.


   Write-HTML -Computername localhost, SRV-2012R2, DC-01, DC-02

   This will create an HTML file on your desktop with information gathered from as many computers as you can access remotely


I’ve added the CmdletBinding attribute to the script, which by itself, allows the use of all common parameters including Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer, and OutVariable.

However, by adding SupportsShouldProcess=$True into the CmdletBinding attribute, we can now test what this script would do if we ran it—for example, if we type Write-HTML -WhatIf, it won’t make any changes, but it will output to the console what the script would have done.


param( [Parameter(Mandatory=$false,


[string]$FilePath = “C:\users\$env:USERNAME\desktop\Write-HTML.html”,

[string[]]$Computername = $env:COMPUTERNAME,

After some of the more common parameters, there is a parameter called $Css, which is where the CSS code has been added to manipulate the HTML file. This is where we can change the color of the report, and format the table headers and data.

$Css='<style>table{margin:auto; width:98%}

     Body{background-color:Orange; Text-align:Center;}

     th{background-color:black; color:white;}

     td{background-color:Grey; color:Black; Text-align:Center;} </style>’ )

The script begins with a verbose output of what this script is going to do.  This will only be shown if the –Verbose or –WhatIf parameter is added after the function. The Begin, Process, and End blocks are not needed, so I like to use these to organize the script. This allows you to break up the sections of your scripts and collapse the sections within the Windows PowerShell ISE.

Begin{Write-Verbose “HTML report will be saved $FilePath”}

Next, the Process section of the script starts. My script has five variables defined within the Process brackets, which allows me to compact all the code after each equals sign into each variable, for example $Hardware, $PercentFree, $Restarted, $Stopped, and $Report. Each variable is accomplishing a specific task and will later be used with the creation of the HTML file.

Let’s examine the first variable within the Process block: $Hardware. First, all WMI information related to Win32_ComputerSystem is queried for each $ComputerName that is specified. By default, this function will only run against the local host, but you can add the -ComputerName  parameter, and specify all the computers you would like the function to run against.

After querying the selected computers, the WMI object is filtered for the objects specified. In this case, it would be: Name, Domain, Manufacture, Model, NumberofLogicalProccessors. But there is one more object that is being specified. This one is a little harder to see—we are also looking for TotalPhysicalMemory.  In this case, I am taking the object and dividing it by 1 GB to give me a more readable output. After it is divided by 1 GB, the output is formatted with {0:N0}, which represents a number in the one’s place or rounded to the nearest whole number (for example, {0:N3} would give you an output like 7.833).

Process{$Hardware=Get-WmiObject -class Win32_ComputerSystem -ComputerName $Computername |

     Select-Object Name,Domain,Manufacturer,Model,NumberOfLogicalProcessors,

     @{ Name = “Installed Memory (GB)” ; Expression = { “{0:N0}” -f( $_.TotalPhysicalMemory / 1gb ) } } |

     ConvertTo-Html -Fragment -As Table -PreContent “<h2>Hardware</h2>” | Out-String

When all the Win32_ComputerSystem information is gathered and filtered with Select-Object, everything is pushed through the pipeline to ConvertTo-Html -Fragment -As Table -PreContent “<h2>Available Disk Space</h2>” | Out-String.

Most of this is pretty straightforward, except the –PreContent parameter, which contains the section’s header information to be displayed above the hardware table. Out-String is the perfect cmdlet for creating HTML documents because it allows Windows PowerShell to convert the objects into an array of strings, yet it will only return one string by default. This gives us the availability to use variables such as $Hardware later in the script within the –Body of the HTML file.

$PercentFree=Get-WmiObject Win32_LogicalDisk -ComputerName $Computername |

     Where-Object { $_.DriveType -eq “3” } | Select-Object SystemName,VolumeName,DeviceID,

     @{ Name = “Size (GB)” ; Expression = { “{0:N1}” -f( $_.Size / 1gb) } },

     @{ Name = “Free Space (GB)” ; Expression = {“{0:N1}” -f( $_.Freespace / 1gb ) } },

     @{ Name = “Percent Free” ; Expression = { “{0:P0}” -f( $_.FreeSpace / $_.Size ) } } |

     ConvertTo-Html -Fragment -As Table -PreContent “<h2>Available Disk Space</h2>” | Out-String

$Restarted=Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Computername | Select-Object Caption,CSName,

     @{ Name = “Last Restarted On” ; Expression = { $_.Converttodatetime($_.LastBootUpTime) } } |

     ConvertTo-Html -Fragment -As Table -PreContent “<h2>Last Boot Up Time</h2>” | Out-String

$Stopped=Get-WmiObject -Class Win32_Service -ComputerName $Computername |

     Where-Object { ($_.StartMode -eq “Auto”) -and ($_.State -eq “Stopped”) } |

     Select-Object SystemName,DisplayName,Name,StartMode,State,Description |

     ConvertTo-Html -Fragment -PreContent “<h2>Services currently stopped that are set to autostart</h2>” | Out-String

The $Report variable is used to design the body and header of the report. The –Body parameter is where everything comes together—all of the previously created variables are placed within quotation marks so they get resolved. Without quotation marks, the body of the report would say: $Hardware $PercentFree $Restarted $Services $Stopped $Css. This is also where the -Title is defined, which changes what the browser tab will say when you view the report.

$Report=ConvertTo-Html -Title “$Computername” `

     -Head “<h1>PowerShell Reporting<br><br>$Computername</h1><br>This report was ran: $(Get-Date)” `

     -Body “$Hardware $PercentFree $Restarted $Services $Stopped $Css”}

The End block is where everything should come together and get cleaned up or formatted. Here, we’re taking the contents of $Report, which has already been converted to HTML, and piping it to the $FilePath (your desktop) specified at the beginning of the script. When complete, Invoke-Expression $FilePath will open the file in your default browser.

End{$Report | Out-File $Filepath  ; Invoke-Expression $FilePath  } }

Remember to paste the code into an elevated command prompt, and you can test the script first with Write-HTML –WhatIf.

You can download the whole function from the Script Center Repository: How to make an HTML server report with PowerShell or on SkyDrive: Write-HTML.

I invite you to follow me on Twitter, Facebook, and Google +. If you have any questions, feel free to email me at mkkerfoot@gmail.com.


Thanks for sharing your time and knowledge, Matthew. I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


Discussion is closed.

Feedback usabilla icon