Reputation: 27756
I have a cmdlet that uses Format-Table
to output potentially long strings (such as registry paths). I would like to set each column width to the output buffer width divided by the number of columns.
Example:
function Write-Something {
[CmdletBinding()] param()
$o = [pscustomobject]@{ a = 'A' * 100; b = 'B' * 100 }
$columnWidth = [int]( $PSCmdlet.Host.UI.RawUI.BufferSize.Width / 2 )
$o | Format-Table @{ e = 'a'; width = $columnWidth }, @{ e = 'b'; width = $columnWidth } -wrap
}
This works nicely for console output, where it produces output like this:
a b - - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAA BBBBBBBBBBBB
When I specify a different output buffer width, using the Width
argument of Out-String
or Out-File
, the formatting won't change, it will still be based on the console buffer width.
Write-Something | Out-File test.txt -Width 200
This produces the same output as above whereas the expected output should be columns of width 100, with no wrapping occuring.
How can I get the actual output buffer width set by the Width
argument of Out-String
or Out-File
from within my cmdlet?
Upvotes: 5
Views: 2929
Reputation: 27756
Simple workaround:
If the first column(s) are of a fixed width, the remaining columns will be spread out evenly over the remaining width.
$o = [pscustomobject]@{ a = 'A' * 100; b = 'B' * 100 }
$o | Format-Table @{ e = ' '; width = 1 }, 'A', 'B' -wrap
Output:
a b - - - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBB
This creates an empty column which looks slightly awkward. In practice we might have useful data that fits into the first fixed-width column, e. g. numbering each row:
$o = 1..2 | ForEach-Object { [pscustomobject]@{ a = 'A' * 100; b = 'B' * 100 } }
$i = 0
$numbered = { $i; ( Get-Variable i -Scope 1 ).Value++ }
$o | Format-Table @{ n = '#'; width = 3; e = $numbered }, 'A', 'B' -wrap
Output:
# a b - - - 1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBB 2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB AAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBB
A numbered column actually makes a table with wrapped columns easier to read, as it is easier to see where each row begins.
We could also remove the empty column from the output like this:
$o | Format-Table @{ e = ' '; width = 1 }, 'A', 'B' -wrap |
Out-String -Stream | ForEach-Object { $_ -replace '^[-\s]\s' }
Upvotes: 1
Reputation: 46
The problem is that you've already fixed the width in your Write-Something cmdlet. The PowerShell way to do this would be for your cmdlet to output your unformatted data objects and for you to replace Out-File with your own cmdlet which controls the output width.
function Write-Something {
[CmdletBinding()] param()
$o = [pscustomobject]@{ a = 'A' * 100; b = 'B' * 100 }
Write-Output $o
}
function Out-Something {
[CmdletBinding()] param(
[Parameter(ValueFromPipeline=$true)]
[psobject]$InputObject,
[Parameter(Position=1)]
[String]$FilePath,
[Parameter(Position=2)]
[int]$Width
)
$columnWidth = [int]( $Width / 2 )
$InputObject | Format-Table @{ e = 'a'; width = $columnWidth }, @{ e = 'b'; width = $columnWidth } -Wrap | `
Out-File -FilePath $FilePath -Width $Width
}
Write-Something | Out-Something test.txt -Width 200
Upvotes: 3