Using HTML to create PDF Reports (Part 2)

by Oct 7, 2022

HTML can be a simple way of formatting data for output reports. In this second part we illustrate how you convert properties that contain arrays to string lists. Arrays cannot be correctly displayed as text, so this problem applies to both HTML reports and exporting data to CSV.

Have a look: the code below composes a HTML report with all of your services which is where we left off at the end of part 1:

$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# compose style sheet
$stylesheet = "
<style>
body { background-color:#AAEEEE;
font-family:Monospace;
font-size:10pt; }
table,td, th { border:1px solid blue;}
th { color:#00008B;
background-color:#EEEEAA; 
font-size: 12pt;}
table { margin-left:30px; }
h2 {
font-family:Tahoma;
color:#6D7B8D;
}
h1{color:#DC143C;}
h5{color:#DC143C;}
</style>
"

# output to HTML
$data | ConvertTo-Html -Title Report -Head $stylesheet | Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path

When you look at the report, you notice that some columns contain data types instead of data, i.e. RequiredServices and DependentServices. The reason is because these properties contain arrays. To display the property content correctly, you need to first convert the arrays to string lists.

Here is a function that automatically detects properties that contain arrays and replaces these with string lists:

function Convert-ArrayToStringList
{
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        $PipelineObject
    )
    process
    {
        $Property = $PipelineObject.psobject.Properties | 
                        Where-Object { $_.Value -is [Array] } | 
                        Select-Object -ExpandProperty Name
                        
        foreach ($item in $Property)
        {
            $PipelineObject.$item = $PipelineObject.$item -join ','
        
          
        }

        return $PipelineObject
    }
}

For this to work, you first must run your results through Select-Object in order to get a copy of the objects that you can then manipulate. Convert-ArrayToStringList can be very helpful for creating CSV exports as well. The code below creates the services list as a CSV file and makes sure all properties are readable, then loads the CSV file into Microsoft Excel:

$Path = "$env:temp\report.csv"

Get-Service |
Select-Object -Property * |
Convert-ArrayToStringList |
Export-Csv -NoTypeInformation -Encoding UTF8 -Path $Path -UseCulture

Start-Process -FilePath excel -ArgumentList $Path

Here is the full script that now creates a services report with all properties readable:

$path = "$env:temp\report.html"

# get data from any cmdlet you wish
$data = Get-Service | Sort-Object -Property Status, Name

# helper function to convert arrays to string lists
function Convert-ArrayToStringList
{
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        $PipelineObject
    )
    process
    {
        $Property = $PipelineObject.psobject.Properties | 
                        Where-Object { $_.Value -is [Array] } | 
                        Select-Object -ExpandProperty Name
                        
        foreach ($item in $Property)
        {
            $PipelineObject.$item = $PipelineObject.$item -join ','
        
          
        }

        return $PipelineObject
    }
}


# compose style sheet
$stylesheet = "
    <style>
    body { background-color:#AAEEEE;
    font-family:Monospace;
    font-size:10pt; }
    table,td, th { border:1px solid blue;}
    th { color:#00008B;
    background-color:#EEEEAA; 
    font-size: 12pt;}
    table { margin-left:30px; }
    h2 {
    font-family:Tahoma;
    color:#6D7B8D;
    }
    h1{color:#DC143C;}
    h5{color:#DC143C;}
    </style>
"

# output to HTML
$data | 
# make sure you use Select-Object to copy the objects
Select-Object -Property * |
Convert-ArrayToStringList |
ConvertTo-Html -Title Report -Head $stylesheet | 
Set-Content -Path $path -Encoding UTF8

Invoke-Item -Path $path 

 


Twitter This Tip! ReTweet this Tip!