Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
PSCustomObject
— это отличный инструмент, который стоит добавить в ваш инструментарий PowerShell. Начнем с основных принципов и работаем над более сложными функциями. Идея использования PSCustomObject
— простой способ создания структурированных данных. Посмотрите на первый пример, и вы получите лучшее представление о том, что это означает.
Примечание.
Оригинальная версия этой статьи появилась в блоге, написанном @KevinMarquette. Команда PowerShell благодарит Кевина за предоставление этого содержимого нам. Пожалуйста, ознакомьтесь с его блогом на PowerShellExplained.com.
Создание PSCustomObject
Я люблю использовать [pscustomobject]
в PowerShell. Создание удобного объекта никогда не было проще.
Из-за этого я собираюсь пропустить все другие способы создания объекта, но мне нужно упомянуть, что большинство из этих примеров — PowerShell версии 3.0 и более новые.
$myObject = [pscustomobject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Этот метод хорошо подходит для меня, потому что я использую хеш-таблицы почти для всего. Но есть случаи, когда мне хотелось бы, чтобы PowerShell обрабатывал хэш-таблицы больше как объекты. Первое, на что вы обращаете внимание, это когда вы хотите использовать Format-Table
или Export-Csv
и понимаете, что хэш-таблица — это просто коллекция пар "ключ-значение".
Затем можно получить доступ к значениям и использовать их так же, как обычный объект.
$myObject.Name
Преобразование хеш-таблицы
Кстати, знали ли вы, что вы можете сделать это:
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = [pscustomobject]$myHashtable
Я предпочитаю создавать объект с самого начала, но бывают случаи, когда необходимо сначала работать с хеш-таблицей. Этот пример работает, так как конструктор принимает хэш-файл для свойств объекта. Важно отметить, что в то время как этот метод работает, он не является точным эквивалентом. Самое большое различие заключается в том, что порядок свойств не сохраняется.
Если вы хотите сохранить порядок, см. упорядоченные хэш-таблицы.
Устаревший подход
Возможно, вы могли видеть, как люди используют New-Object
для создания пользовательских объектов.
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = New-Object -TypeName psobject -Property $myHashtable
Это довольно медленнее, но это может быть ваш лучший вариант в ранних версиях PowerShell.
Сохранение в файл
Я считаю, что лучший способ сохранить хэш-таблицу в файл — это сохранить её в формате JSON. Его можно импортировать обратно в [pscustomobject]
$myObject | ConvertTo-Json -Depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json
Я охватываю больше способов сохранения объектов в файл в моей статье по Многие способы чтения и записи в файлы.
Работа со свойствами
Добавление свойств
Вы по-прежнему можете добавить новые свойства в PSCustomObject
с помощью Add-Member
.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'
$myObject.ID
Удалить свойства
Вы также можете удалить свойства из объекта.
$myObject.psobject.Properties.Remove('ID')
.psobject
— это встроенный элемент, который предоставляет доступ к метаданным базового объекта. Дополнительные сведения о встроенных элементах см. в about_Intrinsic_Members.
Перечисление имен свойств
Иногда вам нужен список всех имен свойств объекта.
$myObject | Get-Member -MemberType NoteProperty | select -ExpandProperty Name
Мы также можем получить этот же список из свойства psobject
.
$myobject.psobject.Properties.Name
Примечание.
Get-Member
возвращает свойства в алфавитном порядке. С помощью оператора доступа к члену для перечисления имен свойств возвращаются свойства в том порядке, в котором они определены на объекте.
Динамический доступ к свойствам
Я уже упомянул, что вы можете напрямую получить доступ к значениям свойств.
$myObject.Name
Можно использовать строку для имени свойства, и она по-прежнему будет работать.
$myObject.'Name'
Мы можем выполнить этот еще один шаг и использовать переменную для имени свойства.
$property = 'Name'
$myObject.$property
Я знаю, что выглядит странно, но это работает.
Преобразование PSCustomObject в хеш-таблицу
Чтобы продолжить с последним разделом, вы можете динамически перебирать свойства и создавать хеш-таблицу из них.
$hashtable = @{}
foreach( $property in $myobject.psobject.Properties.Name )
{
$hashtable[$property] = $myObject.$property
}
Тестирование свойств
Если необходимо знать, существует ли свойство, можно просто проверить наличие этого свойства.
if( $null -ne $myObject.ID )
Но если значение может быть $null
вы можете проверить, существует ли оно, проверив psobject.Properties
для него.
if( $myobject.psobject.Properties.Match('ID').Count )
Добавление методов объекта
Если необходимо добавить метод скрипта в объект, его можно сделать с помощью Add-Member
и ScriptBlock
. Вам нужно использовать автоматическую переменную this
для ссылки на текущий объект. Вот scriptblock
, чтобы превратить объект в хеш-таблицу. (тот же код формирует последний пример)
$ScriptBlock = {
$hashtable = @{}
foreach( $property in $this.psobject.Properties.Name )
{
$hashtable[$property] = $this.$property
}
return $hashtable
}
Затем мы добавим его в объект в качестве свойства скрипта.
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
}
Add-Member @memberParam
Затем мы можем вызвать эту функцию следующим образом:
$myObject.ToHashtable()
Объекты и типы значений
Объекты и типы значений не обрабатывают назначения переменных так же. При назначении типов значений друг другу только значение копируется в новую переменную.
$first = 1
$second = $first
$second = 2
В этом случае $first
равно 1, а $second
— 2.
Переменные объекта содержат ссылку на фактический объект. При назначении одного объекта новой переменной они по-прежнему ссылаются на тот же объект.
$third = [pscustomobject]@{Key=3}
$fourth = $third
$fourth.Key = 4
Так как $third
и $fourth
ссылаются на один и тот же экземпляр объекта, $third.key
и $fourth.Key
равны 4.
psobject. Copy()
Если вам нужна истинная копия объекта, ее можно клонировать.
$third = [pscustomobject]@{Key=3}
$fourth = $third.psobject.Copy()
$fourth.Key = 4
Клон создает неглубокую копию объекта. В этом примере они имеют разные экземпляры, а $third.key
— 3, а $fourth.Key
— 4.
Я называю это неглубокой копией, так как если у вас есть вложенные объекты (объекты со свойствами содержат другие объекты), копируются только значения верхнего уровня. Дочерние объекты будут ссылаться друг на друга.
PSTypeName для пользовательских типов объектов
Теперь, когда у нас есть объект, есть несколько других вещей, которые мы можем сделать с ним, что может быть не так очевидно. Первое, что нам нужно сделать, это дать ему PSTypeName
. Вот как это чаще всего делают люди, по моим наблюдениям:
$myObject.psobject.TypeNames.Insert(0,"My.Object")
Недавно я обнаружил еще один способ сделать это от пользователя Reddit u/markekraus
. Он говорит об этом подходе, который позволяет определить его непосредственно.
$myObject = [pscustomobject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Я люблю, как хорошо это просто вписывается в язык. Теперь, когда у нас есть объект с правильным именем типа, мы можем сделать еще несколько действий.
Примечание.
Вы также можете создавать пользовательские типы PowerShell с помощью классов PowerShell. Дополнительные сведения см. в обзоре класса PowerShell.
Использование DefaultPropertySet (длинный путь)
PowerShell решает, какие свойства будут отображаться по умолчанию. Многие встроенные команды имеют файл форматирования .ps1xml
, который выполняет всю основную работу. Из этой публикации Boe Proxесть еще один способ сделать это на нашем пользовательском объекте с помощью Просто PowerShell. Мы можем дать ему MemberSet
для его использования.
$defaultDisplaySet = 'Name','Language'
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet)
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
$MyObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers
Теперь, когда объект просто попадает в оболочку, он будет отображать только эти свойства по умолчанию.
Update-TypeData с набором свойств по умолчанию
Это хорошо, но недавно я видел лучший способ использовать Update-TypeData, чтобы указать свойства по умолчанию.
$TypeData = @{
TypeName = 'My.Object'
DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData
Это достаточно просто, что я мог бы почти вспомнить это, если бы у меня не было этого поста в качестве краткой ссылки. Теперь я могу легко создать объекты с большим количеством свойств и сделать их внешний вид аккуратным и чистым при просмотре из оболочки. Если мне нужно получить доступ к другим свойствам или увидеть их, они все ещё доступны.
$myObject | Format-List *
Update-TypeData с ScriptProperty
Из этого видео я узнал о создании свойств скрипта для ваших объектов. Это было бы хорошим временем, чтобы отметить, что это работает для существующих объектов тоже.
$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.ToUpper()}
}
Update-TypeData @TypeData
Это можно сделать до создания или после создания объекта, и он по-прежнему будет работать. Это то, что делает его отличным от использования Add-Member
со свойством скрипта. При использовании Add-Member
так, как я ссылался ранее, он существует только в этом конкретном экземпляре объекта. Это относится ко всем объектам с этим TypeName
.
Параметры функции
Теперь эти настраиваемые типы можно использовать для параметров в функциях и сценариях. Вы можете использовать одну функцию для создания этих пользовательских объектов, а затем передать их в другие функции.
param( [PSTypeName('My.Object')]$Data )
PowerShell требует, чтобы объект был заданным типом. При несоответствии типа автоматически возникает ошибка проверки, чтобы избавить вас от необходимости тестировать его в коде. Отличный пример того, как PowerShell позволяет выполнять свои задачи наилучшим образом.
Выходной тип функции
Вы также можете определить OutputType
для расширенных функций.
function Get-MyObject
{
[OutputType('My.Object')]
[CmdletBinding()]
param
(
...
Значение атрибута OutputType является только примечанием к документации. Он не вычисляется из кода функции и не сравнивается с фактическими выходными данными функции.
Основная причина использования типа вывода заключается в том, что метаданные о функции отражают ваши намерения. Такие вещи, как Get-Command
и Get-Help
, которыми может воспользоваться ваша среда разработки. Если вы хотите получить дополнительные сведения, просмотрите справочную информацию: about_Functions_OutputTypeAttribute.
При этом, если вы используете Pester для модульного тестирования функций, рекомендуется удостовериться, что выходные объекты соответствуют вашему OutputType. Это может перехватывать переменные, которые просто падают в поток, когда этого не должно происходить.
Выводы
Контекстом этого было все [pscustomobject]
, но большая часть этой информации относится к объектам в целом.
Я видел большинство из этих особенностей мельком раньше, но никогда не видел их представленными как коллекцию информации о PSCustomObject
. Только на этой прошлой неделе я наткнулся на другую и был удивлен, что я не видел его раньше. Я хотел вытащить все эти идеи вместе, чтобы вы могли, надеюсь, увидеть большую картину и помнить о них, когда у вас есть возможность использовать их. Надеюсь, вы узнали что-то и сможете найти способ работать с этим в ваших сценариях.
PowerShell