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ébb 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.
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 automtikusan 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 hibekeresési módba.
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égetelen 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 tahá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önyezeté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>