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 tego postu przez /u/ markekraus. Zrobiłem trochę kopania i więcej postów na temat pomysłu Adam Bertram i Mike Shepard , gdzie mówią o tym podejściu, które pozwala zdefiniować 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 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 TypeNameelementem .

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.