Добавить объект where в табличную конструкцию?

Переименование заголовков с помощью "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" больше 10, указанное в операторе WHERE, но возвращается с результатами. Почему это??

1 ответ

Lee_Dailey предоставил ключевой указатель в комментарии:

  • Для преобразования данных для дальнейшей программной обработки используйте Select-Object или другие методы преобразования данных, например, через ForEach-Object,

  • Только когда-либо использовать Format-* Командлеты для форматирования данных для отображения, как следует из их названия.

    • Большой эволюционный скачок PowerShell заключался в отправке объектов, а не текста через конвейер, и в то же время Format-* командлеты, такие как Format-Table слишком испуская объекты, эти объекты больше не представляют данные, но инструкции по форматированию для системы форматирования вывода PowerShell - они не служат никакой другой цели.

Поэтому просто заменив 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}

Однако общим для этих двух командлетов является способность принимать рассчитанные свойства на основе хеш-таблиц (@{ label = '...'; expression = { ... } }), как и в вашем вопросе.


Что касается того, что на самом деле произошло в вашей попытке:

Вот упрощенный пример, используя Format-Table:

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

SpaceLeft
---------
       10

Это выглядит просто отлично - и это действительно цель - создать хорошее представление дисплея.

На самом деле, подставляя Select-Object за Format-Table Результаты на том же дисплее:

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

SpaceLeft
---------
       10

Причина в том, что когда вывод команды идет на дисплей, PowerShell неявно, за кулисами вызывает соответствующий Format-* командлет, который в этом случае Format-Table, Другими словами, приведенная выше команда эквивалентна следующей команде:

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

SpaceLeft
---------
       10

Для логики, что за 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 рассказывает другую историю:

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

Неважно, что конкретно представляют эти частично неизвестные свойства - все, что имеет значение, это:

  • Их единственная цель - интерпретировать систему форматирования вывода PowerShell.

  • Выбранные / рассчитанные свойства передаются Format-Table отсутствуют как таковые в выводе.

    • Вот почему ваш Where-Object звонок не работал как задумано: $_.SpaceLeft ссылается на несуществующее свойство, поэтому выражение оценивается как $null, а также $null -lt 10 всегда $true,

Независимо от их вклада, Format-* командлеты выводят экземпляры Microsoft.PowerShell.Commands.Internal.Format.* типы, которые представляют инструкции форматирования.

Другие вопросы по тегам