- 10/05/2020
- 8 minuten om te lezen
-
- j
- m
- s
- j
- c
PSCustomObject
s zijn een geweldige tool om toe te voegen aan uw PowerShell-gereedschapsriem. Laten we beginnen met de basis en ons een weg banen naar de meer geavanceerde functies. Het idee achter het gebruik van een PSCustomObject
is om een eenvoudige manier te hebben om gestructureerde gegevens te maken. Bekijk het eerste voorbeeld en u krijgt een beter idee van wat dat betekent.
Note
De oorspronkelijke versie van dit artikel verscheen op de blog geschreven door @KevinMarquette. Het PowerShell-team dankt Kevin voor het delen van deze inhoud met ons. Bekijk zijn blog op PowerShellExplained.com.
- Creating a PSCustomObject
- Een hashtable converteren
- Legacy benadering
- Opslaan in een bestand
- Werken met eigenschappen
- Eigenschappen toevoegen
- Eigenschappen verwijderen
- Eigenschappen opnoemen
- Dynamische toegang tot eigenschappen
- Verander PSCustomObject in een hashtable
- Testen op eigenschappen
- Eigenschappen van objecten toevoegen
- Objects vs Value types
- psobject.copy()
- PSTypeName voor aangepaste object-typen
- Gebruik DefaultPropertySet (de lange weg)
- Update-TypeData met DefaultPropertySet
- Update-TypeData met ScriptProperty
- Functie parameters
- Functie OutputType
- Dichtende gedachten
Creating a PSCustomObject
Ik ben dol op het gebruik van in PowerShell. Het maken van een bruikbaar object is nog nooit zo eenvoudig geweest.Daarom ga ik alle andere manieren waarop je een object kunt maken overslaan, maar ik moet wel vermelden dat de meeste van deze voorbeelden PowerShell v3.0 en nieuwer zijn.
$myObject = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Deze methode werkt goed voor mij, omdat ik hashtables voor zo ongeveer alles gebruik. Maar er zijn momenten waarop ik zou willen dat PowerShell hashtables meer als een object behandelt. Het eerste verschil merk je wanneer je Format-Table
of Export-CSV
wilt gebruiken en je beseft dat een hashtable gewoon een verzameling sleutel/waarde-paren is.
Je kunt de waarden dan benaderen en gebruiken zoals je een normaal object zou gebruiken.
$myObject.Name
Een hashtable converteren
Nu ik het er toch over heb, wist je dat je dit kon doen:
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = $myHashtable
Ik geef er de voorkeur aan om het object vanaf het begin te maken, maar er zijn momenten dat je eerst met een hashtable moet werken. Dit voorbeeld werkt omdat de constructor een hashtable neemt voor de objecteigenschappen. Een belangrijke opmerking is dat hoewel deze methode werkt, het geen exact equivalent is. Het grootste verschil is dat de volgorde van de eigenschappen niet bewaard blijft.
Legacy benadering
Je hebt misschien gezien dat mensen New-Object
gebruiken om aangepaste objecten te maken.
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = New-Object -TypeName PSObject -Property $myHashtable
Deze manier is een stuk langzamer, maar het kan uw beste optie zijn op vroege versies van PowerShell.
Opslaan in een bestand
Ik vind de beste manier om een hashtable op te slaan in een bestand is door het op te slaan als JSON. U kunt deze dan weer importeren in een
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path$myObject = Get-Content -Path $Path | ConvertFrom-Json
Ik bespreek meer manieren om objecten in een bestand op te slaan in mijn artikel over De vele manieren om naar bestanden te lezen en te schrijven.
Werken met eigenschappen
Eigenschappen toevoegen
Je kunt nog steeds nieuwe eigenschappen aan je PSCustomObject
toevoegen met Add-Member
.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'$myObject.ID
Eigenschappen verwijderen
Je kunt ook eigenschappen van een object verwijderen.
$myObject.psobject.properties.remove('ID')
De psobject
is een verborgen eigenschap die u toegang geeft tot de metadata van het basisobject.
Eigenschappen opnoemen
Soms hebt u een lijst nodig van alle namen van eigenschappen op een object.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
We kunnen deze zelfde lijst ook uit de psobject
eigenschap halen.
$myobject.psobject.properties.name
Dynamische toegang tot eigenschappen
Ik heb al gezegd dat je de waarden van eigenschappen direct kunt benaderen.
$myObject.Name
Je kunt een string gebruiken voor de property naam en het zal nog steeds werken.
$myObject.'Name'
We kunnen nog een stap verder gaan en een variabele gebruiken voor de property naam.
$property = 'Name'$myObject.$property
Ik weet dat het er vreemd uitziet, maar het werkt.
Verander PSCustomObject in een hashtable
Om verder te gaan met de laatste sectie, kun je dynamisch de eigenschappen doorlopen en er een hashtable van maken.
$hashtable = @{}foreach( $property in $myobject.psobject.properties.name ){ $hashtable = $myObject.$property}
Testen op eigenschappen
Als je moet weten of een eigenschap bestaat, zou je gewoon kunnen controleren of die eigenschap een waarde heeft.
if( $null -ne $myObject.ID )
Maar als de waarde $null
zou kunnen zijn, kunt u controleren of die bestaat door depsobject.properties
ervoor te controleren.
if( $myobject.psobject.properties.match('ID').Count )
Eigenschappen van objecten toevoegen
Als u een scriptmethode aan een object moet toevoegen, kunt u dat doen met Add-Member
en eenScriptBlock
. Je moet de this
automatische variabele gebruiken om naar het huidige object te verwijzen. Hier is ascriptblock
om een object in een hashtable te veranderen. (Dezelfde code als in het laatste voorbeeld)
Dan voegen we het toe aan ons object als een script property.
Dan kunnen we onze functie zo aanroepen:
$myObject.ToHashtable()
Objects vs Value types
Objects en value types gaan niet op dezelfde manier om met variabele toewijzingen. Als je waardetypen aan elkaar toewijst, wordt alleen de waarde naar de nieuwe variabele gekopieerd.
$first = 1$second = $first$second = 2
In dit geval is $first
1 en $second
is 2.
Object-variabelen bevatten een verwijzing naar het eigenlijke object. Wanneer u een object toewijst aan een nieuwe variabele, verwijzen ze nog steeds naar hetzelfde object.
$third = @{Key=3}$fourth = $third$fourth.Key = 4
Omdat $third
en $fourth
verwijzen naar dezelfde instantie van een object, zijn zowel $third.key
als$fourth.Key
4.
psobject.copy()
Als u een echte kopie van een object nodig hebt, kunt u het klonen.
$third = @{Key=3}$fourth = $third.psobject.copy()$fourth.Key = 4
Kloon maakt een oppervlakkige kopie van het object. Ze hebben nu verschillende instanties en $third.key
is 3 en $fourth.Key
is 4 in dit voorbeeld.
Ik noem dit een ondiepe kopie omdat als je geneste objecten hebt. (waar de eigenschappen andere objecten bevatten). Alleen de top-level waarden worden gekopieerd. De kind-objecten zullen naar elkaar verwijzen.
PSTypeName voor aangepaste object-typen
Nu we een object hebben, zijn er nog een paar dingen die we ermee kunnen doen die misschien niet zo voor de hand liggen. Het eerste wat we moeten doen is het een PSTypeName
geven. Dit is de meest voorkomende manier waarop ik mensen het zie doen:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Ik ontdekte onlangs een andere manier om dit te doen van deze post door /u/markekraus. Ik deed een littledigging en meer berichten over het idee van Adam Bertram en Mike Shepard waar ze praten over deze aanpak die u toelaat om het te definiëren inline.
$myObject = @{ PSTypeName = 'My.Object' Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Ik hou van hoe mooi dit gewoon past in de taal. Nu we een object met een juiste typenaam hebben, kunnen we nog wat meer dingen doen.
Note
U kunt ook aangepaste PowerShell-typen maken met PowerShell-klassen. Zie voor meer informatiePowerShell Class Overview.
Gebruik DefaultPropertySet (de lange weg)
PowerShell bepaalt voor ons welke eigenschappen standaard moeten worden weergegeven. Veel van de native commando’s hebben een.ps1xml
opmaakbestand dat al het zware werk doet. Uit deze post van Boe Prox, is er een andere manier voor ons om dit te doen op ons aangepaste object met alleen PowerShell. We kunnen het eenMemberSet
geven om te gebruiken.
Nu wanneer mijn object gewoon in de shell valt, zal het standaard alleen die eigenschappen laten zien.
Update-TypeData met DefaultPropertySet
Dit is leuk, maar ik zag onlangs een betere manier toen ik keek naarPowerShell unplugged 2016 met Jeffrey Snover & Don Jones. Jeffrey gebruikteUpdate-TypeData om de standaardeigenschappen op te geven.
$TypeData = @{ TypeName = 'My.Object' DefaultDisplayPropertySet = 'Name','Language'}Update-TypeData @TypeData
Dat is eenvoudig genoeg dat ik het bijna zou kunnen onthouden als ik deze post niet als snelverwijzing had. Nu kan ik gemakkelijk objecten maken met veel eigenschappen en het toch een mooi overzicht geven als ik er vanuit de commandoregel naar kijk. Als ik die andere eigenschappen nodig heb, zijn ze er nog steeds.
$myObject | Format-List *
Update-TypeData met ScriptProperty
Siets anders wat ik uit die video haalde was het maken van script eigenschappen voor je objecten. Dit is een goed moment om erop te wijzen dat dit ook werkt voor bestaande objecten.
Je kunt dit doen voordat je object is gemaakt of erna en het zal nog steeds werken. Dit is wat dit anders maakt dan het gebruik van Add-Member
met een script eigenschap. Wanneer je Add-Member
gebruikt op de manier waarnaar ik eerder verwees, bestaat het alleen op die specifieke instantie van het object. Deze is van toepassing op alle objecten met deze TypeName
.
Functie parameters
U kunt nu deze aangepaste types gebruiken voor parameters in uw functies en scripts. U kunt een functie deze aangepaste objecten laten maken en ze dan aan andere functies doorgeven.
param( $Data )
PowerShell vereist dat het object het type is dat u hebt opgegeven. Als het type niet overeenkomt, wordt automatisch een validatiefout gemaakt, zodat u dit niet in uw code hoeft te testen. Een mooi voorbeeld van PowerShell laten doen waar het goed in is.
Functie OutputType
U kunt ook een OutputType
definiëren voor uw geavanceerde functies.
function Get-MyObject{ param ( ...
De waarde van het OutputType-attribuut is slechts een documentatie-notitie. Ze wordt niet afgeleid van de functiecode of vergeleken met de eigenlijke uitvoer van de functie.
De belangrijkste reden waarom u een uitvoertype zou gebruiken, is dat de meta-informatie over uw functie uw bedoelingen weerspiegelt. Dingen zoals Get-Command
en Get-Help
waar uw ontwikkelomgeving gebruik van kan maken. Als je meer informatie wilt, kijk dan in de help voor het: about_Functions_OutputTypeAttribute.
Met dat gezegd hebbende, als je Pester gebruikt om je functies te testen, zou het een goed idee zijn om te valideren dat de output objecten overeenkomen met je OutputType. Dit zou variabelen kunnen vangen die gewoon op de pijp vallen wanneer dat niet zou moeten.
Dichtende gedachten
De context van dit alles ging over , maar veel van deze informatie is van toepassing op objecten in het algemeen.
Ik heb de meeste van deze functies eerder in het voorbijgaan gezien, maar ik heb ze nooit gepresenteerd gezien als een verzameling van informatie over PSCustomObject
. Vorige week nog kwam ik er nog een tegen en was verbaasd dat ik die niet eerder had gezien. Ik wilde al deze ideeën samenbrengen zodat je hopelijk het grotere plaatje kunt zien en je ervan bewust kunt zijn als je de kans hebt om ze te gebruiken. Ik hoop dat je er iets van leert en een manier vindt om dit in je scripts te verwerken.