zett42
zett42

Reputation: 27756

Format-Table set column width depending on the output buffer width

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

Problem

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

Answers (2)

zett42
zett42

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' }

More Format-Table shenanigans

Upvotes: 1

pg7733
pg7733

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

Related Questions