Szkriptek írása a gyakorlatban

Szkripteket a gyakorlatban ritkán írunk magával a PowerShell konzolablakon, még csak nem is a Notepad az ideális eszköz, hanem valamilyen szkriptszerkesztő. A PowerShell 2.0 beépítet szkriptszerkesztője (ld. a 1.1.12 A grafikus PowerShell felület – Integrated Scripting Environment fejezet), vagy a 2.3.1 PowerGUI, PowerGUI Script Editor fejezetben már említett PowerGUI Script Editora talán a legegyszerűbb ilyen jellegű eszközök, amelyek ráadásul pont eleget tudnak ahhoz, hogy hatékonyan használhassuk őket. Ráadásul mindkettő ingyenes!

PowerGUI Script Editor

A korábbi „osztás” szkriptpéldát kicsit még kiegészítettem, mindez így néz ki a PowerGUI Script Editorban:

44 . ábra Szkriptem a PowerGUI Script  Editorában

Nyomtatásban nem biztos, hogy színes, de a képernyőn látható a fenti ábra színeinek kavalkádja: külön színnel jelzi a program a kulcsszavakat, cmdleteket, változókat, megjegyzéseket, operátorokat.

Az eszközsorban látható „Start Debugging (F5)” gombbal lehet futtatni ott helyben a szkriptet. Az eszközsorban, a beviteli mezőben lehet paramétereket is átadni (a képen ez most „15 7”). A futás során generálódó output kikerül a jobb alsó ablakrészbe és a belső változók tartalma is azonnal megtekinthető a baloldali részben. A jobb szemléltethetőség kedvéért még egy felesleges $c változót is felvettem, hogy látható legyen az, ahogyan a „Locals” részben a változókban tárolt objektumok tulajdonságai is azonnal elérhetők és kiolvashatók, nem kell állandóan get-member-t futtatni.

Megjegyzések, kommentezés (#, <# #>)

A fájlba mentett parancssorozatainkat érdemes komment ekkel ellátni, hogy ha pár hónap után nyitjuk meg őket, akkor is értsük, hogy mit csinál a szkript, a paraméterek, változók hogyan használhatók.

A komment jele a #  jel.

[10] PS C:\old>$a = 5 #értékadás

[11] PS C:\old>$a

5

A fejlesztés során a megjegyzéseket, kommenteket arra is felhasználhatjuk, hogy különböző kódváltozatok tesztelésekor az egyik változatot „kikommentezzük”, míg a másikat teszteljük, aztán meg cserélünk, és megnézhetjük, hogy a másik változat hogyan működik. Vagy az is gyakori, hogy a szkriptünk kifejlesztése során jóval több átmeneti változó és állapot értékét íratjuk ki, míg a végleges verziónál ezt már nem szeretnénk. Ilyenkor szintén jól jön a „kikommentezési” lehetőség. Kitörölni nem akarjuk ezeket a kiíratási lehetőségeket, mert hátha jól jönnek majd a szkript továbbfejlesztésekor.

Ezt a gyors ki-be kommentezést jól támogatja a PowerGUI Script Editora, az eszközsorban található gombokkal egy kattintással tudjuk ezt ki-be kapcsolni, ráadásul több sor kijelölésével is működik.

A # jel hatása csak az adott sorra érvényes a sor végéig. Ha többsoros kommenteket szeretnénk beszúrni, akkor vagy minden sort külön ellátunk ilyen jellel, vagy használhatjuk a PowerShell 2.0 új lehetőségét a többsoros megjegyzés jelölőt (<# #> ):

<# Hosszú megjegyzés,

ami egy új lehetőség a

PowerShell 2.0-ban. #>

$a = 1

Majd a 2.5.10 Paraméterek vizsgálata megszakítás közben

Gyakran szükséges hibakeresés közben paraméterek értékeinek vizsgálatára, ami bizonyos eseteknem nem is olyan egyszerű feladat, mint amennyire elsőre látszik.

Vegyók a következő példafüggvényt:

function Test-Param {

[cmdletbinding()]

param(

    [Parameter(ValueFromPipeline = $true)]

        [int]$inputNumber,

    [Parameter()]

        [int]$szorzó = 2

)

process{

    $inputNumber * $szorzó

}

}

Elmentem a függvénydefiníciót egy szkriptként, egy megszakítási pontot helyezek el a process blokkon belül, majd végrehajtom a szkriptet:

98. ábra Paraméterek vizsgálatának előkészítése ISE-ben

Ezután meghívva a függvényt a futás megáll a kijelölt sornál, de ha a debug prompt mellett lekérdezem a $PSBoundParaméter  változót érdekes módon nem kapok semmit:

PS C:\> 1,4 | Test-Param -szorzó 3

Hit Line breakpoint on 'C:\Users\Tibi\OneDrive\PS\test-param.ps1:10'

[DBG]: PS C:\>> $PSBoundParameters

 

Ennek az lehet az oka, hogy a debug környezetnek saját $PSBoundParameters változója van és mivel ott nem haszálunk semmilyen paraméter, természetesen üres eredményt kapunk. Szerencsére egy másik módon is elérhetjük az átadott paraméterek lekérdezését, a $PSCmdlet.MyInvocation.BoundParameters változón keresztül:

[DBG]: PS C:\>> $PSCmdlet.MyInvocation.BoundParameters

 

Key         Value

---         -----

szorzó          3

inputNumber     1

Itt már láthatjuk az $inputNumber aktuális értékét és a $szorzó megadott értékét is. De mi van akkor, ha nem adunk meg a $szorzó-nak explicit értéket, hanem az alaphelyzet szerinti értéket szeretnénk használni:

PS C:\> 1,4 | Test-Param

Hit Line breakpoint on 'C:\Users\Tibi\OneDrive\PS\test-param.ps1:10'

[DBG]: PS C:\>> $PSCmdlet.MyInvocation.BoundParameters

 

Key         Value

---         -----

inputNumber     1

Sajnos ilyenkor  a BoundParameters nem mutat semmit. Lehetnek olyan helyzetek, amikor jó lenne ilyenkor az alaphelyzet szerinti érékeket is, például ha naplózni szeretnénk az értékek használatát, hogy később is lássuk, hogy ki hogyan milyen paraméterértékekkel használta a függvényt. Ehhez első lépésként a begin blokk egyszerű bővítésével a kívánt eredményhez juthatunk:

function Test-Param {

[cmdletbinding()]

param(

    [Parameter(ValueFromPipeline = $true)]

        [int]$inputNumber,

    [Parameter()]

        [int]$szorzó = 2

)

begin {

    if(!$PSBoundParameters.ContainsKey("szorzó") -and $szorzó){

        $PSBoundParameters.szorzó = $szorzó

    }

}

process{

    $inputNumber * $szorzó

}

}

 Itt az történik, hogy ha a paraméterek között nem szerepel a szorzó, de ennek ellenére van neki értéke, akkor kibővítem a $PSBoundParameters hashtáblát ezze a hiányzó információval. Ha újból futtatjuk a függvényt, a megszakítási pontnál már megkapjuk az alaphelyzetben használt paramétert és annak értékét is:

PS C:\> Test-Param -inputNumber 5

Hit Line breakpoint on 'C:\PowerShell\testparamszkript.ps1:15'

[DBG]: PS C:\>> $PSCmdlet.MyInvocation.BoundParameters

 

Key         Value

---         -----

inputNumber     5

szorzó          2

Ez jó megoldás, de a függvényünk karbantartását megnehezíti, mert ha például átnevezzük a $szorzó paraméterünket $multiplier-re, akkor nem szabad elfeledkezni arról, hogy az előbb betett begin blokkbeli hivatkozásokat is módosítsuk, márpedig ott négyszer is szerepel a paraméter neve. Nem beszélve arról sem, ha sok olyan paraméterünk van, amelyeknek alaphelyzet szerinti értéke van. Erre lehet megoldás az alábbi dinamikus módszer, amellyel a függvény a sajár forráskódját elemzi és kideríti, hogy melyek a dinamukis paraméterek. Ezt most itt nem akarom részletesen megmagyarázni, majd a 2.32.3 Absztrakt szintaxis fa - AST fejezetben lesz szó a használt AST techológiáról.

function Test-Param {

[cmdletbinding()]

param(

    [Parameter(ValueFromPipeline = $true)]

        [int]$inputNumber,

    [Parameter()]

        [int]$szorzó = 2,

    [Parameter()]

        $mikor = (Get-date)

)

begin {

    $ast = (Get-Command $MyInvocation.MyCommand).ScriptBlock.Ast 

    $varswithdefaultvalue = $ast.FindAll({$true}, $false)[0].body.findall({ $args[0] -is [System.Management.Automation.Language.ParameterAst] }, $false) | 

                                Where-Object { $_.DefaultValue } | 

                                    ForEach-Object {$_.name.variablepath.userpath} 

    if($varswithdefaultvalue){ 

        foreach($var in $varswithdefaultvalue){ 

            if(!$PSBoundParameters.ContainsKey($var)){ 

                $PSBoundParameters.$var = Get-Variable -Name $var -ValueOnly 

            } 

        } 

    } 

}

process{

    $inputNumber * $szorzó

}

}

Ha az eredeti függvényhez képest berakok egy új paramétert alaphelyzet szerinti értékkel, akkor a begin blokk változtatása nélkül automatikusan kiegészül a BoundParameters lista ezzel:

PS C:\> Test-Param -inputNumber 5

Hit Line breakpoint on 'C:\PowerShell\testparamszkript.ps1:25'

[DBG]: PS C:\>> $PSCmdlet.MyInvocation.BoundParameters

 

Key                        Value

---                        -----

inputNumber                    5

szorzó                         2

mikor       2016.02.28. 13:41:17

Még jobb megoldás talán a Get-Command segítségével való paraméterfelderítés:

function ParamsDefaultÉrtékekkel {

param(

    [parameter(ParameterSetName = "egy")]

    $egy,

    [parameter(ParameterSetName = "egy")]

    $kettő = 2,

    [parameter(ParameterSetName = "egy")]

    $üres,

    [parameter(ParameterSetName = "másik")]

    $három

)

    $defaults = @{}

    (get-command $MyInvocation.MyCommand.Name).Parameters.GetEnumerator() |

                    Where-Object {!$PSBoundParameters.ContainsKey($_.key) -and (Get-Variable -Name $_.key -Scope Local -ErrorAction Ignore)} |

                        ForEach-Object {$defaults.($_.key) = Get-Variable -Name $_.key -ValueOnly -Scope local}

 

    Write-Host "Paraméterek megadott értékekkel:"

    $PSBoundParameters | Out-Default

 

    Write-Host "Paraméterek default értékekkel:"

 

    $defaults | Out-Default

}

Ha ezt meghívom egy explicit paraméterrel, akkor ezt kapom:

PS C:\> ParamsDefaultÉrtékekkel -egy 1

Paraméterek megadott értékekkel:

 

Key Value

--- -----

egy     1

 

 

Paraméterek default értékekkel:

 

Name                           Value

----                           -----

üres

kettő                          2

három                          3

A $PSBoundParameters változóban ott van az explicit paraméterem, a $defaults-ba pedig én raktam bele azokat, amelyek léteznek, mint változók a függvény érvényességi területén a függvény objektumának paramér tulajdonsága alapján.

Itt egy érdekes dologra hívnám fel a figyelmet. Ugyan én az „egy” nevű paraméterkészletet használtam, ennek ellenére a $három paraméterem is megkapta az alaphelyzet szerinti értéket! Ez számomra meglepő volt, mert én azt feltételeztem, hogy ilyenkor a „másik” paraméterkészlet elemeivel nem is foglalkozik a PowerShell, de ez nincsen így.

Megjegyzés:

Ráadásul ez PowerShell 2.0-ban másképp volt, ha ugyanezt PS 2.0-ban futtatjuk, akkor a $három nem fog szerepelni a paraméterek között:

PS C:\WINDOWS\system32> ParamsDefaultÉrtékekkel -egy 1

Paraméterek megadott értékekkel:

 

Key                                                                      Value

---                                                                      -----

egy                                                                          1

 

 

Paraméterek default értékekkel:

 

Name                           Value

----                           -----

üres

kettő                          2

Érdekes, erről a kompatibilitási különbségről nem tudtam.

Súgó készítése fejezetben látni fogjuk, hogy a megjegyzésekkel profi súgót is készíthetünk szkriptjeinkhez, függvényeinknek.



Word To HTML Converter