Wszystko, co chciałeś wiedzieć o PSCustomObject
PSCustomObject
to doskonałe narzędzie do dodania do pasa narzędzi programu PowerShell. Zacznijmy od podstaw i przyjrzyjmy się bardziej zaawansowanym funkcjom. Chodzi o to PSCustomObject
, aby utworzyć dane ustrukturyzowane w prosty sposób. Przyjrzyj się pierwszem przykładom i lepiej zrozumiesz, co to oznacza.
Uwaga
Oryginalna wersja tego artykułu pojawiła się na blogu napisanym przez @KevinMarquette. Zespół programu PowerShell dziękuje Kevinowi za udostępnienie tej zawartości nam. Zapoznaj się ze swoim blogiem na PowerShellExplained.com.
Tworzenie obiektu PSCustomObject
Uwielbiam używać [PSCustomObject]
w programie PowerShell. Tworzenie obiektu użytecznego nigdy nie było łatwiejsze.
W związku z tym zamierzam pominąć wszystkie inne sposoby tworzenia obiektu, ale muszę wspomnieć, że większość z tych przykładów to program PowerShell w wersji 3.0 i nowszej.
$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Ta metoda działa dobrze dla mnie, ponieważ używam tabel skrótów dla prawie wszystkiego. Ale czasami chciałbym, aby program PowerShell traktować tabele skrótów bardziej jak obiekt. Pierwsze miejsce, w którym zauważysz różnicę, jest to, że chcesz użyć Format-Table
metody lub Export-CSV
i zdajesz sobie sprawę, że tabela skrótu to tylko kolekcja par klucz/wartość.
Następnie możesz uzyskać dostęp do tych wartości i użyć tych wartości, jak zwykły obiekt.
$myObject.Name
Konwertowanie tabeli skrótu
Chociaż jestem na ten temat, czy wiesz, że możesz to zrobić:
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = [pscustomobject]$myHashtable
Wolę utworzyć obiekt od początku, ale czasami trzeba pracować z tabelą skrótu najpierw. Ten przykład działa, ponieważ konstruktor przyjmuje tabelę skrótu dla właściwości obiektu. Jedną z ważnych uwag jest to, że chociaż ta metoda działa, nie jest to dokładne odpowiedniki. Największą różnicą jest to, że kolejność właściwości nie jest zachowywana.
Jeśli chcesz zachować kolejność, zobacz Uporządkowane tabele skrótów.
Starsze podejście
Być może osoby używają New-Object
ich do tworzenia obiektów niestandardowych.
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = New-Object -TypeName PSObject -Property $myHashtable
W ten sposób jest to nieco wolniejsze, ale może to być najlepsza opcja we wczesnych wersjach programu PowerShell.
Zapisywanie w pliku
Uważam, że najlepszym sposobem zapisania tabeli skrótu w pliku jest zapisanie go w formacie JSON. Możesz zaimportować go z powrotem do [PSCustomObject]
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json
Opisuję więcej sposobów zapisywania obiektów w pliku w moim artykule na wiele sposobów odczytywania i zapisywania w plikach.
Praca z właściwościami
Dodawanie właściwości
Możesz nadal dodawać nowe właściwości do pliku PSCustomObject
za pomocą polecenia Add-Member
.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'
$myObject.ID
Usuń właściwości
Można również usunąć właściwości z obiektu.
$myObject.psobject.properties.remove('ID')
Element .psobject
jest elementem wewnętrznym, który zapewnia dostęp do metadanych obiektu podstawowego. Aby uzyskać więcej informacji na temat elementów wewnętrznych, zobacz about_Intrinsic_Members.
Wyliczanie nazw właściwości
Czasami potrzebna jest lista wszystkich nazw właściwości obiektu.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
Możemy również pobrać tę samą listę z psobject
właściwości.
$myobject.psobject.properties.name
Uwaga
Get-Member
Zwraca właściwości w kolejności alfabetycznej. Użycie operatora dostępu do elementu członkowskiego w celu wyliczenia nazw właściwości zwraca właściwości w kolejności, w której zostały zdefiniowane w obiekcie.
Dynamiczne uzyskiwanie dostępu do właściwości
Już wspomniano, że można uzyskać bezpośredni dostęp do wartości właściwości.
$myObject.Name
Możesz użyć ciągu dla nazwy właściwości i nadal będzie działać.
$myObject.'Name'
Możemy wykonać ten jeszcze jeden krok i użyć zmiennej dla nazwy właściwości.
$property = 'Name'
$myObject.$property
Wiem, że wygląda dziwnie, ale to działa.
Konwertowanie obiektu PSCustomObject na tabelę skrótów
Aby kontynuować pracę z ostatniej sekcji, możesz dynamicznie przechodzić przez właściwości i tworzyć z nich tabelę skrótów.
$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
$hashtable[$property] = $myObject.$property
}
Testowanie właściwości
Jeśli musisz wiedzieć, czy właściwość istnieje, możesz po prostu sprawdzić, czy ta właściwość ma wartość.
if( $null -ne $myObject.ID )
Jeśli jednak wartość może być $null
widoczna, możesz sprawdzić, czy istnieje, sprawdzając psobject.properties
jej wartość.
if( $myobject.psobject.properties.match('ID').Count )
Dodawanie metod obiektów
Jeśli musisz dodać metodę skryptu do obiektu, możesz to zrobić za pomocą Add-Member
polecenia i ScriptBlock
. Należy użyć zmiennej automatycznej odwołującej this
się do bieżącego obiektu. Oto element scriptblock
umożliwiający przekształcenie obiektu w tabelę skrótów. (ten sam kod w ostatnim przykładzie)
$ScriptBlock = {
$hashtable = @{}
foreach( $property in $this.psobject.properties.name )
{
$hashtable[$property] = $this.$property
}
return $hashtable
}
Następnie dodamy go do naszego obiektu jako właściwość skryptu.
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
}
Add-Member @memberParam
Następnie możemy wywołać naszą funkcję w następujący sposób:
$myObject.ToHashtable()
Obiekty a typy wartości
Obiekty i typy wartości nie obsługują przypisań zmiennych w taki sam sposób. W przypadku przypisania typów wartości do siebie tylko wartość zostanie skopiowana do nowej zmiennej.
$first = 1
$second = $first
$second = 2
W tym przypadku $first
wartość to 1 i $second
ma wartość 2.
Zmienne obiektu przechowują odwołanie do rzeczywistego obiektu. Po przypisaniu jednego obiektu do nowej zmiennej nadal odwołują się do tego samego obiektu.
$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4
Ponieważ $third
i $fourth
odwołuje się do tego samego wystąpienia obiektu, oba $third.key
i $fourth.Key
mają wartość 4.
psobject.copy()
Jeśli potrzebujesz prawdziwej kopii obiektu, możesz go sklonować.
$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4
Klon tworzy płytkią kopię obiektu. Mają teraz różne wystąpienia i $third.key
mają wartość 3 i $fourth.Key
ma wartość 4 w tym przykładzie.
Nazywam to płytkią kopią, ponieważ jeśli obiekty zagnieżdżone (obiekty z właściwościami zawierają inne obiekty), kopiowane są tylko wartości najwyższego poziomu. Obiekty podrzędne będą się odwoływać do siebie.
PSTypeName dla typów obiektów niestandardowych
Teraz, gdy mamy obiekt, istnieje kilka innych rzeczy, które możemy z tym zrobić, które mogą nie być prawie tak oczywiste. Pierwszą rzeczą, którą musimy zrobić, jest nadanie mu .PSTypeName
Jest to najbardziej typowy sposób, w jaki widzę, że ludzie to robią:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Niedawno odkryłem inny sposób, aby to zrobić z Redditor u/markekraus
. Mówi o tym podejściu, które umożliwia zdefiniowanie go w tekście.
$myObject = [PSCustomObject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Uwielbiam, jak miło to po prostu pasuje do języka. Teraz, gdy mamy obiekt o odpowiedniej nazwie typu, możemy wykonać kilka innych czynności.
Uwaga
Można również tworzyć niestandardowe typy programu PowerShell przy użyciu klas programu PowerShell. Aby uzyskać więcej informacji, zobacz Omówienie klasy programu PowerShell.
Korzystanie z elementu DefaultPropertySet (długa droga)
Program PowerShell decyduje o tym, jakie właściwości mają być wyświetlane domyślnie. Wiele poleceń natywnych ma .ps1xml
plik formatowania, który wykonuje wszystkie ciężkie operacje podnoszenia. W tym wpisie boe Prox istnieje inny sposób, abyśmy to zrobili w naszym obiekcie niestandardowym przy użyciu tylko programu PowerShell. Możemy dać jej MemberSet
użyć.
$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
Teraz, gdy mój obiekt po prostu spadnie do powłoki, pokaże tylko te właściwości domyślnie.
Update-TypeData z ustawieniem DefaultPropertySet
Jest to miłe, ale ostatnio widziałem lepszy sposób używania update-TypeData do określenia właściwości domyślnych.
$TypeData = @{
TypeName = 'My.Object'
DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData
To jest na tyle proste, że prawie pamiętam to, jeśli nie miałem tego postu jako krótkiego odwołania. Teraz mogę łatwo tworzyć obiekty z dużą ilością właściwości i nadal dać mu ładny czysty widok podczas przeglądania go z powłoki. Jeśli muszę uzyskać dostęp do tych innych właściwości lub zobaczyć je, nadal są tam.
$myObject | Format-List *
Update-TypeData z właściwością ScriptProperty
Coś innego wysiadłem z tego klipu wideo, tworząc właściwości skryptu dla obiektów. Byłoby to dobry moment, aby wskazać, że działa to również dla istniejących obiektów.
$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData
Można to zrobić przed utworzeniem obiektu lub po nim i nadal będzie działać. To sprawia, że różni się to od użycia Add-Member
z właściwością skryptu. Jeśli używasz Add-Member
sposobu, w jaki się odwołujem wcześniej, istnieje on tylko w tym konkretnym wystąpieniu obiektu. Dotyczy to wszystkich obiektów z tym TypeName
elementem .
Parametry funkcji
Możesz teraz używać tych typów niestandardowych dla parametrów w funkcjach i skryptach. Można utworzyć jedną funkcję, a następnie przekazać je do innych funkcji.
param( [PSTypeName('My.Object')]$Data )
Program PowerShell wymaga, aby obiekt był określonym typem. Zgłasza błąd weryfikacji, jeśli typ nie jest zgodny automatycznie, aby zapisać krok testowania dla niego w kodzie. Doskonałym przykładem umożliwienia programowi PowerShell zrobienia tego, co robi najlepiej.
Typ danych wyjściowych funkcji
Można również zdefiniować element OutputType
dla funkcji zaawansowanych.
function Get-MyObject
{
[OutputType('My.Object')]
[CmdletBinding()]
param
(
...
Wartość atrybutu OutputType jest tylko notatką dotyczącą dokumentacji. Nie pochodzi on z kodu funkcji ani nie jest porównywany z rzeczywistymi danymi wyjściowymi funkcji.
Głównym powodem użycia typu danych wyjściowych jest to, że metadane dotyczące funkcji odzwierciedlają intencje. Get-Command
Takie elementy jak i Get-Help
to, że środowisko deweloperskie może korzystać z zalet. Jeśli chcesz uzyskać więcej informacji, zapoznaj się z pomocą: about_Functions_OutputTypeAttribute.
Jeśli używasz platformy Pester do testowania swoich funkcji, dobrym pomysłem byłoby sprawdzenie, czy obiekty wyjściowe są zgodne z parametrem OutputType. Może to przechwytywać zmienne, które po prostu spadną do potoku, gdy nie powinny.
Myśli zamykające
Kontekstem tego wszystkiego [PSCustomObject]
było , ale wiele z tych informacji dotyczy ogólnie obiektów.
Widziałem większość tych funkcji w przekazywaniu wcześniej, ale nigdy nie widziałem ich przedstawiać jako zbiór informacji na temat PSCustomObject
. Tylko w tym zeszłym tygodniu natknąłem się na innego i był zaskoczony, że nie widziałem go wcześniej. Chciałem wyciągnąć wszystkie te pomysły razem, aby mieć nadzieję, że zobaczysz większy obraz i być świadomy ich, gdy masz okazję ich używać. Mam nadzieję, że coś się nauczyłeś i znajdziesz sposób na to, aby pracować z twoimi skryptami.