Как фильтровать вывод с Powershell Select-Object


15 ноября 2019


Фильтрация в Powershell с Select-Object на примерах

Команда Powershell Select-Object фильтрует вывод информации. Когда Where-Object выступает в качестве условий, через который проходит объект, Select-Object используется для фильтрации колонок и строк. Эта команда так же позволяет выводить дополнительные свойства, так как по умолчанию команды Powershell выводят не все свойства.

Описание и синтаксис

Если вы посмотрите свойства, который хранит объект, то увидите что их намного больше чем выводится по умолчанию:

Get-Service | Get-Member -MemberType *Property*

Получение свойств в Powershell

Для вывода всех свойств понадобится использовать Select-Object:

Get-Service -Name WinRM
Get-Service -Name WinRM | Select-Object -Property *

Пример с Powershell Select-Object

Знак '*' говорит, что нам нужно вывести все свойства. Вы так же можете заметить, что вывод в виде строки, а не таблицы. В некоторых случаях Powershell сам меняет формат отображения на список. Если нам нужна таблица добавьте Format-Table, но такой формат может быть сложно читаем:

Get-Service -Name WinRM | Select-Object -Property * | Format-Table

Пример с форматированием Powershell Select-Object

Что бы сделать вывод более читаемым можно указать только определенные колонки:

Get-Service -Name WinRM | Select-Object Name, RequiredServices | Format-Table

Пример с форматированием Powershell Select-Object

Параметр Property первый принимает значения и поэтому его не обязательно указывать.

Когда нужно вывести все колонки, кроме определенных можно использовать параметр ExcludeProperty:

Get-Service -Name WinRM | Select-Object * -ExcludeProperty ServiceName,Status,Name| ft

Пример с ExcludeProperty Powershell Select-Object

Алиасы

Эта команда имеет один алиас в виде Select:

Get-Process | Select Name, Path

Пример с алиасом Powershell Select

Выражения и скрипты

Нам не обязательно указывать существующие свойства, можно использовать выражения. Один из самых очевидных примеров это то, что мы можем добавлять колонки с новыми значениями. Ниже пример где мы выводим еще одну колонку изменив число:

$num = @(1,2,3,4)
$num | select-object -Property {$PSItem+1}

Пример с выражением Expression Powershell Select-Object

$PSItem это значение, которое проходит через конвейер. Вы можете знать второй способ написания в виде "$_".

Колонка имеет имя по умолчанию, что бы изменить это разделим выражение на Label, где укажем имя и выражение Expression:

$num | select-object -Property @{Label="Значение + 1"; Expression={$PSItem+1}}

Expression Powershell Select-Object

По сути мы имеем формат hashtable. Более наглядные примеры мы можем увидеть, когда нам нужно перевести один тип значений в другой.

Когда мы выполняем команду Get-Volume мы получаем список разделов, общее и свободное пространство. Добавим колонку, которая будет показывать процент свободного пространства:

Get-Volume | select -Property DriveLetter, @{Label='Free'; Expression = {[string]([int]($_.SizeRemaining/$_.Size*100)) + " %"}}

Пример с Expression Powershell Select-Object

Выше уже упоминалось, что этот тип похож на hashtable. Мы можем вывести выражение в отдельную строку и просто вставить его в select:

$free = @{Label='Free'; Expression = {[string]([int]($_.SizeRemaining/$_.Size*100)) + " %"}}
Get-Volume | select -Property DriveLetter, $free

Пример с Expression Powershell Select-Object

Такой же пример можно использовать и с процессами, где значения отображаются в Кб. На примере ниже я конвертирую в Мб:

Get-Process | Select-Object -Property Name, @{Label='WS(MB)'; Expression={$PSItem.WS/1Mb}}

Пример с Expression Powershell Select-Object добавление колонки

Если вам нужны значения в GB или другом размере просто замените их в выражении. Если нужно округлить, можно использовать [int] так же как я это делал в предыдущем примере.

InputObject

Так же как и любые другие командлеты работающие через конвейер этот тоже имеет параметр InputObject. С помощью его мы можем использовать командлет без конвейера:

$data = Get-Host
Select-Object -Property Name -InputObject $data

Пример с Powershell Select-Object InputObject

Такое написание аналогично этому:

$data = Get-Host
$data | Select-Object -Property Name

ExpandProperty

Для примера рассмотрим ситуацию, где элемент хранит несколько значений. Это будет выглядеть так:

$hash = [pscustomobject]@{Type='array'; collection=@(1,2,3,4,5)}
$hash | Select-Object -Property $PSItem

Пример с Powershell Select-Object hashtable

Если мы хотим вывести все значения хранящиеся в Collection это нужно делать через метод ExpandProperty:

$hash = [pscustomobject]@{Type='array'; collection=@(1,2,3,4,5)}
$hash | Select-Object -Property Type -ExpandProperty collection

Пример с Powershell Select-Object pscutomobject

Дополнительные параметры

У нас есть два параметра, с помощью которых мы можем получать первые и последние элемент из объекта. Это параметры:

  • First - получение элементов с начала;
  • Last - получение элементов с конца.

Я не могу придумать пример без использования сортировки Powershell Sort-Object, поэтому пример ниже с ним. Мы возвращаем процесс, который имеет наибольшее значение PM:

Get-Process | Sort-Object WS -Descending | Select-Object -First 1

Пример с Powershell Select-Object First

Есть возможность использовать индексы указав Index. В предыдущем примере мы получили первый элемент с использованием First, аналогичный пример с индексами:

Get-Process | Sort-Object WS -Descending | Select-Object -Index 0

Пример с Powershell Select-Object Index

 

Использование с условиями

Условия не совсем подходят для использования с Select, но это можно делать. Например у нас есть команда Get-NetTCPConnection, которая получает список сетевых сеансов с отображением портов и идентификаторов процессов:

Get-NetTCPConnection

Get-NetTCPConnection

С помощью условий заменим колонку RemotePort на имена протоколов:


$prot = @{Label='LocalPortName'; Expression={
    if ($PSItem.LocalPort -eq 443){'HTTPS'}
    elseif ($PSItem.LocalPort -eq 80){'HTTP'}
    elseif ($PSItem.LocalPort -eq 22){'SSH'}
    elseif ($PSItem.LocalPort -eq 53){'DNS'}
    elseif ($PSItem.LocalPort -eq 389){'LDAP'}
    elseif ($PSItem.LocalPort -eq 135){'LOC-SRV'}
    }
}
Get-NetTCPConnection | Select-Object -Property LocalAddress,OwningProcess,LocalPort,$prot,RemotePort | Sort-Object -Descending LocalPortName | ft

Пример условий с Powershell Select-Object

Обратите внимание, что сортировка применяется после создания колонки, а не до (как это было показано в другом примере).

Логично было бы использовать условия в виде switch в Powershell. Аналогичный пример, но со switch:


$prot = @{Label='LocalPortName'; Expression={
    switch($PSItem.LocalPort){
        443 {'HTTPS'}
        80 {'HTTP'}
        22 {'SSH'}
        53 {'DNS'}
        389 {'LDAP'}
        135 {'LOC-SRV'}
        }
    }
}

Get-NetTCPConnection | Select-Object -Property LocalAddress,OwningProcess,LocalPort,$prot,RemotePort | Sort-Object -Descending LocalPortName | ft

Пример условий switch с Powershell Select-Object

 

Работа с Where-Object

Как уже говорилось в начале статьи, where чаще применяется в качестве условий, а select фильтрует колонки, и может изменять значения. В какой последовательности использовать обе команды - зависит от разных случаев. Если мы еще точно не знаем какие колонки нам нужно вывести лучше использовать where первым:

Get-Package | where -Property Name -Like "*C++*" | select Version

Пример where с Powershell Select-Object

Если бы мы изменили порядок, то у нас бы ничего не отобразилось:

Get-Package | select Version |where -Property Name -Like "*C++*"

Это связано с тем, что мы выполняем where для колонки, которой не существует (в select выбран только Version). Другие примеры вы можете посмотреть в статье Фильтрация через Where-Object в Powershell с примерами.

...

Теги: #powershell


Популярные тэги
О блоге
Этот блог представляет собой конспекты выученного материала, преобретенного опыта и лучшие практики в системном администрировании и программировании.