Powershell: converto-html separate values onto new lines

Viewed 31

I'm building a script that will create an html report containing a table with multiple values in each Column Row (e.g. given cell may have 1 or more values). I'm building my output variable like this (assume there is a bunch of script before that is going to put data into all those variables):

I'm going to return the data generated here as part of a function call


$dlphashtable=[Ordered]@{
        Exchange = ($exchangemembers | Out-String).Trim()
        OneDriveUsers = ($onedrivemembers | Out-String).Trim()
        OneDriveGroups = ($onedrivesites | Out-String).Trim()
        SharePoint = ($sharepointlocations | Out-String).Trim()
        Teams = ($teamslocations | Out-String).Trim()
        Endpoints = ($endpointdlplocations | Out-String).Trim()
        DefenderforCA = ($defenderforCAlocations | Out-String).Trim()
        OnPremDLP = ($onpremlocations | Out-String).Trim()
    }

    $dlppolicydetailobject = [PSCustomObject]$dlphashtable
        
    return $dlppolicydetailobject

If I output this data to a csv, grid-view, or to the screen, each one of the items shows up on a new line as i want it to (and i'd expect). Grid View Output Image Excel Output Image

However if I convert the file to HTML then the table formats the text based on the width of the browser. View of converto-html output

How can I make the output so that each of the values in the HTML table show up on a new line in their appropriate column?

1 Answers

If your intent is to simply force line breaks between the multiple values represented in a single table cell, you must separate them with <br> HTML elements instead of literal newlines (which is what Out-String uses; literal newlines are not preserved as such in HTML rendering).

The challenge is that ConvertTo-Html automatically escapes the property values it puts into table cells, so that verbatim <br> turns into &lt;br&gt;. The workaround is to insert the <br> strings afterwards, and for that you can mark the places where it goes with a character you don't expect to be part of the values, a NUL ([char] 0x0), represented as "`0" as an expandable string is the ideal candidate:

# Note: No need for `return`: This both constructs and outputs
#       the custom object.
([pscustomobject] @{
  Exchange       = $exchangemembers -join "`0"
  OneDriveUsers  = $onedrivemembers -join "`0"
  OneDriveGroups = $onedrivesites -join "`0"
  SharePoint     = $sharepointlocations -join "`0"
  Teams          = $teamslocations -join "`0"
  Endpoints      = $endpointdlplocations -join "`0"
  DefenderforCA  = $defenderforCAlocations -join "`0"
  OnPremDLP      = $onpremlocations -join "`0"
} | ConvertTo-Html) -replace "`0", '<br>'

Original form of the answer, which applies to a different use case:

If you have multiple collections with corresponding elements and you want want to represent each set of corresponding elements in a separate table row, you need to construct multiple objects, with the properties of each containing one element from each input array:

# The list of all arrays.
$arrays = @(
  $exchangemembers,
  $onedrivemembers,
  $onedrivesites,
  $sharepointlocations,
  $teamslocations,
  $endpointdlplocations,
  $defenderforCAlocations,
  $onpremlocations
)

# Find the max. element count among all arrays.
$maxElemCount = ($arrays | ForEach-Object Count | Measure-Object -Maximum).Maximum

# Loop over all arrays and construct and output
# a [pscustomobject] for each set of corresponding elements.
foreach ($i in 0..($maxElemCount-1)) {
  [pscustomobject] @{
    Exchange       = $exchangemembers[$i]
    OneDriveUsers  = $onedrivemembers[$i]
    OneDriveGroups = $onedrivesites[$i]
    SharePoint     = $sharepointlocations[$i]
    Teams          = $teamslocations[$i]
    Endpoints      = $endpointdlplocations[$i]
    DefenderforCA  = $defenderforCAlocations[$i]
    OnPremDLP      = $onpremlocations[$i]
  }    
}

# Note: No `return` statement needed - the above loop
#       *implicitly* output all objects.
Related