Alles wat u wilde weten over PSCustomObject
PSCustomObject is een geweldig hulpmiddel om toe te voegen aan uw PowerShell-gereedschapsgordel. Laten we beginnen met de basisbeginselen en onze weg in de geavanceerdere 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 hebt een beter idee van wat dat betekent.
Notitie
De oorspronkelijke versie van dit artikel verscheen op het blog geschreven door @KevinMarquette. Het PowerShell-team bedankt Kevin voor het delen van deze inhoud met ons. Bekijk zijn blog op PowerShellExplained.com.
Een PSCustomObject maken
Ik gebruik [PSCustomObject] graag in PowerShell. Het maken van een bruikbaar object is nog nooit zo eenvoudig geweest.
Daarom ga ik alle andere manieren overslaan waarop u een object kunt maken, maar ik moet vermelden dat de meeste van deze voorbeelden PowerShell v3.0 en hoger zijn.
$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Deze methode werkt goed voor mij omdat ik hashtables voor bijna alles gebruik. Maar er zijn momenten waarop ik wil dat PowerShell hashtables meer als een object behandelt. De eerste plaats waar u het verschil ziet, is wanneer u wilt gebruiken Format-Table of Export-CSV u zich realiseert dat een hashtabel slechts een verzameling sleutel-waardeparen is.
Vervolgens kunt u de waarden openen en gebruiken zoals u een normaal object zou doen.
$myObject.Name
Een hashtabel converteren
Terwijl ik in het onderwerp ben, wist u dat u dit kon doen:
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = [pscustomobject]$myHashtable
Ik wil het object liever vanaf het begin maken, maar er zijn tijden dat u eerst met een hashtabel moet werken. Dit voorbeeld werkt omdat de constructor een hashtabel gebruikt voor de objecteigenschappen. Een belangrijke opmerking is dat hoewel deze methode werkt, het niet exact een equivalent is. Het grootste verschil is dat de volgorde van de eigenschappen niet behouden blijft.
Zie Geordende hashtabellen als u de volgorde wilt behouden.
Verouderde benadering
Mogelijk hebt u gezien dat personen New-Object aangepaste objecten maken.
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = New-Object -TypeName PSObject -Property $myHashtable
Op deze manier is het vrij wat langzamer, maar het kan de beste optie zijn voor vroege versies van PowerShell.
Opslaan in een bestand
Ik vind de beste manier om een hashtabel op te slaan in een bestand door het bestand op te slaan als JSON. U kunt deze weer importeren in een [PSCustomObject]
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json
Ik heb meer manieren besproken om objecten op te slaan in een bestand in mijn artikel over de vele manieren om bestanden te lezen en te schrijven.
Werken met eigenschappen
Eigenschappen toevoegen
U kunt nog steeds nieuwe eigenschappen toevoegen aan uw PSCustomObject met Add-Member.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'
$myObject.ID
Eigenschappen verwijderen
U kunt ook eigenschappen van een object verwijderen.
$myObject.psobject.properties.remove('ID')
Het .psobject is een intrinsiek lid dat u toegang geeft tot metagegevens van basisobjecten. Zie about_Intrinsic_Members voor meer informatie over intrinsieke leden.
Namen van eigenschappen opsommen
Soms hebt u een lijst met alle eigenschapsnamen voor een object nodig.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
We kunnen dezelfde lijst ook van de psobject accommodatie ophalen.
$myobject.psobject.properties.name
Dynamisch toegang krijgen tot eigenschappen
Ik heb al gezegd dat u rechtstreeks toegang hebt tot eigenschapswaarden.
$myObject.Name
U kunt een tekenreeks gebruiken voor de eigenschapsnaam en deze werkt nog steeds.
$myObject.'Name'
We kunnen deze stap nog één stap uitvoeren en een variabele gebruiken voor de naam van de eigenschap.
$property = 'Name'
$myObject.$property
Dat ziet er vreemd uit, maar het werkt wel.
PSCustomObject converteren naar een hashtabel
Als u wilt doorgaan vanuit de laatste sectie, kunt u de eigenschappen dynamisch doorlopen en een hashtabel maken.
$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
$hashtable[$property] = $myObject.$property
}
Testen op eigenschappen
Als u wilt weten of er een eigenschap bestaat, kunt u gewoon controleren of die eigenschap een waarde heeft.
if( $null -ne $myObject.ID )
Maar als de waarde kan zijn $null , kunt u controleren of deze bestaat door de psobject.properties waarde te controleren.
if( $myobject.psobject.properties.match('ID').Count )
Objectmethoden toevoegen
Als u een scriptmethode aan een object wilt toevoegen, kunt u dit doen met Add-Member en een ScriptBlock. U moet de this automatische variabeleverwijzing naar het huidige object gebruiken. Hier volgt een scriptblock om een object om te zetten in een hashtabel. (hetzelfde codeformulier als het laatste voorbeeld)
$ScriptBlock = {
$hashtable = @{}
foreach( $property in $this.psobject.properties.name )
{
$hashtable[$property] = $this.$property
}
return $hashtable
}
Vervolgens voegen we het als scripteigenschap toe aan ons object.
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
}
Add-Member @memberParam
Vervolgens kunnen we onze functie als volgt aanroepen:
$myObject.ToHashtable()
Objecten versus waardetypen
Objecten en waardetypen verwerken variabeletoewijzingen niet op dezelfde manier. Als u waardetypen aan elkaar toewijst, wordt alleen de waarde gekopieerd naar de nieuwe variabele.
$first = 1
$second = $first
$second = 2
In dit geval $first is dit 1 en $second 2.
Objectvariabelen bevatten een verwijzing naar het werkelijke object. Wanneer u één object toewijst aan een nieuwe variabele, verwijzen ze nog steeds naar hetzelfde object.
$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4
Omdat $third en $fourth verwijst naar hetzelfde exemplaar van een object, beide $third.key en $fourth.Key zijn 4.
psobject.copy()
Als u een echte kopie van een object nodig hebt, kunt u het klonen.
$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4
Kloon maakt een ondiepe kopie van het object. Ze hebben nu verschillende exemplaren en $third.key zijn 3 en $fourth.Key zijn 4 in dit voorbeeld.
Ik noem dit een ondiepe kopie omdat als u geneste objecten hebt. (waarbij de eigenschappen andere objecten bevatten). Alleen de waarden op het hoogste niveau worden gekopieerd. De onderliggende objecten verwijzen naar elkaar.
PSTypeName voor aangepaste objecttypen
Nu we een object hebben, zijn er nog een paar dingen die we ermee kunnen doen die misschien niet zo duidelijk zijn. Het eerste wat we moeten doen, is het geven van een PSTypeName. Dit is de meest voorkomende manier waarop ik zie dat mensen het doen:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Ik heb onlangs een andere manier ontdekt om dit te doen vanuit dit bericht door /u/markekraus. Ik heb wat gegraven en meer berichten over het idee van Adam Bertram en Mike Shepard waar ze over deze aanpak praten, zodat je het inline kunt definiëren.
$myObject = [PSCustomObject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Ik hou ervan hoe mooi dit past in de taal. Nu we een object met een juiste typenaam hebben, kunnen we nog wat meer dingen doen.
Notitie
U kunt ook aangepaste PowerShell-typen maken met behulp van PowerShell-klassen. Zie Overzicht van PowerShell-klassen voor meer informatie.
DefaultPropertySet gebruiken (de lange weg)
PowerShell bepaalt voor ons welke eigenschappen standaard moeten worden weergegeven. Veel van de systeemeigen opdrachten hebben een .ps1xmlopmaakbestand dat al het zware werk doet. Vanuit dit bericht van Boe Prox is er een andere manier om dit te doen op ons aangepaste object met behulp van Alleen PowerShell. We kunnen het MemberSet gebruiken.
$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
Als mijn object nu alleen in de shell valt, worden deze eigenschappen standaard alleen weergegeven.
Update-TypeData met DefaultPropertySet
Dit is leuk, maar ik zag onlangs een betere manier bij het kijken naar PowerShell losgekoppeld 2016 met Jeffrey Snover & Don Jones. Jeffrey gebruikte Update-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 kon onthouden als ik dit bericht niet als snel referentie had. Nu kan ik eenvoudig objecten met veel eigenschappen maken en het nog steeds een mooi schoon beeld geven wanneer ik het bekijk vanuit de shell. Als ik die andere eigenschappen moet openen of zien, zijn ze er nog.
$myObject | Format-List *
Update-TypeData met ScriptProperty
Iets anders dat ik uit die video heb gehaald, was het maken van scripteigenschappen voor uw objecten. Dit zou een goed moment zijn om te benadrukken dat dit ook voor bestaande objecten werkt.
$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData
U kunt dit doen voordat uw object wordt gemaakt of daarna en het nog steeds werkt. Dit is wat dit anders maakt dan het gebruik met Add-Member een scripteigenschap. Wanneer u Add-Member de manier gebruikt waarnaar ik eerder heb verwezen, bestaat deze alleen op dat specifieke exemplaar van het object. Deze is van toepassing op alle objecten met deze TypeName.
Functieparameters
U kunt deze aangepaste typen nu gebruiken voor parameters in uw functies en scripts. U kunt met één functie deze aangepaste objecten maken en deze vervolgens doorgeven aan andere functies.
param( [PSTypeName('My.Object')]$Data )
PowerShell vereist dat het object het type is dat u hebt opgegeven. Er wordt een validatiefout gegenereerd als het type niet automatisch overeenkomt om de stap voor het testen ervan in uw code op te slaan. Een goed voorbeeld van het laten doen van PowerShell wat het beste doet.
Function OutputType
U kunt ook een definitie OutputType definiëren voor uw geavanceerde functies.
function Get-MyObject
{
[OutputType('My.Object')]
[CmdletBinding()]
param
(
...
De kenmerkwaarde OutputType is slechts een documentatienotitie. Het is niet afgeleid van de functiecode of vergeleken met de werkelijke functie-uitvoer.
De belangrijkste reden waarom u een uitvoertype zou gebruiken, is dat meta-informatie over uw functie uw bedoelingen weerspiegelt. Dingen als Get-Command en Get-Help dat uw ontwikkelomgeving kan profiteren van. Als u meer informatie wilt, bekijkt u de help voor deze informatie: about_Functions_OutputTypeAttribute.
Als u Pester gebruikt om uw functies te testen, is het een goed idee om de uitvoerobjecten te valideren die overeenkomen met uw OutputType. Dit kan variabelen vangen die gewoon naar de pijp vallen als dat niet het geval is.
Gedachten sluiten
De context hiervan ging allemaal om [PSCustomObject], maar veel van deze informatie is van toepassing op objecten in het algemeen.
Ik heb de meeste van deze functies al eerder gezien, maar ze nooit gezien als een verzameling informatie over PSCustomObject. Net deze week stoot ik op een andere en was verrast dat ik het nog niet eerder had gezien. Ik wilde al deze ideeën samenbrengen, zodat u hopelijk het grotere beeld kunt zien en u er rekening mee kunt houden wanneer u ze kunt gebruiken. Ik hoop dat u iets hebt geleerd en een manier kunt vinden om dit in uw scripts te doen.