Thursday, November 19, 2009

Messing with output from Format-Table

Found at question at psobject.codeplex.com:

I was wondering if I could write the outout without any blank spaces between 2 fields. For example, I am using hash tables to display 2 columns from dir output. But it always comes up with a blank space between those 2 data elements. I need this to generate a fixed format output with data elements only and no spaces in between. Any help is greatly appreciated.

$column1 = @{expression="mode";width=5;label="mode";alignment="left"}
$column2 = @{expression="name";width=10;label="name";alignment="left"}

$dir |format-table $column1,$column2

$mode  name
----  ----
d---- download
d---- extract
-a--- alias.txt
-a--- Compute...
-a--- execute...
-a--- get_dn.ps1
-a--- hh

Well, it can be done. I looked into the objects the Format-Table spit out and after some poking around, I came up with this -

$column1 = @{expression="mode";width=5;label="mode";alignment="left"}
$column2 = @{expression="name";width=20;label="name";alignment="left"}

# Save widths, all non-fixed length value should specify a width
$widths=@{}
dir | format-table $column1,@{l="|";e={"|"}},$column2 | foreach {
if ($_.pstypenames[0] -eq "Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData") {
# Capture the values and convert them to one value
$value=""
$count=$_.formatentryinfo.formatPropertyFieldList.count
foreach($i in 0..($count-1)) {
$value+=$_.formatentryinfo.formatPropertyFieldList.item($i).propertyvalue.ToString().padright($widths.$i)
}
# Delete all but one field
$_.formatentryinfo.formatPropertyFieldList.removerange(1,$count-1)
# and update its value
$_.formatentryinfo.formatPropertyFieldList.item(0).propertyValue=$value
$_
}
elseif ($_.pstypenames[0] -eq "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData") {
# Capture the headers and convert them to one header
$value=""
$width=0

$count=$_.shapeinfo.tablecolumninfolist.count
foreach($i in 0..($count-1)) {
$w=$_.shapeinfo.tablecolumninfolist.item($i).width
$width+=$w
$widths.$i=$w
$value+=$_.shapeinfo.tablecolumninfolist.item($i).propertyname.ToString().padright($w)
}
# Delete all but one field
$_.shapeinfo.tablecolumninfolist.removerange(1,$count-1)
# and update its value
$_.shapeinfo.tablecolumninfolist.item(0).propertyName=$value
$_.shapeinfo.tablecolumninfolist.item(0).width=$width
$_
}
else
{
$_
}
}







If you like it, convert it to a function as en exercise ;)



 



Happy formatting!

2 comments:

Jason Archer said...

To answer the user's question, it would be far easier to do this:

dir | ForEach-Object {"Mode Name";"---------"} {"{0}{1}" -f $_.Mode,$_.Name}

I used string formatting so that you can add padding like so: "{0,-10}{1}"

Now, if you wanted to do this for any ole object, then it would be more worth while to let Format-Table do the dirty work.

Per Østergaard said...

@Jason

Your suggestion was also my first reaction, but to still be able to utilize Format-Table and to let people use what they already know, I decided to look a way to manipulate the output from Format-Table.

:)