Seriál Windows PowerShell: Tvorba vlastních objektů (část 27.)

V minulém díle jsme vytvářeli textový výstup pomocí operátoru formátování. Dnes se podíváme na opačný pól – vytvoříme si vlastní objekt z daného textového výstupu.

Již několikrát jsem zmiňoval, že PowerShell je postaven nad objekty a s objekty dokáže velice efektivně pracovat. Problém občas nastává, pokud vytváříte vlastní skript nebo funkci a na výstupu chcete mít vlastní objekty. V tomto případě se hodí cmdlet New-Object. Tento cmdlet má jeden povinný parametr, TypeName, tento parametr určuje typ objektu – ve většině našich případů zde zadejte PSObject. Tím vytvoříte objekt typu System.Management.Automation.PSCustomObject – bohužel vytvoření objektu bez vlastností nebo metod nedává moc smysl:

PS C:\> New-Object -TypeName PSObject

PS C:\> $a = New-Object -TypeName PSObject
PS C:\> $a

PS C:\> $a.GetType().FullName
System.Management.Automation.PSCustomObject
PS C:\> $a | Get-Member

TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()

K tomuto objektu můžeme vlastnosti přidávat později za běhu skriptu, například takto:

[20]: $a = $a | Add-Member -MemberType NoteProperty -Name Vlastnost -Value 'Nejaky text' -PassThru
[21]: $a

Vlastnost
---------
Nejaky text

[22]: $a | Get-Member

   TypeName: System.Management.Automation.PSCustomObject

Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Vlastnost NoteProperty System.String Vlastnost=Nejaky text

Pomocí cmdletu Add-Member jsme k původnímu objektu přidali vlastnost Vlastnost a přiřadili jsme jí určitou hodnotu. I když je tento způsob vytváření objektů možný, existuje naštěstí lepší volba. Tou je použití parametru Parameter při vytváření objektu pomocí New-Object. Pojďme si vytvořit nový objekt:

PS C:\> New-Object -TypeName PSObject -Property @{ a=1; b=2; c=3 }

a b c
- - -
1 2 3

PS C:\> $b = New-Object -TypeName PSObject -Property @{ a=1; b=2; c=3 }
PS C:\> $b | Get-Member

   TypeName: System.Management.Automation.PSCustomObject

Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
a NoteProperty System.Int32 a=1
b NoteProperty System.Int32 b=2
c NoteProperty System.Int32 c=3

Parameter očekává hash tabulku, jejíž dvojice klíč-hodnota se stanou vlastností a její hodnotou v novém objektu. Hash tabulku si samozřejmě můžeme vytvořit předem a pak ji uvést jako hodnotu parametru.

PS C:\> $prop = @{
>> a=1
>> b=2
>> c=3
>> }
>>
PS C:\> $prop

Name Value
---- -----
a 1
b 2
c 3

PS C:\> $prop.GetType().FullName
System.Collections.Hashtable
PS C:\> New-Object -TypeName PSObject -Property $prop

a b c
- - -
1 2 3

Vidíte, že tvorba nového objektu proběhla ve dvou krocích. Nejdříve jsme v hash tabulce určili, jaké vlastnosti bude nový objekt obsahovat a ve druhém kroku jsme tyto vlastnosti použili při vytváření objektu typu PSObject. Tím jsme si oddělili „starosti“ s přemýšlením o vlastnostech objektu. Zkusme jednoduchý příklad.

function Get-TNObject
{
    param(
        $ComputerName = $env:COMPUTERNAME
    )

    $os = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem

    $prop = @{
        ComputerName = $ComputerName
        OSName = $os.Caption
        OSVersion = $os.Version
        ScanTime = Get-Date
    }

    New-Object -TypeName PSObject -Property $prop

}

Funkce Get-TNObject očekává na vstupu jméno počítače, který testujeme. Uvnitř funkce zavoláme cmdlet Get-WmiObject a zjistíme informace o operačním systému. Do hash tabulky poté vložíme informace o jménu počítače, jeho operačním systému a verzi a také datum, kdy jsme tento sken spustili. Na posledním řádku poté vytváříme objekt. Tento objekt je dále pouštěn do roury a výsledky funkce tam můžeme zpracovat jiným cmdletem. Použití je následující:

PS C:\> Get-TNObject

OSVersion ScanTime OSName ComputerName
--------- -------- ------ ------------
5.1.2600 05-Jun-12 11:29:14 Microsoft Windows XP Profe... MAKOVEC-40

PS C:\> Get-TNObject localhost

OSVersion ScanTime OSName ComputerName
--------- -------- ------ ------------
5.1.2600 05-Jun-12 11:29:18 Microsoft Windows XP Profe... localhost

PS C:\> Get-TNObject localhost | Format-Table -AutoSize

OSVersion ScanTime OSName ComputerName
--------- -------- ------ ------------
5.1.2600 05-Jun-12 11:29:32 Microsoft Windows XP Professional localhost

Pokud bychom chtěli zpracovávat více počítačů, můžeme použít například cmdlet ForEach-Object.

PS C:\> 'localhost',$env:COMPUTERNAME,'makovec-40','192.168.100.100' |% { Get-TNObject $_; Sleep 2 }

OSVersion ScanTime OSName ComputerName
--------- -------- ------ ------------
5.1.2600 05-Jun-12 11:34:59 Microsoft Windows XP Profe... localhost
5.1.2600 05-Jun-12 11:35:01 Microsoft Windows XP Profe... MAKOVEC-40
5.1.2600 05-Jun-12 11:35:03 Microsoft Windows XP Profe... makovec-40
5.1.2600 05-Jun-12 11:35:05 Microsoft Windows XP Profe... 192.168.100.100

Pro kontrolu jsem přidal čekání dvě vteřiny, aby bylo vidět, že ScanTime se nám opravdu mění v závislosti na volání funkce. Jak jsem již zmiňoval – výstupem jsou objekty a můžeme s nimi dále libovolně pracovat.

PS C:\> 'localhost',$env:COMPUTERNAME, 'makovec-40','192.168.100.100' |% { Get-TNObject $_ } | Sort ComputerName

OSVersion ScanTime OSName ComputerName
--------- -------- ------ ------------
5.1.2600 05-Jun-12 11:38:28 Microsoft Windows XP Profe... 192.168.100.100
5.1.2600 05-Jun-12 11:38:28 Microsoft Windows XP Profe... makovec-40
5.1.2600 05-Jun-12 11:38:28 Microsoft Windows XP Profe... MAKOVEC-40
5.1.2600 05-Jun-12 11:38:28 Microsoft Windows XP Profe... localhost

PS C:\> 'localhost',$env:COMPUTERNAME, 'makovec-40','192.168.100.100' |% { Get-TNObject $_ } | Sort ComputerName | ft -AutoSize

OSVersion ScanTime OSName ComputerName
--------- -------- ------ ------------
5.1.2600 05-Jun-12 11:38:43 Microsoft Windows XP Professional 192.168.100.100
5.1.2600 05-Jun-12 11:38:43 Microsoft Windows XP Professional makovec-40
5.1.2600 05-Jun-12 11:38:43 Microsoft Windows XP Professional MAKOVEC-40
5.1.2600 05-Jun-12 11:38:43 Microsoft Windows XP Professional localhost

Tato technika vytváření objektů za běhu funkce nebo skriptu je velice užitečná. Vzhledem k tomu, že v PowerShellu pracujeme s objekty velice často, byla by škoda, pokud by vaše funkce/skripty pouze posílaly textový výstup pomocí Write-Host. Až budete příště zpracovávat nějaká data, vzpomeňte si na New-Object a zkuste jej využít.

- David Moravec