Тип PSPropertyExpression

Тип Microsoft.PowerShell.Commands.PSPropertyExpression (его акселератор — [pspropertyexpression]) присутствует в PowerShell с самого начала, но в версии 6.1 он стал публичным (public), что делает его доступным и для нас, как авторов скриптов и модулей.

Сам по себе этот тип используется, например, параметром Property командлета Measure-Object.

Get-Process pwsh | Measure-Object -Property CPU -Average
Count             : 3
Average           : 39.8645833333333
Sum               :
Maximum           :
Minimum           :
StandardDeviation :
Property          : CPU

В данном случае, в качестве значения параметра -Property мы указали строчное значение, однако, особенность этого типа данных в том, что кроме строк он может принимать и скриптблоки — scriptblock, и это позволяет нам отбирать для измерений не только уже существующие свойства объектов, но также и результаты их преобразований.

Get-Process pwsh | Measure-Object -Property {$_.Threads.Count} -Sum
Count             : 3
Average           :
Sum               : 71
Maximum           :
Minimum           :
StandardDeviation :
Property          : $_.Threads.Count

В PowerShell 6.2 появился командлет Join-String, также использующий PSPropertyExpression в качестве типа данных для значений параметра -Property.

Get-Service R* | Join-String -Property { $_.DisplayName + "`n" + $_.Description } -Separator "`n`n"
Remote Access Auto Connection Manager
Creates a connection to a remote network whenever a program references a remote DNS or NetBIOS name or address.

Remote Access Connection Manager
Manages dial-up and virtual private network (VPN) connections from this computer to the Internet or other remote networks. If this service is disabled, any services that explicitly depend on it will fail to start.

...

Также этот тип неявным образом используется несколькими командлетами, например — Select-Object.

PSPropertyExpression

Теперь давайте посмотрим, как мы можем использовать тип Microsoft.PowerShell.Commands.PSPropertyExpression.

Однако сначала мы получим объект процесса pwsh, который мы и будем использовать в дальнейших примерах.

$ps = Get-Process pwsh | Select-Object -First 1

Property

Создать объект PSPropertyExpression мы можем следующим образом.

$PathProperty = [pspropertyexpression]::new("Path")

Получить значение указанного свойства (в данном случае — Path) определенного объекта мы можем при помощи метода GetValues объекта PSPropertyExpression.

$PathProperty.GetValues($ps)
Result                                 ResolvedExpression Exception
------                                 ------------------ ---------
C:\Program Files\PowerShell\7\pwsh.exe Path

В качестве результата мы получим объект Microsoft.PowerShell.Commands.PSPropertyExpressionResult, состоящий из следующих свойств: Result, в котором расположено значение интересующего нас свойства, ResolvedExpression, где указано имя этого свойства, а также Exception, содержащее исключение, в случае если таковое произошло при попытке это значение получить.

Если же нас интересует исключительно значение указанного свойства, мы можем запросить свойство Result полученного объекта.

$PathProperty.GetValues($ps).Result
C:\Program Files\PowerShell\7\pwsh.exe

Wildcards

В качестве аргумента при создании нового объекта PSPropertyExpression мы можем использовать и строки с символами подстановки.

$MemorySize = [pspropertyexpression]::new("*MemorySize64")

Свойство HasWildCardCharacters объекта PSPropertyExpression теперь будет содержать значение True.

$MemorySize.HasWildCardCharacters
True

Теперь, как и в предыдущем примере, вызовем метод GetValues.

$MemorySize.GetValues($ps)
       Result ResolvedExpression         Exception
       ------ ------------------         ---------
        66896 NonpagedSystemMemorySize64
     61038592 PagedMemorySize64
       381112 PagedSystemMemorySize64
     61190144 PeakPagedMemorySize64
2204026884096 PeakVirtualMemorySize64
     61038592 PrivateMemorySize64
2204008886272 VirtualMemorySize64

При создании объекта PSPropertyExpression с использованием строки мы можем указать второй параметр типа bool. Установка его в True укажет конструктору, что первый аргумент указан в его окончательном виде и дальнейшие попытки раскрыть встречающиеся в нем символы подстановки производить не нужно. Это может пригодиться, например, если ваши объекты содержат такие символы в именах свойств.

$WildcardProperty = [pspropertyexpression]::new("Property*Name?", $true)

Parameter Sets

Еще одной особенностью типа PSPropertyExpression является то, что он позволяет нам указывать наборы свойств — Property Set.

Например, объект процесса обладает двумя наборами свойств — PSConfiguration и PSResources.

Get-Process | Get-Member -MemberType PropertySet | Select-Object -Property Name
Name
----
PSConfiguration
PSResources

Первый из них — PSConfiguration, к примеру, содержит следующие свойства.

$ps.PSConfiguration.ReferencedPropertyNames
Name
Id
PriorityClass
FileVersion

Давайте создадим объект PSPropertyExpression на основе этого набора свойств.

$PSConfiguration = [pspropertyexpression]::new("PSConfiguration")

Теперь, если мы вызовем метод GetValues, то в качестве результата получим четыре объекта PSPropertyExpressionResult, каждый из которых соответствует одному из свойств набора PSConfiguration.

$PSConfiguration.GetValues($ps)
Result  ResolvedExpression Exception
------  ------------------ ---------
pwsh    Name
12752   Id
Normal  PriorityClass
7.0.1.0 FileVersion

Метод GetValues обладает и второй перегрузкой (overload), которая позволяет нам указать три параметра: первый — target, как и в предыдущих примерах, это объект, значения свойств которого мы получаем, второй параметр — expand, при установке которого в $false, мы можем предотвратить раскрытие набора свойств на составляющие его отдельные свойства, и третий — eatExceptions, установка которого в $false приведет к тому, что любое возникшее при получении значений свойств исключение (exception) приведет к прекращению выполнения метода GetValues. По умолчанию же исключения видны только в свойстве Exception объекта PSPropertyExpressionResult.

$PSConfiguration.GetValues($ps, $false, $false)

Понятно, что в данном случае никакого результата не будет.

Интересно, что на основе объекта PSPropertyExpression для набора свойств, мы можем получить объекты PSPropertyExpression для каждого входящего в набор свойства. Сделать это можно при помощи метода ResolveNames.

$PSConfiguration.ResolveNames($ps)
Script HasWildCardCharacters
------ ---------------------
                       False
                       False
                       False
                       False

И хотя в обычном их виде мы не можем сказать, какой из них которому свойству соответствует, однако узнать это мы можем при помощи метода ToString.

$PSConfiguration.ResolveNames($ps) | ForEach-Object ToString
Name
Id
PriorityClass
FileVersion

Кроме того, метод ResolveNames обладает и второй перегрузкой, позволяющей указать параметр expand, установка которого в $false, так же, как и в методе GetValues, ведет к предотвращению раскрытия набора свойств на его составляющие свойства.

$PSConfiguration.ResolveNames($ps, $false)

ScriptBlock

Как мы уже говорили, кроме строчных значений объект PSPropertyExpression поддерживает и скриптблоки, что открывает перед нами еще большее число возможностей по получению и преобразованию значений различных свойств.

$WorkingSet = [pspropertyexpression]::new({$_.WorkingSet64 / 1mb})
$WorkingSet.GetValues($ps)
     Result ResolvedExpression    Exception
     ------ ------------------    ---------
98.66015625 $_.WorkingSet64 / 1mb
$WorkingSet.GetValues($ps).Result
98.66015625

Result

Что же нам дает объект PSPropertyExpression?

Действительно, в случае с указанием определенного свойства

[pspropertyexpression]::new("Path").GetValues($ps)

мы можем получить его значение и напрямую.

$ps.Path

Однако когда мы указываем строку, содержащую символы подстановки, набор свойств или же скриптблок, то в этих случаях объект PSPropertyExpression позволяет нам получить значения нужных свойств без необходимости использования командлетов ForEach-Object или Select-Object.

То есть вместо команд

$ps | Select-Object -Property *MemorySize64
$ps | ForEach-Object -Process {$_.WorkingSet64 / 1mb}

мы можем использовать уже упоминавшиеся выше

[pspropertyexpression]::new("*MemorySize64").GetValues($ps)
[pspropertyexpression]::new({$_.WorkingSet64 / 1mb}).GetValues($ps)

и тем самым несколько сократить количество задействованных ресурсов, а также время, требуемое на выполнение команд.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s