Hibakeresés háttérfolyamatokban és távoli munkamenetekben

PowerShell 5.0-nál korábbi verziók esetében nem volt könnyű dolgunk háttérfolyamatként futó vagy távoli módon futtatott szkriptek hibafelderítésében. Az általános módszer az volt, hogy a háttérben vagy távol futó szkripteket előtérben futtattuk, és ott használtuk a megszakítási pontokat és egyéb lehetőségeket. Ez akkor volt problematikus, amikor pont a paraméterátadással vagy az eredmények átvételével kapcsolatban gyanakodtunk hibákra, hiszen a normál módon futtatott szkriptekkel az így előforduló hibalehetőségek nem voltak szimulálhatók.

PowerShell 5.0-ban már teljesértékű módon, akár az ISE grafikus szerkesztőben is könnyen kereshetjük a hibákat.

Hibakeresés háttérfolyamatokban

Háttérfolyamatok esetében nagyon egyszerű a dolgunk. Nézzünk egy nagyon egyszerű példát:

$script = {

    $a = "valami"

 

    Wait-Debugger

 

    Write-Host "haliho"

}

 

Start-Job -ScriptBlock $script

Látható, hogy itt megszakítási pont helyett a Wait-Debugger cmdlettel szakítom meg a futtatást. Ha ezt elindítom, majd lekérdezem a futó háttérfolyamatokat, akkor ezt látom:

PS C:\PowerShell> Get-Job

 

Id     Name            PSJobTypeName   State         HasMoreData     Location 

--     ----            -------------   -----         -----------     -------- 

10     Job10           BackgroundJob   AtBreakpoint  True            localhost

Egy új státus jelent meg, az „AtBreakpoint”, ami azt mutatja, hogy az adott háttérfolyamat a hibakeresésre vár. Ezt indítani a Debug-Job  cmdlettel tudjuk:

PS C:\PowerShell> Debug-Job -Id 10

Stopped at: Write-Host "haliho"

 És innentől használhatjuk a továbblépés, folytatás és egyéb lehetőségeket. Még látványosabb a dolog, ha a héttérfolyamat szkrtiptblokkját elmentjük fájlként, és azt futtatjuk háttérfolyamatként:

Set-Content -Path C:\PowerShell\job.ps1 -Value $script

Start-Job -ScriptBlock {C:\PowerShell\job.ps1}

Itt szintén megáll a futtatás és szintén el kell indítani a debugger-t:

PS C:\PowerShell> Debug-Job -Id 12

 De ilyenkor automatikusan betöltődik az elmentett szkript az ISE-ben egy újabb fülön és megjelenik a sárga héttérrel kiemelt sor:

100 . ábra Elmentett szkript háttérben futtatásakor teljes értékű a hibakeresés

Azért még mindig lehetne fokozni a hibakeresési élményt azzal, hogy az előtérben történő lépésenkénti végrehajtásnál át tudnánk lépni a Start-Job sorából a háttérben futó szkript lépésenkénti végrehajtásába, de ez sajnos még nem megy, muszáj Wait-Debugger-t tenni oda.

Az előző fejezetben látott „BreakAll” funkciót szintén ellátja a Debug-Job cmdlet. Ha a háttérfolyamatunk hosszabb ideig fut és nem raktunk be Wait-Debugger-t, akkor a Debug-Job erőszakkal is megállítja a háttérfolyamatot és belép hibakeresési módba.

Ez a hibakeresés akkor is működik, ha nem is én indítottam el a PowerShell processzt. A Get-PSHostProcessInfo  cmdlet segítségével fel tudom mérni, hogy melyek azok a processzek, amik a PowerShell-t futtatják, lehetnek ezek akár háttérfolyamatok (job), powershell.exe vagy ISE, akármi. Most épp egy ISE a folyamat, amit szeretnék elemezgetni:

PS C:\> Get-PSHostProcessInfo

 

ProcessName    ProcessId AppDomainName    MainWindowTitle

-----------    --------- -------------    ---------------

powershell          8020 DefaultAppDomain Windows PowerShell

powershell_ise     19804 DefaultAppDomain Windows PowerShell ISE

Ennek az ISE folyamatnak az azonosítója 19804. Hozzá tudok csatlakozni ehhez a processzhez az Enter-PSHostProcess  segítségével:

 

PS C:\> Enter-PSHostProcess -Id 19804

[Process:19804]: PS C:\Users\Tibi\Documents> Get-Runspace

Ilyenkor a prompt is megváltozik. Ilyenkor mi nem ugyanabba a fő runspace-be csatlakozunk be, hanem egy új nyílik számunkra. Ezeket a runspace-eket felmérhetjük:

[Process:19804]: PS C:\Users\Tibi\Documents> Get-Runspace

 

 Id Name            ComputerName    Type          State         Availability

 -- ----            ------------    ----          -----         ------------

  1 Runspace1       localhost       Local         Opened        Busy

  2 RemoteHost      localhost       Local         Opened        Busy

A RemoteHost nevű runspace az, ami most megnyílt számunkra, tehát abban vagyok épp most benne. Ha szeretném az ISE-ben futó szkriptemet debugolni, akkor a 1-esbe kell belépjek a Debug-Runspace  cmdlettel:

[Process:19804]: PS C:\Users\Tibi\Documents> Debug-Runspace -Id 1

Debugging Runspace: Runspace1

To end the debugging session type the 'Detach' command at the debugger prompt,

or type 'Ctrl+C' otherwise.

 

At line:1 char:7

+ while($true){Get-Random; Start-Sleep 1}

+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Itt mutatja is, hogy hol állt éppen meg a szkriptem, tudnék a szokásos debug parancsokkal operálni. Ha a $PID változót megnézem, akkor látszik, hogy tényleg az ISE processzben vagyok benne:

[DBG]: [Process:19804]: [Runspace1]: PS Course:\>> $PID

19804

Ha kész vagyok a hibakereséssel, akkor a detach  paranccsal léphetek ki a debug runspace-ből, ilyenkor folytatódik a szkript futása a háttérben, majd az exit-tel a processzből:

[DBG]: [Process:19804]: [Runspace1]: PS Course:\>> detach

[Process:19804]: PS C:\Users\Tibi\Documents> exit

PS C:\>

Távoli munkamenetek hibafelderítése

Csak egy kicsit bonyolultabb a helyzetünk távoli munkamenetek hibakeresésekor. Induljunk ki hasonló helyzetből, mint az előzőekben látott, elmentett szkript-alapú példa volt, méghozzá tervezett hibafelderítést végzünk a Wait-Debugger cmdlet használatával:

$rs = {

        $pid

        $a = 1

        Wait-Debugger

        Get-date

   }

 

Set-Content -Path $env:TEMP\remscr.ps1 -Value $rs

$s = New-PSSession -ComputerName dc2016

Copy-Item -ToSession $s -Path $env:TEMP\remscr.ps1 -Destination c:\powershell

 

Invoke-Command -Session $s -ScriptBlock {& c:\powershell\remscr.ps1}

Itt az $rs változóban tárolom a távoli futtatásra szánt szkriptet. Ennek első sorában található a $pid változó kiíratása, mert ez adja meg nekünk a távoli PowerShell processz azonosítóját és erre szükségünk lenne abban az esetben, ha nem rendelkeznénk a hibafelderítéshez szükséges sessionID-val. Ilyen példánk lesz a 2., ezt tehát mindenképpen érdemes valamilyen módon kinyerni a futtatás során.

Ezt a szkriptet elmentem az ideiglenes mappába, majd megnyitok egy kapcsolatot a távoli géphez. A szkriptet – kihasználva a PowerShell 5.0 új lehetőségét – ezen a távoli kapcsolaton keresztül másolom át a DC2016 gépem c:\powershell mappájába. Végén meghívom távoli végrehajtással ezt a szkriptet.

3228

WARNING: Session Session1 with instance ID bbd0e04b-7286-4a0b-be2c-cdda7a3bfab5 on computer dc2016 has been disconnected because the script running on the session has stopped at a breakpoint.

 Use the Enter-PSSession cmdlet on this session to connect back to the session and begin interactive debugging.

Láthatjuk, hogy a processzazonosító 3228 és hogy a távoli kapcsolat bontódott is, mert a távoli szkript hibakereső állapotba került. A session egyedi azonosítója (instanceID) látható is a figyelmeztető üzenetben, erre is szükségünk lehet.

Most tulajdonképpen bármelyik gépről folytathatjuk a hibafelderítést, egyszerűség kedvéért folytassuk ugyanazon a gépen, annál is inkább, hiszen a session objektum még mindig megtalálható a $s változóban, így egyszerűen újra tudunk ehhez csatlakozni, majd be is léphetünk ebbe a munkamenetbe:

PS C:\Windows\system32> Connect-PSSession -Session $s

 

 Id Name            ComputerName    State         ConfigurationName     Availability

 -- ----            ------------    -----         -----------------     ------------

  1 Session1        dc2016          Opened        Microsoft.PowerShell   RemoteDebug

 

PS C:\Windows\system32> Enter-PSSession -Session $s

WARNING: You have entered a session that is currently stopped at a debug breakpoint inside a running command or script.  Use the Windows PowerShell command line debugger to continue debugging.

 

[dc2016]: [DBG]: PS C:\Users\Administrator\Documents>>

Ilyenkor az ISE a PowerShell 5.0-ban – miután egy elmentett szkriptről van szó – meg is nyitja ezt egy új szkriptszerkesztő fülön:

101 . ábra A távoli szkript automatikusan megnyílik az ISE szerkesztőjében

Látható a fül szövegében, hogy ez egy távoli szkript ([Remote File]), de ettől függetlenül a hibafelderítés minden lehetősége rendelkezésünkre áll, mint például a lépésenkénti végrehajtás, vagy a változók tartalmának kiolvasása.

Most nézzük azt az esetet, amikor egy hosszan futó szkriptünk van, és nem tervezett módon akarunk hibafelderítést végezni. Ehhez a módosított szkript a következő:

$rs = {

        $pid

        $a = 1

        while($true){

            Get-date

            Start-Sleep 5

        }

   }

 

Set-Content -Path $env:TEMP\remscr.ps1 -Value $rs

$s = New-PSSession -ComputerName dc2016

Copy-Item -ToSession $s -Path $env:TEMP\remscr.ps1 -Destination c:\powershell

 

Invoke-Command -Session $s -ScriptBlock {& c:\powershell\remscr.ps1}

Az első sorban a futó processz azonosítóját, a végtelen ciklusban az aktuális időt írom ki. Itt is elmentem a szkriptet és a távoli kapcsolaton keresztül másolom át a DC2016 nevű gépemre.

Ha ezt elindítom, meg is kapom a processz azonosítót és az időadatok elkezdenek csordogálni:

3176

 

2015. szeptember 19., szombat 23:50:36

2015. szeptember 19., szombat 23:50:41

2015. szeptember 19., szombat 23:50:46

Nézzük most azt a helyzetet, mintha nem férnénk hozzá a session azonosítójához. Ez némileg igaz is, hiszen fut a szkriptünk így most nem tudunk belenézni a $s tartalmába, és nem akarjuk megállítani. Nyitok egy új Powershell Tab-ot az ISE-ben:

102 . ábra New PowerShell Tab - új PowerShell processz ugyanabban az ISE ablakban

És itt futtatom a következő cmdleteket:

PS C:\Windows\system32> Enter-PSSession -ComputerName dc2016

 

[dc2016]: PS C:\Users\Administrator\Documents> Enter-PSHostProcess -id 3176

 

[dc2016]: [Process:3176]: PS C:\Users\Administrator\Documents> Get-Runspace

 

 Id Name            ComputerName    Type          State         Availability  

 -- ----            ------------    ----          -----         ------------  

  1 RemoteHost      localhost       Local         Opened        Busy          

  2 RemoteHost      localhost       Local         Opened        Busy          

 

 

 

[dc2016]: [Process:3176]: PS C:\Users\Administrator\Documents> Debug-Runspace 1

[dc2016]: [DBG]: [Process:3176]: [RemoteHost]: PS C:\Users\Administrator\Documents>>

Első lépésben tehát csatlakoztam a DC2016 gépemhez, majd az előbb látott 3176-os processzhez csatlakozom az új Enter-PSHostProcess  cmdlettel. Látható, hogy a sor elején, a promptban a [dc2016] mellett immár a [Process:3176] is megjelent. Még nem értünk teljesen célt, hiszen a processz egy új futtatási környezetébe (másik szál) érkeztünk, a hibakeresést az 1-es számú Runspace-ben kell végezzük, így oda csatlakozom a Debug-Runspace  1 cmdlettel. Ilyenkor megint megnyílik a szkriptszerkesztőben a távoli szkript és sárga kiemeléssel mutatja, hogy éppen melyik sornál állítottuk meg a futtatást.

Ha végeztem a hibafelderítéssel és szeretném, hogy a szkript futása folytatódjon, akkor az új detach  paranccsal bezárhatom ezt az üzemmódot, majd exit-el kiléphetek a távoli kapcsolatból:

[dc2016]: [DBG]: [Process:2480]: [RemoteHost]: PS C:\Users\Administrator>> detach

 

[dc2016]: [Process:2480]: PS C:\Users\Administrator\Documents> exit

 

PS C:\Windows\system32>



Word To HTML Converter