- 10/05/2020
- 8 minut na przeczytanie
-
- j
- m
- s
- j
- c
.
PSCustomObject
s są świetnym narzędziem, które można dodać do swojego paska narzędzi PowerShell. Zacznijmy od podstaw i przejdźmy do bardziej zaawansowanych funkcji. Ideą używania PSCustomObject
jest posiadanie prostego sposobu na tworzenie danych strukturalnych. Spójrz na pierwszy przykład, a będziesz miał lepsze pojęcie, co to oznacza.
Note
Oryginalna wersja tego artykułu pojawiła się na blogu napisanym przez @KevinMarquette. Zespół ThePowerShell dziękuje Kevinowi za podzielenie się z nami tą treścią. Proszę sprawdzić jego blog naPowerShellExplained.com.
- Tworzenie PSCustomObject
- Konwersja hashtable
- Podejście legendarne
- Zapisywanie do pliku
- Praca z właściwościami
- Dodawanie właściwości
- Usuwanie właściwości
- Wyliczanie nazw właściwości
- Dynamiczny dostęp do właściwości
- Konwersja PSCustomObject do hashtable
- Testowanie właściwości
- Dodawanie metod obiektów
- Objects vs Value types
- psobject.copy()
- PSTypeName dla niestandardowych typów obiektów
- Używanie DefaultPropertySet (długa droga)
- Update-TypeData with DefaultPropertySet
- Update-TypeData with ScriptProperty
- Parametry funkcji
- Function OutputType
- Myślenia końcowe
Tworzenie PSCustomObject
Uwielbiam używać w PowerShell. Z tego powodu pominę wszystkie inne sposoby tworzenia obiektów, ale muszę wspomnieć, że większość z tych przykładów to PowerShell v3.0 i nowsze.
$myObject = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Ta metoda działa dobrze dla mnie, ponieważ używam hashtables do wszystkiego. Ale są chwile, kiedy chciałbym, aby PowerShell traktował hashtables bardziej jak obiekty. Pierwszym miejscem, w którym zauważysz różnicę jest kiedy chcesz użyć Format-Table
lub Export-CSV
i zdasz sobie sprawę, że tablica hashtabli jest po prostu kolekcją par klucz/wartość.
Możesz wtedy uzyskać dostęp i używać wartości jak normalnego obiektu.
$myObject.Name
Konwersja hashtable
Podczas gdy jestem w temacie, czy wiedziałeś, że możesz zrobić to:
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = $myHashtable
Wolę tworzyć obiekt od początku, ale są chwile, kiedy musisz najpierw pracować z ahashtable. Ten przykład działa, ponieważ konstruktor pobiera tablicę hashtable dla właściwości obiektu. Jedną z ważnych uwag jest to, że podczas gdy ta metoda działa, nie jest ona dokładnym odpowiednikiem. Największą różnicą jest to, że kolejność właściwości nie jest zachowana.
Podejście legendarne
Może widziałeś, jak ludzie używają New-Object
do tworzenia niestandardowych obiektów.
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = New-Object -TypeName PSObject -Property $myHashtable
Ten sposób jest nieco wolniejszy, ale może być najlepszą opcją na wczesnych wersjach PowerShell.
Zapisywanie do pliku
Odkryłem, że najlepszym sposobem na zapisanie hashtable do pliku jest zapisanie go jako JSON. Możesz zaimportować go z powrotem do
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path$myObject = Get-Content -Path $Path | ConvertFrom-Json
Obejmuję więcej sposobów zapisywania obiektów do pliku w moim artykule na tematWiele sposobów odczytu i zapisu do plików.
Praca z właściwościami
Dodawanie właściwości
Możesz nadal dodawać nowe właściwości do swojego PSCustomObject
za pomocą Add-Member
.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'$myObject.ID
Usuwanie właściwości
Możesz również usuwać właściwości z obiektu.
$myObject.psobject.properties.remove('ID')
Właściwość psobject
jest właściwością ukrytą, która daje dostęp do metadanych obiektu bazowego.
Wyliczanie nazw właściwości
Czasami potrzebujesz listy wszystkich nazw właściwości obiektu.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
Możemy uzyskać tę samą listę również z właściwości psobject
.
$myobject.psobject.properties.name
Dynamiczny dostęp do właściwości
Wspomniałem już, że można uzyskać bezpośredni dostęp do wartości właściwości.
$myObject.Name
Możesz użyć łańcucha dla nazwy właściwości i to nadal będzie działać.
$myObject.'Name'
Możemy zrobić ten jeden krok więcej i użyć zmiennej dla nazwy właściwości.
$property = 'Name'$myObject.$property
Wiem, że to wygląda dziwnie, ale działa.
Konwersja PSCustomObject do hashtable
Aby kontynuować z ostatniej sekcji, możesz dynamicznie chodzić po właściwościach i tworzyć z nich hashtable.
$hashtable = @{}foreach( $property in $myobject.psobject.properties.name ){ $hashtable = $myObject.$property}
Testowanie właściwości
Jeśli musisz wiedzieć, czy dana właściwość istnieje, możesz po prostu sprawdzić, czy ta właściwość ma wartość.
if( $null -ne $myObject.ID )
Ale jeśli wartość mogłaby być $null
, możesz sprawdzić, czy istnieje, sprawdzającpsobject.properties
dla niej.
if( $myobject.psobject.properties.match('ID').Count )
Dodawanie metod obiektów
Jeśli potrzebujesz dodać metodę skryptu do obiektu, możesz to zrobić za pomocą Add-Member
i aScriptBlock
. Musisz użyć this
automatycznej zmiennej odwołującej się do bieżącego obiektu. Tutaj jest ascriptblock
aby zamienić obiekt w tablicę hashtable. (ten sam kod z ostatniego przykładu)
Wtedy dodamy go do naszego obiektu jako właściwość skryptu.
Wtedy możemy wywołać naszą funkcję w ten sposób:
$myObject.ToHashtable()
Objects vs Value types
Objects i typy wartości nie obsługują przypisania zmiennych w ten sam sposób. Jeśli przypiszesz typy wartości do siebie nawzajem, tylko wartość zostanie skopiowana do nowej zmiennej.
$first = 1$second = $first$second = 2
W tym przypadku, $first
jest 1 i $second
jest 2.
Zmienne obiektowe przechowują odniesienie do rzeczywistego obiektu. Kiedy przypisujesz jeden obiekt do nowej zmiennej, wciąż odwołują się one do tego samego obiektu.
$third = @{Key=3}$fourth = $third$fourth.Key = 4
Ponieważ $third
i $fourth
odwołują się do tej samej instancji obiektu, zarówno $third.key
jak i$fourth.Key
mają wartość 4.
psobject.copy()
Jeśli potrzebujesz prawdziwej kopii obiektu, możesz go sklonować.
$third = @{Key=3}$fourth = $third.psobject.copy()$fourth.Key = 4
Clone tworzy płytką kopię obiektu. Mają one teraz różne instancje i $third.key
jest 3, a $fourth.Key
jest 4 w tym przykładzie.
Nazywam to płytką kopią, ponieważ jeśli masz zagnieżdżone obiekty. (gdzie właściwości zawierają inne obiekty). Kopiowane są tylko wartości najwyższego poziomu. Obiekty potomne będą odwoływać się do siebie nawzajem.
PSTypeName dla niestandardowych typów obiektów
Teraz, gdy mamy obiekt, jest jeszcze kilka rzeczy, które możemy z nim zrobić, a które mogą nie być tak oczywiste. Pierwszą rzeczą, którą musimy zrobić, to nadać mu PSTypeName
. Jest to najczęstszy sposób, w jaki ludzie to robią:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Ostatnio odkryłem inny sposób na zrobienie tego z tego postu autorstwa /u/markekraus. I did a littledigging and more posts about the idea from Adam Bertram and Mike Shepard where they talkabout this approach that allows you to define it inline.
$myObject = @{ PSTypeName = 'My.Object' Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
I love how niceely this just fits into the language. Teraz, gdy mamy obiekt z odpowiednią nazwą typu, możemy zrobić jeszcze kilka rzeczy.
Uwaga
Możesz również tworzyć niestandardowe typy PowerShell używając klas PowerShell. Aby uzyskać więcej informacji, zobaczPowerShell Class Overview.
Używanie DefaultPropertySet (długa droga)
PowerShell decyduje za nas, jakie właściwości mają być domyślnie wyświetlane. Wiele z natywnych poleceń ma plik formatujący.ps1xml
, który wykonuje całą ciężką pracę. Z tego postu przez Boe Prox, jest inny sposób na zrobienie tego na naszym niestandardowym obiekcie używając tylko PowerShell. Możemy dać muMemberSet
do użycia.
Teraz, gdy mój obiekt po prostu spadnie do powłoki, domyślnie pokaże tylko te właściwości.
Update-TypeData with DefaultPropertySet
To jest fajne, ale ostatnio widziałem lepszy sposób podczas oglądaniaPowerShell unplugged 2016 z Jeffreyem Snoverem & Don Jones. Jeffrey używałUpdate-TypeData do określenia domyślnych właściwości.
$TypeData = @{ TypeName = 'My.Object' DefaultDisplayPropertySet = 'Name','Language'}Update-TypeData @TypeData
To jest na tyle proste, że prawie mógłbym to zapamiętać, gdybym nie miał tego postu jako quickreference. Teraz mogę łatwo tworzyć obiekty z wieloma właściwościami i nadal nadawać im ładny, czysty wygląd, gdy patrzę na nie z poziomu powłoki. Jeśli potrzebuję uzyskać dostęp lub zobaczyć te inne właściwości, one tam pozostaną.
$myObject | Format-List *
Update-TypeData with ScriptProperty
Coś jeszcze wyniosłem z tego wideo to tworzenie właściwości skryptu dla twoich obiektów. To byłby dobry moment, aby zaznaczyć, że to działa również dla istniejących obiektów.
Możesz to zrobić przed utworzeniem obiektu lub po i nadal będzie działać. To jest to, co czyni to innym niż użycie Add-Member
z właściwością skryptu. Kiedy używasz Add-Member
w sposób opisany wcześniej, istnieje ona tylko na tej konkretnej instancji obiektu. Ten odnosi się do wszystkich obiektów z tym TypeName
.
Parametry funkcji
Możesz teraz użyć tych niestandardowych typów dla parametrów w twoich funkcjach i skryptach. Możesz mieć jedną funkcję, która tworzy te niestandardowe obiekty, a następnie przekazuje je do innych funkcji.
param( $Data )
PowerShell wymaga, aby obiekt był typu określonego przez użytkownika. Jeśli typ nie jest zgodny automatycznie wyrzuca błąd walidacji, aby oszczędzić Ci testowania go w kodzie. Wspaniały przykład pozwalania PowerShell na robienie tego, co robi najlepiej.
Function OutputType
Możesz również zdefiniować OutputType
dla swoich zaawansowanych funkcji.
function Get-MyObject{ param ( ...
Wartość atrybutu OutputType jest tylko uwagą do dokumentacji. Nie jest on wyprowadzany z kodu funkcji ani porównywany z rzeczywistym wyjściem funkcji.
Głównym powodem, dla którego używałbyś typu wyjścia, jest to, że meta informacje o twojej funkcji odzwierciedlają twoje intencje. Rzeczy takie jak Get-Command
i Get-Help
, z których może skorzystać twoje środowisko programistyczne. Jeśli chcesz uzyskać więcej informacji, to spójrz na pomoc dla niego:about_Functions_OutputTypeAttribute.
Pamiętając o tym, jeśli używasz Pestera do testowania jednostkowego swoich funkcji, to dobrym pomysłem byłoby sprawdzenie czy obiekty wyjściowe pasują do twojego OutputType. To mogłoby złapać zmienne, które po prostu wpadają do rury, kiedy nie powinny.
Myślenia końcowe
Kontekst tego był o , ale wiele z tych informacji odnosi się do obiektów w ogóle.
Widziałem większość z tych funkcji w przelocie wcześniej, ale nigdy nie widziałem ich przedstawionych jako zbiór informacji na PSCustomObject
. Właśnie w tym ostatnim tygodniu natknąłem się na kolejny i byłem zaskoczony, że nie widziałem go wcześniej. Chciałem zebrać wszystkie te pomysły razem, abyś mógł, mam nadzieję, zobaczyć większy obraz i być świadomy ich, gdy masz okazję ich używać. Mam nadzieję, że nauczyłeś się czegoś i możesz znaleźć sposób na wykorzystanie tego w swoich skryptach.