Vše, co jste chtěli vědět o PSCustomObject
PSCustomObject
je skvělý nástroj pro přidání do pásu nástrojů PowerShellu. Začněme základy a pusťme se do pokročilejších funkcí. Cílem použití metody a PSCustomObject
je vytvořit strukturovaná data jednoduchým způsobem. Podívejte se na první příklad a budete mít lepší představu o tom, co to znamená.
Poznámka:
Původní verze tohoto článku se objevila na blogu napsané @KevinMarquette. Tým PowerShellu děkujeme Kevinovi za sdílení tohoto obsahu s námi. Prosím, podívejte se na jeho blog na PowerShellExplained.com.
Vytvoření objektu PSCustomObject
Miluji používání [PSCustomObject]
v PowerShellu. Vytvoření použitelného objektu nebylo nikdy jednodušší.
Z tohoto důvodu přeskočím všechny další způsoby, jak můžete vytvořit objekt, ale musím zmínit, že většina těchto příkladů je PowerShell v3.0 a novější.
$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Tato metoda funguje dobře pro mě, protože pro všechno používám hashtables. Ale někdy bych chtěl, aby PowerShell zacháněl s hashtables spíše jako s objektem. První místo, kde si všimnete rozdílu, je, když chcete použít Format-Table
nebo Export-CSV
a zjistíte, že hashtable je jen kolekce párů klíč/hodnota.
Pak můžete přistupovat k běžným objektům a používat je jako normální objekt.
$myObject.Name
Převod hashovatelné tabulky
Zatímco jsem na tématu, víte, že to můžete udělat:
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = [pscustomobject]$myHashtable
Dávám přednost vytvoření objektu od začátku, ale někdy musíte nejprve pracovat s hashtable. Tento příklad funguje, protože konstruktor přebírá hashtable pro vlastnosti objektu. Jednou z důležitých poznámek je, že i když tato metoda funguje, nejedná se o přesný ekvivalent. Největší rozdíl spočívá v tom, že pořadí vlastností není zachováno.
Pokud chcete zachovat pořadí, přečtěte si téma Uspořádané hashtables.
Starší přístup
Možná jste viděli, jak lidé používají New-Object
k vytváření vlastních objektů.
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = New-Object -TypeName PSObject -Property $myHashtable
Tento způsob je poměrně pomalejší, ale může být nejlepší volbou v dřívějších verzích PowerShellu.
Ukládání do souboru
Najdu nejlepší způsob, jak uložit hashtable do souboru, je uložit ho jako JSON. Můžete ho naimportovat zpět do [PSCustomObject]
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json
Probírám další způsoby ukládání objektů do souboru v článku o mnoha způsobech čtení a zápisu do souborů.
Práce s vlastnostmi
Přidání vlastností
Nové vlastnosti můžete stále přidávat do svého PSCustomObject
souboru .Add-Member
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'
$myObject.ID
Odebrání vlastností
Můžete také odebrat vlastnosti z objektu.
$myObject.psobject.properties.remove('ID')
Je .psobject
vnitřní člen, který poskytuje přístup k metadatům základního objektu. Další informace o vnitřních členech najdete v tématu about_Intrinsic_Members.
Výčet názvů vlastností
Někdy potřebujete seznam všech názvů vlastností v objektu.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
Tento seznam můžeme získat i mimo psobject
tuto vlastnost.
$myobject.psobject.properties.name
Poznámka:
Get-Member
vrátí vlastnosti v abecedním pořadí. Pomocí operátoru přístupu člena k vytvoření výčtu názvů vlastností vrátí vlastnosti v pořadí, v jakém byly definovány v objektu.
Dynamický přístup k vlastnostem
Už jsem zmínil, že máte přístup k hodnotám vlastností přímo.
$myObject.Name
Pro název vlastnosti můžete použít řetězec a bude stále fungovat.
$myObject.'Name'
Můžeme to udělat ještě jeden krok a pro název vlastnosti použít proměnnou.
$property = 'Name'
$myObject.$property
Vím, že to vypadá divně, ale funguje to.
Převedení objektu PSCustomObject na hashtable
Pokud chcete pokračovat z poslední části, můžete dynamicky procházet vlastnosti a vytvořit z nich hashovací tabulku.
$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
$hashtable[$property] = $myObject.$property
}
Testování vlastností
Pokud potřebujete vědět, jestli vlastnost existuje, můžete jen zkontrolovat, jestli má tato vlastnost hodnotu.
if( $null -ne $myObject.ID )
Pokud ale můžete $null
zkontrolovat, jestli hodnota existuje, zkontrolujte psobject.properties
ji.
if( $myobject.psobject.properties.match('ID').Count )
Přidání metod objektů
Pokud potřebujete přidat metodu skriptu do objektu, můžete to udělat s Add-Member
a .ScriptBlock
Musíte použít automatickou proměnnou this
odkaz na aktuální objekt. Tady je funkce scriptblock
pro převod objektu na hashtable. (stejný kód jako poslední příklad)
$ScriptBlock = {
$hashtable = @{}
foreach( $property in $this.psobject.properties.name )
{
$hashtable[$property] = $this.$property
}
return $hashtable
}
Pak ho přidáme do objektu jako vlastnost skriptu.
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
}
Add-Member @memberParam
Pak můžeme volat naši funkci takto:
$myObject.ToHashtable()
Objekty vs. Typy hodnot
Objekty a typy hodnot nezpracují přiřazení proměnných stejným způsobem. Pokud k sobě přiřadíte typy hodnot, zkopíruje se do nové proměnné pouze hodnota.
$first = 1
$second = $first
$second = 2
V tomto případě $first
je 1 a $second
je 2.
Proměnné objektu obsahují odkaz na skutečný objekt. Když přiřadíte jeden objekt nové proměnné, budou stále odkazovat na stejný objekt.
$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4
Vzhledem k tomu, že $third
a $fourth
odkazuje na stejnou instanci objektu, obě $third.key
a $fourth.Key
jsou 4.
psobject.copy()
Pokud potřebujete skutečnou kopii objektu, můžete ji naklonovat.
$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4
Klon vytvoří mělkou kopii objektu. Teď mají různé instance a $third.key
jsou 3 a $fourth.Key
v tomto příkladu jsou 4.
Říkám to mělké kopii, protože pokud máte vnořené objekty (objekty s vlastnostmi obsahují jiné objekty), zkopírují se pouze hodnoty nejvyšší úrovně. Podřízené objekty budou vzájemně odkazovat.
PSTypeName pro vlastní typy objektů
Když teď máme objekt, můžeme s ním udělat několik dalších věcí, které nemusí být tak zřejmé. První věc, kterou musíme udělat, je dát to PSTypeName
. To je nejběžnější způsob, jak to vidím u lidí:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Nedávno jsem objevil další způsob, jak to udělat z Redditor u/markekraus
. Mluví o tomto přístupu, který vám umožní definovat ho v textu.
$myObject = [PSCustomObject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Miluju, jak pěkně to zapadá do jazyka. Teď, když máme objekt se správným názvem typu, můžeme udělat něco dalšího.
Poznámka:
Můžete také vytvořit vlastní typy PowerShellu pomocí tříd PowerShellu. Další informace najdete v tématu Přehled třídy PowerShellu.
Použití defaultPropertySet (dlouhá cesta)
PowerShell se rozhodne, jaké vlastnosti se mají ve výchozím nastavení zobrazit. Spousta nativních příkazů má .ps1xml
formátovací soubor , který dělá všechny náročné úlohy. Z tohoto příspěvku od Boe Prox je další způsob, jak to udělat u našeho vlastního objektu pomocí jen PowerShellu. Můžeme ji MemberSet
dát k použití.
$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
Když teď objekt právě spadá do prostředí, zobrazí se ve výchozím nastavení jenom tyto vlastnosti.
Update-TypeData s defaultPropertySet
To je pěkné, ale nedávno jsem viděl lepší způsob, jak pomocí Update-TypeData určit výchozí vlastnosti.
$TypeData = @{
TypeName = 'My.Object'
DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData
To je dost jednoduché, že bych si to skoro vzpomněl, pokud jsem neměl tento příspěvek jako stručný odkaz. Nyní mohu snadno vytvářet objekty s mnoha vlastnostmi a stále dát pěkný čistý pohled při prohlížení z prostředí. Pokud potřebuji získat přístup k těmto dalším vlastnostem nebo je zobrazit, jsou tam pořád.
$myObject | Format-List *
Update-TypeData pomocí ScriptProperty
Něco jiného jsem z tohoto videa vyšel z vytváření vlastností skriptu pro vaše objekty. To by bylo dobrý čas upozornit na to, že to funguje i pro existující objekty.
$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData
Můžete to udělat před vytvořením nebo po vytvoření objektu a bude fungovat i nadále. To se liší od použití Add-Member
s vlastností skriptu. Když použijete Add-Member
způsob, jak jsem odkazoval dříve, existuje pouze na této konkrétní instanci objektu. Tento objekt platí pro všechny objekty s tímto TypeName
objektem .
Parametry funkce
Tyto vlastní typy teď můžete použít pro parametry ve svých funkcích a skriptech. Můžete mít jednu funkci, která tyto vlastní objekty vytvoří, a pak je předat do dalších funkcí.
param( [PSTypeName('My.Object')]$Data )
PowerShell vyžaduje, aby byl objekt typem, který jste zadali. Pokud se typ automaticky neshoduje s krokem testování v kódu, vyvolá chybu ověření. Skvělý příklad, jak nechat PowerShell dělat to, co dělá nejlépe.
OutputType funkce
Můžete také definovat OutputType
pokročilé funkce.
function Get-MyObject
{
[OutputType('My.Object')]
[CmdletBinding()]
param
(
...
Hodnota atributu OutputType je pouze poznámka k dokumentaci. Není odvozen z kódu funkce nebo ve srovnání se skutečným výstupem funkce.
Hlavním důvodem, proč byste použili typ výstupu, je, aby meta informace o funkci odrážely vaše záměry. Get-Command
Například a Get-Help
že vaše vývojové prostředí může využívat výhod. Pokud chcete získat další informace, podívejte se na nápovědu: about_Functions_OutputTypeAttribute.
Pokud k testování funkcí používáte Pester, pak by bylo vhodné ověřit, že výstupní objekty odpovídají vašemu outputType. To by mohlo zachytit proměnné, které právě spadají do kanálu, když by neměly.
Závěrečné myšlenky
Kontext toho bylo vše o [PSCustomObject]
, ale spousta těchto informací platí pro objekty obecně.
Viděl jsem většinu těchto funkcí předávat dříve, ale nikdy jsem je neviděl jako kolekci informací o PSCustomObject
. Jen tento minulý týden jsem narazil na další a byl překvapen, že jsem ho neviděl předtím. Chtěl jsem všechny tyto nápady spojit, abyste mohli vidět větší obraz a být si o nich vědomi, když máte příležitost je použít. Doufám, že jste se něco naučili a můžete najít způsob, jak to udělat do vašich skriptů.