A Windows PowerShell hibakezelését sajnos nem találjuk meg az msdn-en, ugyanis egyáltalán nincs dokumentálva (2006 óta), a Windows PowerShell Blog-on található bejegyzés szerint a Windows PowerShell: TFM könyv szerzői ingyenesen elérhetővé tették a 11. fejezetet, mely ezzel a témakörrel foglalkozik, sajnos a blogon található link nem működik és a google cache-ből sem érhető el a pdf.
A PowerShell kivételkezelésének megértéséhez szükséges a .NET kivételkezelésének megértése. Szerencsére ez jól dokumentált (link1, link2), így csak egy, a legszükségesebb információkat tartalmazó gyors összefoglalás található itt.
A .NET keretrendszerben, amennyiben egy hiba történik egy metódusban, melyet a metóduson belül nem lehet megoldani, az egy kivételes esemény. Ekkor egy kivétel (Exception) dobódik (throw), mely a System.Exception osztály egy altípusa (amely tartalmazza a hibaüzenetet és a stack trace-t is). A hívó pedig dönthet úgy, hogy ezt a kivételt elkapja (catch) és lekezeli, vagy továbbdobja. További lehetőség, hogy el sem kapja, ekkor a stack-ben lévő következő hívó kapja meg a kivételt.
Jópár kivételeket reprezentáló osztály található a .NET framework-ben, a PowerShell Management és Automation névtereiben pedig még több. Azonban ezekre is igaz, hogy közös ősük a System.Exception osztály (és általában tartalmazzák a hibaüzenetet és/vagy a stack trace-t).
A .NET-ben csak kivételt dobhatunk, de PowerShellben akármit. Amikor valami olyat dobunk, ami nem egy kivétel, azt becsomagolja a PowerShell egy RuntimeException-be. Például ha "throw (ls *.txt)"-t írunk PowerShellben, akkor az ls (ekvivalens a dir paranccsal) kimenete konvertálódik string-é és a RuntimeException üzenet (message) részébe kerül.
Természetesen dobhatunk szabványos kivételeket is (például: throw (new-object IO.DirectoryNotFoundException) ).
Általában érdemes a már meglévő kivétel-hierarchiából választani kivételt, nem pedig a RuntimeException-re hagyatkozni, mert így lehetőségünk adódik specifikus kivételek elkapására.
A Windows PowerShellben a kivételek elkapására a "trap" utasítást használhatjuk.
Fontos megjegyezni, hogy nem feltétlen szükséges a hibák kezelését megvalósítanunk. A $ErrorActionPreference-et beállíthatjuk "Continue"-ra és "SilentlyContinue"-ra is. Ez ekvivalens a Visual Basic ON ERROR RESUME NEXT-jével, ekkor nem szükséges hibakezelő részeket írnunk. Amennyiben biztosak vagyunk abban, hogy a scriptünkben hol léphetnek fel olyan hibák amiket nem kívánunk kezelni, ezen helyek előtt átállhatunk SilentlyContinue-ra (majd ezen részek után a "if(-not $?){ #Error handling with use of $Error }" elágazás segítségével megvizsgálni, volt e hiba, ha akarjuk egyáltalán ellenőrizni).
A Windows PowerShell rendelkezik több beépített változóval, melyekkel a hibák bekövetkezése esetén megjelenített információ mennyiségét szabályozhatjuk:
Összefoglalva, a PowerShell kivételkezelése hasonlít a VB kivételkezelésére (ON ERROR GOTO TRAP ... RESUME NEXT):
Elhelyezünk egy trap-et (minden egyes kezelendő kivételnek), majd pedig amikor kiváltódik a kivétel, a vezérlés a trap blokk első utasításának adódik át. A hibakezelés után vagy "continue" vagy "break" utasítást adhatunk ki. Fontos megjegyezni, hogy a PowerShellben a trap-ek sorrendje és pozíciója adott scope-on belül nem számít.
Szemben azzal, ami jópár PowerShell könyvben olvasható, a "continue" után a vezérlés a hibát kiváltó utasítás után következő utasításnak adódik át, NEM pedig a következő sornak.
Első példánk elég egyszerű:
A kimenet:
Van egy harmadik lehetőségünk is a "break" és "continue" utasítások mellett, a "return (argument)". Mivel a return működését befolyásolja a $ErrorActionPreference, ezért a működése gyakorlatilag kiszámíthatatlan, emiatt pedig kerülendő a használata. Ha a trap-en belül szeretnénk valamit kiiratni, használjuk inkább a Write-Output cmdlet-et.
A fent bemutatott trap bevezetése nem aratott osztatlan elismerést a PowerShell felhasználók körében. Adam Weigert elkészítette a C#-ból ismerős Try/Catch/Finally kulcsszavak implementációját.
Ez a példa szemléleti, hogy ha break-et használunk, akkor a kivétel továbbdobódik egy külső trapnek:
A kimenet: