使用Format-Table控制列宽

30
我试图从列表中获取一些电脑的最后重启时间。当我使用以下代码时:
foreach ($pc in $pclist) {
  Get-CimInstance -ClassName win32_operatingsystem -ComputerName $pc |
    select csname, lastbootuptime 
}

输出如下:

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

这很整洁,但如果计算机名称很长,我无法看到完整的名称。因此我使用管道符号Format-Table:

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

这是我得到的结果:

CONFA7-L1-1A 2016年7月15日 上午9:55:16
CONFA7-L1-1E 2016年7月21日 下午12:58:16
CONFA7-L1-1F 2016年5月31日 上午8:51:46

这里有两个问题。

  1. 没有标题。如果我删除 -HideTableHeaders 每个输出都会有标题,这不是必要的。

  2. 之间有很多空格。

基本上,我只需要一个类似第一个输出的输出,但不截断完整名称。我该如何解决这些问题?


4
请执行以下命令以获取远程计算机上操作系统的名称和最后引导时间:Get-CimInstance -ClassName win32_operatingsystem -ComputerName $pclist | Format-Table csname, lastbootuptime -AutoSize - user4003407
4
“-AutoSize” 是关键。 - Ansgar Wiechers
Get-CimInstance -ClassName win32_operatingsystem -ComputerName $pclist | Sort-Object csname -Ascending | Format-Table csname, lastbootuptime -AutoSize。我这样做对吗?因为我收到了以下错误信息:Sort-Object: 找不到与参数名 'Ascending' 匹配的参数。 - screenslaver
1
我的错。Sort-Object 只有一个 -Descending 参数。默认是升序排列,所以只需省略此参数即可。 - Ansgar Wiechers
3
由于Get-CimInstance已经支持一次检查多台计算机,而且它是并行执行的,因此您不需要将此命令放入循环中。这样会导致结果失去顺序。 - user4003407
显示剩余3条评论
2个回答

63

我将总结并补充PetSerAlAnsgar Wiechers的有用评论:

太长没看(tl;dr):

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

-AutoSize 确保 CSName(计算机名称)列的宽度足以显示所有值(除非这些值本身太长而无法放在单行上,此时必须使用 -Wrap - 参见下文)。

Get-CimInstance 接受一个计算机名称的 数组,因此不需要循环;但是,由于目标计算机是 并行查询 的,返回的对象顺序通常不会与计算机名称的输入顺序匹配 - 这可以通过调用 Sort-Object CSName 来纠正。

控制各个列的宽度

# 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

注意:在Windows PowerShell中,您将只看到被截断的值12...,因为它使用3个单独的.字符来表示截断; 在PowerShell [Core] 6+中改进为使用一个单一字符(水平省略号,U+2026)。
阅读以下内容以了解更多有关表格式化的信息。
在本质上,您的问题是关于如何控制制表符输出的输出列宽度,这适用于任何cmdlet的输出。
对于制表符输出,请直接使用Format-Table cmdlet(而不是Select-Object):Select-Object的目的是创建自定义对象,而不是格式化输出;如果这样的对象(通常是没有预定义格式视图的任何类型的实例)恰好具有4个或更少的属性,则默认情况下会使用Format-Table进行格式化(但您无法应用选项);否则,隐式使用的是Format-List。感谢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] 如zett42所指出,如果所有列都有相同的自定义宽度,则您可以在技术上绕过此要求,因为将属性名称字符串传递给e (Expression) 哈希表条目会被解释为通配符模式,因此字符串'*'匹配所有属性名称; 例如:
[pscustomobject] @{ a=1; b=2 } | Format-Table @{ e='*'; width=10 }


@zett42,说得好,但考虑到您最近的发现,您现在可能已经有资格成为专家了;是的,我可以看出均匀分布可能很有用,但正如您所暗示的那样,它应该是“选择加入”的。 - mklement0
1
@zett42,我已经提交了两个问题,并更新了答案以链接到它们。 - mklement0

19

如果您想要截取特定长度的数据并手动指定列宽,您可以为每个属性属性传递一个Width属性。

例如,如果您希望您的数据看起来像这样:

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

以下是基本的 Format-Table 语法,附有显式属性列表:

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

我们可以为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

注意:我意识到这在 mklement0 更完整的答案底部已经涵盖了,但如果这是你的用例并且你正在快速滚动,请希望这有助于在高层次上突出显示此策略。


2
我将一台机器升级到了PowerShell 5.1,突然间我的电子邮件报告中的列没有对齐。在哈希表中添加Width=x参数可以重新对齐所有内容。 - user208145
4
考虑到问题的标题,使这些信息更易发现是非常合理的。我已经将这种技巧添加到了我的答案顶部,但是你的回答依然提供了额外的内容:它展示了如何使用计算出的属性哈希表来对输出列进行重命名。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接