Powershell Format-Wide and Sorting
I found something that does exactly what I want, and is more generic:
http://www.leporelo.eu/blog.aspx?id=powershell-formatting-format-wide-rotated-to-format-columns (dead link)
- Version 0.4 code (pasted at the bottom of this answer in case this link dies too)
- Archived 0.1 code (included because it has more discussion/examples)
Example with regular Format-Wide
'The basic promise behind implicit remoting is that you can work ' +
'with remote commands using local syntax.' -split ' ' | Format-Wide -force -prop {$_} -col 3
The basic promise
behind implicit remoting
is that you
can work with
remote commands using
local syntax.
Example with Format-Columns
'The basic promise behind implicit remoting is that you can work ' +
'with remote commands using local syntax.' -split ' ' | . Format-Columns -col 3
The is remote
basic that commands
promise you using
behind can local
implicit work syntax.
remoting with
I am still surprised Powershell doesn't have a built-in option to do this.
Version 0.4 code:
function Format-Columns {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[PsObject[]]$InputObject,
[Object]$Property,
[int]$Column,
[int]$MaxColumn,
[switch]$Autosize
)
Begin { $values = @() }
Process { $values += $InputObject }
End {
function ProcessValues {
$ret = $values
$p = $Property
if ($p -is [Hashtable]) {
$exp = $p.Expression
if ($exp) {
if ($exp -is [string]) { $ret = $ret | % { $_.($exp) } }
elseif ($exp -is [scriptblock]) { $ret = $ret | % { & $exp $_} }
else { throw 'Invalid Expression value' }
}
if ($p.FormatString) {
if ($p.FormatString -is [string]) { $ret = $ret | % { $p.FormatString -f $_ } }
else { throw 'Invalid format string' }
}
}
elseif ($p -is [scriptblock]) { $ret = $ret | % { & $p $_} }
elseif ($p -is [string]) { $ret = $ret | % { $_.$p } }
elseif ($p -ne $null) { throw 'Invalid -property type' }
# in case there were some numbers, objects, etc., convert them to string
$ret | % { $_.ToString() }
}
if (!$Column) { $Autosize = $true }
$values = ProcessValues
$valuesCount = @($values).Count
if ($valuesCount -eq 1) {
return $values
}
# from some reason the console host doesn't use the last column and writes to new line
$consoleWidth = $host.ui.RawUI.maxWindowSize.Width - 1
$gutterWidth = 2
# get length of the longest string
$values | % -Begin { [int]$maxLength = -1 } -Process { $maxLength = [Math]::Max($maxLength,$_.Length) }
# get count of columns if not provided
if ($Autosize) {
$Column = [Math]::Max( 1, ([Math]::Floor(($consoleWidth/($maxLength+$gutterWidth)))) )
$remainingSpace = $consoleWidth - $Column*($maxLength+$gutterWidth);
if ($remainingSpace -ge $maxLength) {
$Column++
}
if ($MaxColumn -and $MaxColumn -lt $Column) {
$Column = $MaxColumn
}
}
$countOfRows = [Math]::Ceiling($valuesCount / $Column)
$maxPossibleLength = [Math]::Floor( ($consoleWidth / $Column) )
# cut too long values, considers count of columns and space between them
$values = $values | % {
if ($_.length -gt $maxPossibleLength) { $_.Remove($maxPossibleLength-2) + '..' }
else { $_ }
}
#add empty values so that the values fill rectangle (2 dim array) without space
if ($Column -gt 1) {
$values += (@('') * ($countOfRows*$Column - $valuesCount))
}
# in case there is only one item, make it array
$values = @($values)
<#
now we have values like this: 1, 2, 3, 4, 5, 6, 7, ''
and we want to display them like this:
1 3 5 7
2 4 6 ''
#>
$formatString = (1..$Column | %{ "{$($_-1),-$maxPossibleLength}" }) -join ''
1..$countOfRows | % {
$r = $_-1
$line = @(1..$Column | %{ $values[$r + ($_-1)*$countOfRows]} )
Write-Output "$($formatString -f $line)".PadRight($consoleWidth,' ')
}
}
<#
.SYNOPSIS
Formats incoming data to columns.
.DESCRIPTION
It works similarly as Format-Wide but it works vertically. Format-Wide outputs the data row by row, but Format-Columns outputs them column by column.
.PARAMETER Property
Name of property to get from the object.
It may be
-- string - name of property.
-- scriptblock
-- hashtable with keys 'Expression' (value is string=property name or scriptblock)
and 'FormatString' (used in -f operator)
.PARAMETER Column
Count of columns
.PARAMETER Autosize
Determines if count of columns is computed automatically.
.PARAMETER MaxColumn
Maximal count of columns if Autosize is specified
.PARAMETER InputObject
Data to display
.EXAMPLE
1..150 | Format-Columns -Autosize
.EXAMPLE
Format-Columns -Col 3 -Input 1..130
.EXAMPLE
Get-Process | Format-Columns -prop @{Expression='Handles'; FormatString='{0:00000}'} -auto
.EXAMPLE
Get-Process | Format-Columns -prop {$_.Handles} -auto
.NOTES
Name: Get-Columns
Author: stej, http://twitter.com/stejcz
Site: http://www.leporelo.eu/blog.aspx?id=powershell-formatting-format-wide-rotated-to-format-columns
Lastedit: 2017-09-11
Version 0.4 - 2017-09-11
- removed color support and changed output from Write-Host to Write-Output
Version 0.3 - 2017-04-24
- added ForegroundColor and BackgroundColor
Version 0.2 - 2010-01-14
- added MaxColumn
- fixed bug - displaying collection of 1 item was incorrect
Version 0.1 - 2010-01-06
#>
}