Udostępnij za pośrednictwem


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 prowadzonym 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 zera, ale czasami trzeba najpierw pracować z tabelą skrótu. Ten przykład działa, ponieważ konstruktor przyjmuje tablicę skrótów jako 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.

Przestarzałe podejście

Być może widziałeś ludzi używających New-Object 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 do 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 pobrać tę samą listę również z właściwości psobject.

$myobject.psobject.Properties.Name

Uwaga

Get-Member Zwraca właściwości w kolejności alfabetycznej. Użycie operatora dostępu do elementów, aby wypisać nazwy właściwości, zwraca je w kolejności, w jakiej były definiowane w obiekcie.

Dynamiczne uzyskiwanie dostępu do właściwości

Już wspomniałem, ż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, możesz sprawdzić, czy istnieje, sprawdzając psobject.Properties.

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 i ScriptBlock. Aby odwołać się do bieżącego obiektu, należy użyć automatycznej zmiennej this. 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łytką kopią, ponieważ jeśli istnieją zagnieżdżone obiekty (to jest obiekty, których właściwości 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 .ps1xmlplik formatowania, który wykonuje wszystkie złożone zadania. W tym wpisie Boe Prox znajdujemy inny sposób, aby wykonać to na naszym obiekcie niestandardowym, używając tylko PowerShell. Możemy dać MemberSet, aby mogła go 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 opadnie na powłokę, domyślnie będzie pokazywał tylko te właściwości.

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 gdybym nie miał tego postu jako szybkiego odniesienia, mógłbym to prawie zapamiętać. Teraz mogę łatwo tworzyć obiekty z dużą ilością właściwości, a jednocześnie nadać im ładny i przejrzysty widok podczas przeglądania ich 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 użyciem właściwości ScriptProperty

Coś jeszcze, co wyniosłem z tego filmu, to tworzenie właściwości skryptu dla twoich 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 w sposób, do którego odnosiłem się wcześniej, istnieje on tylko w tym konkretnym wystąpieniu obiektu. Dotyczy to wszystkich obiektów z tym TypeNameelementem .

Parametry funkcji

Możesz teraz używać tych typów niestandardowych dla parametrów w funkcjach i skryptach. Możesz mieć jedną funkcję tworzącą te niestandardowe obiekty i 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 zaoszczędzić ci krok testowania tego w twoim kodzie. Doskonałym przykładem umożliwienia programowi PowerShell zrobienia tego, co robi najlepiej.

Typ wyjściowy 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. Takie elementy jak Get-Command i Get-Help, z których może korzystać środowisko deweloperskie. 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 wychwytywać zmienne, które nie powinny trafiać do potoku.

Myśli zamykające

Kontekstem tego wszystkiego był [pscustomobject], ale wiele z tych informacji dotyczy ogólnie obiektów.

Widziałem większość tych funkcji przelotnie wcześniej, ale nigdy nie widziałem ich przedstawionych jako zbiór informacji na 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 czegoś się nauczyłeś i znajdziesz sposób na to, aby zastosować to w swoich skryptach.