Как работать с PSCustomObject в Powershell


24 октября 2019


Работа с типом Powershell PSCustomObject на примерах

Тип Powershell PSCustomObject - это еще один способ хранить структурированные данные наряду с массивами. Выбор в строну PSCustomObject более верен, когда нам нужно хранить не набор элементов, а объект. Кроме того этот объект будет быстрее работать.

Создание

Для создания объекта можно использовать два подхода. Первый работает с версии PS 3.0:

$object = [PSCustomObject]@{
    Name     = 'Alex'
    Language = 'Powershell'
    Country  = 'Russia'
}

Либо использовать команду New-Object, но с большими данными он будет работать медленнее:

$object = New-Object PSObject -Property @{Name = 'Alex'; 
                                          Language = 'Powershell';
                                          Country = 'Russia'}

Если вы читали статью про создание hashtable в Powershell, то видели некоторые сложности с экспортом и форматированием обычных хэш таблиц, но использование PSCustomObject решает эти проблемы.

Доступ к данным можно получить так:

$object.Name
$object.'Name'
$value = 'Name'
$object.$value

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

Все эти способы работают одинаково.

Преобразование существующих hashtable

Если у вас уже создана хеш-таблица, то вы ее можете преобразовать следующим образом:

$hash_object = @{'Computer'='Sql1'; 'Administrator'='Dimitriy'; 'Date'=(Get-Date)}
$hash_object.GetType()
$ps_object = [pscustomobject]$hash_object
$ps_object.GetType()

преобразование Powershell PSCustomObject

Если попытаться вывести эти таблицы, то можно заметить разницу в отображении данных:

отображение Powershell PSCustomObject и hashtable

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

 

Сохранение в файл

Этот тип можно импортировать и экспортировать из файла работая с различными форматами.

CSV

Если вы пробовали сохранить хэш таблицу в CSV, то могли испытывать сложности с этим. Я читал, что это можно сделать, но с преобразованием в объект сделать это проще всего:

$ps_obj = @{'Name1'='Var1'; 'Name2'='Var2';'Name3'='Var3'}
[PSCustomObject]$ps_obj | Export-Csv -Path C:\ps_object.csv -Delimiter ',' -NoTypeInformation

На примере виден результат экспорта в CSV hashtable и csv:

экспорт Powershell PSCustomObject и hashtable в csv

С импортом таких данных проблем тоже нет:

$peobject = Import-Csv -Path C:\ps_object.csv -Delimiter ','
$peobject
$peobject.GetType()

Иморт Powershell PSCustomObject из csv

JSON

Так же как и с hashtable вы можете конвертировать данные в Json с дальнейшим импортом и экспортом:

$pwobject = [pscustomobject]@{'Name'='Lera';'Age'=10;}
$pwobject | ConvertTo-Json | Set-Content -Path "C:\json.txt"
$pwobject = Get-Content -Path "C:\json.txt" -Raw | ConvertFrom-Json
$pwobject.GetType()
$pwobject

Иморт Powershell PSCustomObject из json и экспорт

XML

Этот способ работает и с хэш таблицами и с кастомными объектами:

$ps_xml = [PSCustomObject]@{'key'='val';'key1'=@{'key1'='val1';'key2'='val2'}}
Export-Clixml -Path "C:\ps_xml.cli" -InputObject $ps_xml
Import-Clixml -Path "C:\ps_xml.cli"

Иморт Powershell PSCustomObject из xml и экспорт

 

Изменение, добавление и удаление свойств

Мы не можем изменять объект так же как и с hashtable. При таких действиях мы получим ошибку:

$ps_xml = [PSCustomObject]@{'key'='val';}
$ps_xml['key'] = 'change'
$ps_xml
  • Не удается индексировать в объект типа System.Management.Automation.PSObject.
  • Unable to index into an object of type System.Management.Automation.PSObject.

Для добавления свойств нужно использовать команду Add-Member:

$ps_xml = [PSCustomObject]@{'key'='val';}
$ps_xml | Add-Member -MemberType NoteProperty -Name 'key2' -Value 'val2'

Изменение свойств Powershell PSCustomObject

Так же и меняется значение:

$ps_xml = [PSCustomObject]@{'key'='val';}
$ps_xml | Add-Member -MemberType NoteProperty -Name 'key' -Value 'val2' -Force

Изменение свойств Powershell PSCustomObject

Если вы забудете указать ключ Force, то получите ошибку:

  • Add-Member : Не удается добавить элемент с именем "key", так как элемент с таким именем уже существует. Чтобы все равно перезаписать этот элемент, добавьте в команду параметр Force.
  • Add-Member : Cannot add a member with the name "key3" because a member with that name already exists. To overwrite the member anyway, add the Force parameter to your command.

Когда нужно удалить свойство используется метод remove:

$ps_xml.psobject.properties.remove('key')

При попытке удалить несуществующее значение появится ошибка:

  • Невозможно вызвать метод для выражения со значением NULL
  • You cannot call a method on a null-valued expression.

 

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

Мы можем вывести все свойства и методы у объекта таким же способом, каким получаем аналогичные данные у результатов команд:

$objects = [PSCustomObject]@{'PropertyName'='PropertyValue';}
$objects | Get-Member

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

Либо отобразить только имена:

$objects = [PSCustomObject]@{'PropertyName'='PropertyValue';}
$objects | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name

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

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

 

Преобразование в hashtable

Выше мы уже рассматривали как сделать объект из обычно таблицы, но вам может понадобиться и обратное преобразование. Прямой возможности сделать этого нет и нам нужно добавлять такие значения в таблицу самостоятельно через цикл:

$myobject = [PSCustomObject]@{'DateToday'=(Get-Date); 'Month'=(Get-Date).Month;}

$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
    $hashtable[$property] = $myObject.$property
}

Преобразование Powershell PSCustomObject в hashtable

 

Проверка в условиях

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

$myobject = [PSCustomObject]@{'DateToday'=(Get-Date); 'Month'=(Get-Date).Month;}
if ($null -ne $myobject.Month){'Ok'}

Либо использовать еще один скрытый метод:

if ($myobject.psobject.properties.match('Month')){'Ok'}

Проверка Powershell PSCustomObject в условиях 

 

Создание своих методов у объектов

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

$ptobject = [PSCustomObject]@{'SQL'='127.0.0.1'; 'Login'='TechSupport'}
# Скрипт, который будет вызывать при вызове метода
$ScriptBlock = {
    $result = $ptobject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
    return $result
}
# Добавление параметров в объект
$memberParam = @{
    MemberType = "ScriptMethod"
    InputObject = $ptobject
    Name = "TakeNames"
    Value = $scriptBlock
}
Add-Member @memberParam
$ptobject | Get-Member
# Вызов метода
$ptobject.TakeNames()

Создание метода Powershell PSCustomObject

Так же сработает и со скриптом, который преобразовываем объект в хэш таблицу:

$psobject = [PSCustomObject]@{'SQL'='127.0.0.1'; 'Login'='TechSupport'}
# Скрипт, который будет вызывать при вызове метода
$ScriptBlock = {
    $hashtable = @{}
    foreach( $property in $psobject.psobject.properties.name )
    {
        $hashtable[$property] = $psobject.$property
    }
    return $hashtable
}
# Добавление параметров в объект
$memberParam = @{
    MemberType = "ScriptMethod"
    InputObject = $psobject
    Name = "ConvertToHashTable"
    Value = $scriptBlock
}
Add-Member @memberParam
$psobject | Get-Member
# Вызов метода
$psobject.ConvertToHashTable()

Создание метода Powershell PSCustomObject 

Объекты и ссылки

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

$a = 1
$b = $a
$b = 2
$b
$a

вывод переменной в Powershell

В момент объявления $b = $a они не начинают хранить по 1, а ссылаются на один и тот же элемент. Исходя из этой ситуации в примере ниже мы изменим значение объекта:

$a = [PSCustomObject]@{Val=3}
$b = $a
$b.Val = 2
$b
$a

Изменение свойств Powershell PSCustomObject

psobject.copy()

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

$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4

Копирование Powershell PSCustomObject

Таким образом у нас находятся два разных массива в памяти и изменение одного из них не повлияет на другой.

 

Изменения свойства TypeName

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

$val = [PSCustomObject]@{Key=3}
$val | Get-Member

TypeName в Powershell PSCustomObject

Для его изменения мы можем использовать следующую команду:

$val.PSObject.TypeNames.Insert(0,"KeysObject")

TypeName в Powershell PSCustomObject

Это можно сделать и при создании объекта:

$val = [PSCustomObject]@{
    Key=3;
    PSTypeName = 'Key.Object'}
$val | Get-Member

установка TypeName в Powershell PSCustomObject 

...

Теги: #powershell


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