Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Controlling column widths with Format-Table

Tags:

I am trying to get the last reboot time of some PCs from a list. When I use

foreach ($pc in $pclist) {   Get-CimInstance -ClassName win32_operatingsystem -ComputerName $pc |     select csname, lastbootuptime  } 

The output comes as following.

csname       lastbootuptime ------       -------------- CONFA7-L1-1A 7/15/2016 9:55:16 AM CONFA7-L1-1F 5/31/2016 8:51:46 AM CONFA7-L1-1G 6/18/2016 11:09:15 AM CONFA7-L1... 6/26/2016 5:31:31 PM CONFA7-L3... 7/24/2016 3:48:43 PM

Which is neat, but if the PC name is long, I am unable to see the full name. So I pipelined Format-Table:

Get-CimInstance -ClassName win32_operatingsystem -ComputerName $pc |   select csname, lastbootuptime |   Format-Table  -HideTableHeaders  

And this is what I get:

CONFA7-L1-1A 7/15/2016 9:55:16 AM    CONFA7-L1-1E 7/21/2016 12:58:16 PM    CONFA7-L1-1F 5/31/2016 8:51:46 AM

There are two problems here.

  1. There is no heading. If I remove -HideTableHeaders there will be heading for every output which is not required.

  2. There is a lot of white spaces in between.

Basically I just need to get an output similar to the first one, but without truncating the full names. How can I fix these?

like image 339
screenslaver Avatar asked Jul 24 '16 17:07

screenslaver


People also ask

How do you adjust column width in Word table?

To adjust table row and column size in Word: Click anywhere in the table. In "Table Tools" click the [Layout] tab > locate the "Cell Size" group and choose from of the following options: To fit the columns to the text (or page margins if cells are empty), click [AutoFit] > select "AutoFit Contents."

How do you make one column bigger than the other in Word?

On the Page Layout or Layout tab, click Columns. At the bottom of the list, choose More Columns. In the Columns dialog box, adjust the settings under Width and spacing to choose your column width and the spacing between columns. If you want columns of varying widths, deselect the checkbox next to Equal column width.


2 Answers

To summarize and complement the helpful comments made by PetSerAl and Ansgar Wiechers:

tl;dr

Get-CimInstance -ClassName win32_operatingsystem -ComputerName $pclist |   Sort-Object CSName |     Format-Table CSName, LastBootUpTime -AutoSize 

-AutoSize is what ensures that the CSName (computer name) column is as wide as it needs to be to show all values in full (unless these values themselves are too long to fit on a single line, in which case -Wrap must be used - see below).

Get-CimInstance takes an array of computer names, so there's no need for a loop; however, since the target computers are queried in parallel, the order of objects returned will typically not match the input order of computer names - this is rectified with the Sort-Object CSName call.

To control the width of individual columns:

# Instead of a simple property name, 'prop1', pass a *hashtable* # (@{ ... }`) with a 'width' entry to Format-Table PS> [pscustomobject] @{ prop1='1234567890'; prop2='other' } |        Format-Table -Property @{ e='prop1'; width = 5 }, prop2  prop1 prop2 ----- ----- 1234… other 

Note: In Windows PowerShell, you'll see just 12... as the truncated value, because it uses 3 individual . characters to represent the truncation; in PowerShell [Core] 6+ this was improved to using a single character, (HORIZONTAL ELLIPSIS, U+2026).

Read on to learn more about table formatting.


At its core, your question is about how to control the output column width of tabular output, which applies to any cmdlet's output.

Use the Format-Table cmdlet (directly) for tabular output, not Select-Object: the purpose of Select-Object is to create custom objects, not to format output; if such objects (generally, instances of any type without predefined formatting views) happen to haven 4 or fewer properties, they are by default formatted with Format-Table behind the scenes (but you don't get to apply options); otherwise, it is Format-List that is implicitly used. Thanks, PetSerAl.

  • Format-Table invariably limits output lines to the available screen width, which means:

    • Columns may not get printed at all.
    • Especially the last column that is printed may have its values truncated, with the missing part indicated by ... / - though note that all printed columns can have truncated values, as explained below.
  • If you want to create longer lines, pipe Format-Table's output to | Out-File -Width <int> or | Out-String -Stream -Width <int>; note that if you print the latter to the screen, lines will wrap (but the extra line breaks won't be part of the data).

    • Caveat: On Windows PowerShell, do NOT use -Width ([int]::MaxValue), because table-formatted data for types with formatting data is unconditionally right-padded with spaces to the full width, which can consume inordinate amounts of memory / space in the output file and you may even run out of memory. In PowerShell Core, this has been fixed as of at least v6.1.

    • An alternative on Windows (does not work in PowerShell Core on Unix-like platforms) is to use [console]::BufferWidth = <column-count> to widen the screen buffer to allow longer lines that don't wrap, but require horizontal scrolling.
      Additionally, on Windows it only works in the regular console, not in the ISE.

  • To control column widths - which indirectly determines how many columns will fit - use the following parameters:

    • -AutoSize ... tells Format-Table to make columns as wide as necessary to fit all data values, but note that this can result in fewer (less typically: more) columns getting displayed.

    • -Wrap ... makes column values span multiple lines, if needed, to avoid truncation; again, this can apply to all columnsThanks, zett42., not just the last one, namely in case an automatically determined or fixed column width (specified via a width entry, as shown next) happens to be exceeded by specific values.

    • To specify custom column widths, pass a hashtable with a width entry as an argument - a so-called calculated property to Format-Table's -Property parameter; e.g., the following example limits the 1st output column to 5 characters:

        [pscustomobject] @{ prop1='1234567890'; prop2='other' } |     Format-Table -Property @{ e='prop1'; width = 5 }, prop2 
      • If truncation occurs, which is applied to the end of values by default, the truncation indicator ... / invariably takes up the last 3 characters of the truncated value (in Windows PowerShell) / only the last character (in PowerShell [Core] 6+); in the example above, the prop1 value renders as 12... / 1234… for a total of 5 chars.

      • To truncate the start of values instead, you must change the column to be right-aligned, with a alignment = 'right' entry (default is 'left', 'center' is the 3rd option; both of these truncate the end of values).

      • If you want to retain left alignment while still truncating at the start of values, you'll have to use a custom expression in a script block ({ ... }) assigned to the e (expression) entry:

        [pscustomobject] @{ prop1='1234567890'; prop2='other' } |   Format-Table -Property @{        n='prop1'; e={ $_.prop1 -replace '^.+(.{4})$', '…$1'}; width = 5      }, prop2 
      • Note: Specifying at least one custom width means that you must explicitly enumerate all properties to output in the -Property argument, even the ones that don't need custom widths.[1]

  • Caveats, as of PowerShell 7.1:

    • A bug prevents custom widths from taking effect unless the first column (also) has one; additionally, it never takes effect in the last column - see GitHub issue #14676.

    • As zett42 points out and demonstrates in this answer, if the first column is a calculated one that specifies a custom width, the remaining line width is evenly distributed among those remaining columns that do not themselves specify a column width, irrespective of how wide the values in those columns actually are - unless you also pass -AutoSize. This unexpected behavior is discussed in GitHub issue #14677.


[1] As zett42 points out, you can technically bypass this requirement if all columns are to have the same custom width, because passing a property-name string to the e (Expression) hashtable entry is interpreted as a wildcard pattern, so that string '*' matches all property names; e.g.:
[pscustomobject] @{ a=1; b=2 } | Format-Table @{ e='*'; width=10 }

like image 73
mklement0 Avatar answered Oct 12 '22 09:10

mklement0


If you want trim data past a certain length and manually specify column widths, you can pass a Width property for each property attribute.

For example, if you wanted your data to look like this:

Column 1    Column 2      Column 3      Column 4 --------    --------      --------      -------- Data        Lorem ip...   Lorem ip...   Important data 

Here's the basic Format-Table syntax, with a list of explicit properties:

$data | Format-Table -Property Col1, Col2, Col3, Col4 -AutoSize 

Instead of just passing in the property names, we can add some additional metadata to Property:

$a = @{Expression={$_.Col1}; Label="Column 1"; Width=30},       @{Expression={$_.Col2}; Label="Column 2"; Width=30},       @{Expression={$_.Col3}; Label="Column 3"; Width=30},       @{Expression={$_.Col4}; Label="Column 4"; Width=30} $data | Format-Table -Property $a 

Note: I realize this is covered at the bottom of mklement0's more complete answer, but if this is your use case and you're scrolling quickly, I hope this helps highlight this strategy at a high level

like image 29
KyleMit Avatar answered Oct 12 '22 07:10

KyleMit