- 10/05/2020
- 8 minuter att läsa
-
- j
- m
- s
- j
- c
PSCustomObject
s är ett utmärkt verktyg att lägga till i ditt PowerShell-verktygsbälte. Vi börjar med grunderna och arbetar oss fram till de mer avancerade funktionerna. Tanken bakom att använda en PSCustomObject
är att ha ett enkelt sätt att skapa strukturerade data. Ta en titt på det första exemplet så får du en bättre uppfattning om vad det innebär.
Note
Originalversionen av den här artikeln publicerades på bloggen skriven av @KevinMarquette. PowerShell-teamet tackar Kevin för att han delade detta innehåll med oss. Kolla gärna in hans blogg påPowerShellExplained.com.
- Skapa ett PSCustomObject
- Konvertering av en hashtable
- Legacy approach
- Spara till en fil
- Arbeta med egenskaper
- Lägga till egenskaper
- Ta bort egenskaper
- Enumerera egenskapsnamn
- Dynamisk åtkomst till egenskaper
- Konvertera PSCustomObject till en hashtable
- Testa efter egenskaper
- Lägga till objektmetoder
- Objekt vs. värdetyper
- psobject.copy()
- PSTypeName för anpassade objekttyper
- Using DefaultPropertySet (the long way)
- Update-TypeData with DefaultPropertySet
- Update-TypeData with ScriptProperty
- Funktionsparametrar
- Function OutputType
- Avslutande tankar
Skapa ett PSCustomObject
Jag älskar att använda i PowerShell. Att skapa ett användbart objekt har aldrig varit enklare.På grund av detta kommer jag att hoppa över alla andra sätt du kan skapa ett objekt, men jag måste nämna att de flesta av dessa exempel är PowerShell v3.0 och nyare.
$myObject = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Denna metod fungerar bra för mig eftersom jag använder hashtables för nästan allt. Men det finns tillfällen då jag skulle vilja att PowerShell behandlar hashtables mer som ett objekt. Det första stället där du märker skillnaden är när du vill använda Format-Table
eller Export-CSV
och du inser att ahashtable bara är en samling nyckel/värdepar.
Du kan då komma åt och använda värdena som du skulle göra med ett vanligt objekt.
$myObject.Name
Konvertering av en hashtable
När jag ändå är inne på ämnet, visste du att du kan göra så här:
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = $myHashtable
Jag föredrar att skapa objektet från början, men det finns tillfällen då man måste arbeta med ahashtable först. Det här exemplet fungerar eftersom konstruktören tar en hashtable för objektets egenskaper. En viktig notering är att även om den här metoden fungerar är den inte en exakt motsvarighet. Den största skillnaden är att egenskapens ordning inte bevaras.
Legacy approach
Du kanske har sett folk använda New-Object
för att skapa egna objekt.
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = New-Object -TypeName PSObject -Property $myHashtable
Detta sätt är ganska mycket långsammare, men det kan vara ditt bästa alternativ i tidiga versioner av PowerShell.
Spara till en fil
Jag tycker att det bästa sättet att spara en hashtable till en fil är att spara den som JSON. Du kan importera den tillbaka till en
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path$myObject = Get-Content -Path $Path | ConvertFrom-Json
Jag täcker fler sätt att spara objekt till en fil i min artikel omDe många sätten att läsa och skriva till filer.
Arbeta med egenskaper
Lägga till egenskaper
Du kan fortfarande lägga till nya egenskaper till din PSCustomObject
med Add-Member
.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'$myObject.ID
Ta bort egenskaper
Du kan också ta bort egenskaper från ett objekt.
$myObject.psobject.properties.remove('ID')
psobject
är en dold egenskap som ger dig tillgång till metadata för basobjektet.
Enumerera egenskapsnamn
Ibland behöver du en lista över alla egenskapsnamn på ett objekt.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
Vi kan få samma lista från egenskapen psobject
också.
$myobject.psobject.properties.name
Dynamisk åtkomst till egenskaper
Jag har redan nämnt att du kan få direkt åtkomst till egenskapsvärden.
$myObject.Name
Du kan använda en sträng för egenskapsnamnet och det kommer fortfarande att fungera.
$myObject.'Name'
Vi kan ta detta ett steg till och använda en variabel för egenskapsnamnet.
$property = 'Name'$myObject.$property
Jag vet att det ser konstigt ut, men det fungerar.
Konvertera PSCustomObject till en hashtable
För att fortsätta från förra avsnittet kan du dynamiskt gå igenom egenskaperna och skapa en hashtable från dem.
$hashtable = @{}foreach( $property in $myobject.psobject.properties.name ){ $hashtable = $myObject.$property}
Testa efter egenskaper
Om du behöver veta om en egenskap existerar kan du bara kontrollera om egenskapen har ett värde.
if( $null -ne $myObject.ID )
Men om värdet skulle kunna vara $null
kan du kontrollera om den finns genom att kontrollerapsobject.properties
för den.
if( $myobject.psobject.properties.match('ID').Count )
Lägga till objektmetoder
Om du behöver lägga till en skriptmetod till ett objekt kan du göra det med Add-Member
och enScriptBlock
. Du måste använda den automatiska variabeln this
som refererar till det aktuella objektet. Här finns ascriptblock
för att förvandla ett objekt till en hashtable. (samma kod som i det senaste exemplet)
Därefter lägger vi till den i vårt objekt som en skriptegenskap.
Därefter kan vi anropa vår funktion så här:
$myObject.ToHashtable()
Objekt vs. värdetyper
Objekt och värdetyper hanterar inte variabeltilldelningar på samma sätt. Om du tilldelar värdetyper till varandra kopieras endast värdet till den nya variabeln.
$first = 1$second = $first$second = 2
I det här fallet är $first
1 och $second
2.
Objektsvariabler innehåller en referens till det faktiska objektet. När du tilldelar ett objekt till en nyvariabel refererar de fortfarande till samma objekt.
$third = @{Key=3}$fourth = $third$fourth.Key = 4
Om $third
och $fourth
refererar till samma instans av ett objekt är både $third.key
och$fourth.Key
4.
psobject.copy()
Om du behöver en äkta kopia av ett objekt kan du klona det.
$third = @{Key=3}$fourth = $third.psobject.copy()$fourth.Key = 4
Clone skapar en ytlig kopia av objektet. De har olika instanser nu och $third.key
är 3och $fourth.Key
är 4 i det här exemplet.
Jag kallar detta för en ytlig kopia eftersom om du har inbäddade objekt. (där egenskaperna innehåller andra objekt). Endast värdena på den översta nivån kopieras. Barnobjekten refererar till varandra.
PSTypeName för anpassade objekttyper
När vi nu har ett objekt finns det ytterligare några saker vi kan göra med det som kanske inte är lika uppenbara. Det första vi behöver göra är att ge det en PSTypeName
. Detta är det vanligaste sättet jag ser folk göra det på:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Jag upptäckte nyligen ett annat sätt att göra detta från detta inlägg av /u/markekraus. Jag gjorde en liten sökning och fler inlägg om idén från Adam Bertram och Mike Shepard där de talar om detta tillvägagångssätt som gör att du kan definiera det inline.
$myObject = @{ PSTypeName = 'My.Object' Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Jag älskar hur fint detta passar in i språket. Nu när vi har ett objekt med ett korrekt typnamn kan vi göra några fler saker.
Note
Du kan också skapa egna PowerShell-typer med hjälp av PowerShell-klasser. Mer information finns iPowerShell Class Overview.
Using DefaultPropertySet (the long way)
PowerShell bestämmer åt oss vilka egenskaper som ska visas som standard. Många av de inhemska kommandona har en.ps1xml
formateringsfil som gör allt det tunga jobbet. Från det här inlägget av Boe Prox finns det ett annat sätt för oss att göra detta på vårt anpassade objekt genom att bara använda PowerShell. Vi kan ge det enMemberSet
som det ska använda.
Nu när mitt objekt bara faller till skalet kommer det bara att visa dessa egenskaper som standard.
Update-TypeData with DefaultPropertySet
Detta är trevligt men jag såg nyligen ett bättre sätt när jag tittade påPowerShell unplugged 2016 med Jeffrey Snover & Don Jones. Jeffrey användeUpdate-TypeData för att ange standardegenskaperna.
$TypeData = @{ TypeName = 'My.Object' DefaultDisplayPropertySet = 'Name','Language'}Update-TypeData @TypeData
Det är tillräckligt enkelt för att jag nästan skulle kunna komma ihåg det om jag inte hade det här inlägget som en snabbreferens. Nu kan jag enkelt skapa objekt med många egenskaper och ändå ge det en snygg ren bild när jag tittar på det från skalet. Om jag behöver komma åt eller se de andra egenskaperna finns de fortfarande där.
$myObject | Format-List *
Update-TypeData with ScriptProperty
En annan sak som jag fick ut av den videon var att skapa skriptegenskaper för dina objekt. Det här är ett bra tillfälle att påpeka att detta även fungerar för befintliga objekt.
Du kan göra detta innan objektet skapas eller efteråt och det kommer fortfarande att fungera. Det är detta som skiljer detta från att använda Add-Member
med en skriptegenskap. När du använder Add-Member
på det sätt som jag hänvisade till tidigare finns det bara på den specifika instansen av objektet. Den här gäller för alla objekt med denna TypeName
.
Funktionsparametrar
Du kan nu använda dessa anpassade typer för parametrar i dina funktioner och skript. Du kan låta onefunktion skapa dessa anpassade objekt och sedan skicka dem till andra funktioner.
param( $Data )
PowerShell kräver att objektet är av den typ du angett. Ett valideringsfel visas automatiskt om typen inte stämmer överens för att du inte ska behöva testa det i din kod. Ett bra exempel på att låta PowerShell göra det den är bäst på.
Function OutputType
Du kan också definiera ett OutputType
för dina avancerade funktioner.
function Get-MyObject{ param ( ...
Värdet för attributet OutputType är bara en dokumentationsanteckning. Det härleds inte från funktionskoden och jämförs inte med den faktiska funktionsutgången.
Den främsta anledningen till att du använder en utdatatyp är att metainformationen om din funktion återspeglar dina avsikter. Saker som Get-Command
och Get-Help
som din utvecklingsmiljö kan dra nytta av. Om du vill ha mer information kan du ta en titt på hjälpen för det: about_Functions_OutputTypeAttribute.
Med det sagt, om du använder Pester för att enhetstesta dina funktioner så skulle det vara en bra idé att validera att utdataobjekten matchar din OutputType. Detta skulle kunna fånga upp variabler som bara hamnar i röret när de inte borde göra det.
Avslutande tankar
Sammanhanget av detta handlade om , men mycket av den här informationen gäller för objekt i allmänhet.
Jag har sett de flesta av de här funktionerna i förbigående tidigare, men jag har aldrig sett dem presenterade som en samling av information om PSCustomObject
. Så sent som förra veckan snubblade jag över ytterligare en och blev förvånad över att jag inte hade sett den tidigare. Jag ville samla alla dessa idéer så att ni förhoppningsvis kan se helheten och bli medvetna om dem när ni har möjlighet att använda dem. Jag hoppas att ni har lärt er något och kan hitta ett sätt att arbeta in detta i era manus.