Sdílet prostřednictvím


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 TypeNameobjektem .

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ů.