Thursday, July 10, 2014

Neatly Formatting a HashTable in Verbose Output

Had a problem where the Verbose output I was emitting looked like crap because all of the entries were neatly aligned until I tried to share the contents of a hash table.

Nicely formatted verbose output seems obsessive until you have to consume it.  Keeping the verbose output pretty makes it easier to spot issues when things go wrong.  If the details you’re after are all over the screen then it will be too difficult to scan, so you’ll miss stuff.

First, we need to turn up the verbose noise, and create a sample hashtable.

 

### Turn verbose noise up

$VerbosePreference = 'Continue'

 

### Sample table, of hash

$hashTable = @{

    foo     = '10'

    bar     = '2'

    fitzbar = '300000'

    baz     = '400'

}

 

 

The way I had been outputting is like this:

 

Write-Verbose "This is nicely aligned: foo"

Write-Verbose "This is my hashtable: $($hashTable | Out-String)"

Write-Verbose "This too is nicely aligned and easy to scan"

 

Which produced this (below). Not bad, the details are there but it doesn’t make it easy to scan the verbose output because my eyes no have to dart over to the left.

 

 

VERBOSE: This is nicely aligned: foo

VERBOSE: This is my hashtable:

Name                           Value                                           

----                           -----                                           

baz                            400                                             

bar                            2                                               

foo                            10                                              

fitzbar                        300000                                          

 

 

 

VERBOSE: This too is nicely aligned and easy to scan

 

 

A couple more lines of code fixed that problem:

 

### Find the longest Key to determine the column width

$columnWidth = $hashTable.Keys.length | Sort-Object| Select-Object -Last 1

 

### Output the HashTable using the column width

Write-Verbose "This is nicely aligned: foo"

Write-Verbose "This is my hashtable: "

$hashTable.GetEnumerator() | ForEach-Object {

    Write-Verbose ("  {0,-$columnWidth} : {1}" -F $_.Key, $_.Value) -Verbose

}

Write-Verbose "This too is nicely aligned and easy to scan"

 

Now I get each hashtable entry on its own line, nicely aligned.

 

VERBOSE: This is nicely aligned: foo

VERBOSE: This is my hashtable:

VERBOSE:   baz     : 400

VERBOSE:   bar     : 2

VERBOSE:   foo     : 10

VERBOSE:   fitzbar : 300000

VERBOSE: This too is nicely aligned and easy to scan

 

1 comment:

Alex Tcherniakhovski said...

Thanks Craig - this is exactly what I was looking for.

I extended your idea to format my PSObjects by converting them to HashTable (http://stackoverflow.com/questions/3740128/pscustomobject-to-hashtable):

$h = @{}

if($hashTable -is [PSObject])
{
$hashTable.PSObject.Properties | foreach {$h."$($_.Name)" = $_.Value} | Out-Null
}
elseif($hashTable -is [HashTable])
{
$h = $hashTable
}
else
{
Write-Verbose "This Cmdlet only formats PSObjects and HashTables" -Verbose
return
}

# the rest of the code is the same

Alex