在表构造上添加一个where对象?

时间:2019-03-15 01:14:06

标签: powershell

用'label'重命名标题,我想过滤最后一个'SpaceLeft'。但是它不能正常工作。例如:

Get-WmiObject win32_logicaldisk -ComputerName sfuslt167 -Filter "drivetype=3" |
  Format-Table -Property deviceID,
    @{label='freespace(GB)';expression={$_.freespace / 1GB -as [int]}},
    @{label='Size(GB)';expression={$_.size / 1GB -as [int]}}, 
    @{label='SpaceLeft';expression={$_.freespace / $_.size * 100}} |
      Where-Object {$_.SpaceLeft -lt 10}

结果:

deviceID freespace(GB) Size(GB)        SpaceLeft
-------- ------------- --------        ---------
C:                 130      237 54.8893461475826

这应该什么都不会返回,因为'SpaceLeft'中的值大于WHERE语句中指定的10,但是返回结果。为什么会这样?

1 个答案:

答案 0 :(得分:1)

Lee Dailey在评论中提供了关键指针:

  • 转换数据以进行进一步的编程处理,请使用Select-Object 或其他数据转换方法,例如通过ForEach-Object

  • 仅使用Format-* cmdlet来按其名称所示,格式化数据以显示 。 >

    • PowerShell的巨大发展飞跃是通过管道发送对象而不是 text ,并且Format-Table之类的Format-* cmdlet也会发出对象,这些对象不再表示数据,而是表示PowerShell's output-formatting system格式化说明-它们没有其他用途。

因此,只需将Format-Table替换为Select-Object就可以解决您的问题:

Get-WmiObject win32_logicaldisk -ComputerName sfuslt167 -Filter "drivetype=3" |
  Select-Object -Property deviceID,
    @{label='freespace(GB)';expression={$_.freespace / 1GB -as [int]}},
    @{label='Size(GB)';expression={$_.size / 1GB -as [int]}}, 
    @{label='SpaceLeft';expression={$_.freespace / $_.size * 100}} |
      Where-Object {$_.SpaceLeft -lt 10}

这两个cmdlet的共同点在于,可以接受基于哈希表的calculated properties@{ label = '...'; expression = { ... } }),就像您的问题一样。


关于您尝试中的实际发生的情况

这是一个简化的示例,使用Format-Table

PS> [pscustomobject] @{ freespace = 100; size = 1000 } |
      Format-Table @{label='SpaceLeft'; expression={$_.freespace / $_.size * 100}}

SpaceLeft
---------
       10

这个看起来很好-的确是这样做的目的-产生一个很好的 display 表示形式。

实际上,用Select-Object代替Format-Table会得到相同的显示

PS> [pscustomobject] @{ freespace = 100; size = 1000 } |
      Select-Object @{ label='SpaceLeft'; expression={$_.freespace / $_.size * 100} }

SpaceLeft
---------
       10

原因是当命令输出转到 display 时, PowerShell 隐式地在幕后调用适当的 {{ 1}} cmdlet ,在这种情况下为Format-*。 换句话说,上面的命令等效于以下命令:

Format-Table

有关在何时选择PS> [pscustomobject] @{ freespace = 100; size = 1000 } | Select-Object @{label='SpaceLeft'; expression={$_.freespace / $_.size * 100}} | Format-Table SpaceLeft --------- 10 cmdlet的后面的逻辑,请参阅this answer

但是,您可以选择(格式化)cmdlet,例如Format-*,而不是(隐式地)应用Format-Table,以列表样式显示在每个行上的每个属性:

Format-List

但是,在进行进一步处理时, 不是PS> [pscustomobject] @{ freespace = 100; size = 1000 } | Select-Object @{label='SpaceLeft'; expression={$_.freespace / $_.size * 100}} | Format-List SpaceLeft : 10 Select-Object创建的,因此仅Format-Table是合适的:

首先使用Select-Object,首先使用Get-Member -Type Properties,看看输出对象具有哪些属性:

Select-Object

正如预期的那样,输出具有一个名为PS> ([pscustomobject] @{ freespace = 100; size = 1000 } | Select-Object @{label='SpaceLeft'; expression={$_.freespace / $_.size * 100}} | Get-Member -Type Properties).Name SpaceLeft 的属性,这就是您的SpaceLeft调用可以对其进行操作的地方。

使用Where-Object而不是Format-Table讲述了一个不同的故事:

Select-Object

这些部分隐晦地命名的属性具体代表什么并不重要-重要的是:

  • 它们的唯一目的是由PowerShell的输出格式系统解释。

  • 传递给PS> ([pscustomobject] @{ freespace = 100; size = 1000 } | Format-Table @{label='SpaceLeft'; expression={$_.freespace / $_.size * 100}} | Get-Member -Type Properties).Name autosizeInfo ClassId2e4f51ef21dd47e99d3c952918aff9cd groupingEntry pageFooterEntry pageHeaderEntry shapeInfo ClassId2e4f51ef21dd47e99d3c952918aff9cd groupingEntry shapeInfo ClassId2e4f51ef21dd47e99d3c952918aff9cd formatEntryInfo outOfBand writeStream ClassId2e4f51ef21dd47e99d3c952918aff9cd groupingEntry ClassId2e4f51ef21dd47e99d3c952918aff9cd groupingEntry 的选定属性/计算属性在输出中不存在

    • 这就是为什么您的Format-Table调用无法按预期进行的原因:Where-Object引用了一个不存在的属性,因此该表达式的值为$_.SpaceLeft,而$null为< em>总是 $null -lt 10

$true cmdlet输出Microsoft.PowerShell.Commands.Internal.Format.*类型的实例,它们代表格式化指令