Temauke: Windows PowerShell del 7

Temauke: Windows PowerShell del 7

Noen ganger må vi håndtere feil som oppstår i kjøringen av en CmdLet, script eller funksjon. Vi skal her se på hvordan vi kan påvirke hvordan feil skal håndteres.

Feilsøking og debugging

Håndtering av feil (ErrorAction)

Feil i PowerShell deles inn i to kategorier:

Terminating Denne type feil stopper scriptet
Non-terminating Selv om det har oppstått feil kan scriptet fortsette videre

Feil som oppstår representeres med et eget objekt – ErrorRecord. Dette objektet inneholder en exception som er beskriver årsaken til at feilen har oppstått, i tillegg til å si hvor.

ErrorRecord objektene lagres i en standard variabel med navn $error. $error er en samling med ErrorRecords (faktisk 256 objekter – noe som tilsvarer de 256 siste feilene som har oppstått).

Hvert ErrorRecord objekt inneholder følgende egenskaper:

Exception Er et eget objekt, med egne egenskaper. Den viktigste er Message som beskriver feilen. (Inneholder feilteksten)
TargetObject Dette er objektet hvor feilen oppsto
CategoryInfo Er en kategorisering av feil
FullyQualifiedErrorId Så spesifikk informasjon som mulig om feilen
ErrorDetails Denne er valgfri, så noen ganger er den null. Andre ganger inneholder den feilmeldingen i klartekst på engelsk.
InvocationInfo Hvis tilgjengelig, så sier denne deg hvilken linje i scriptet som har feilet, eller hvilken CmdLet. Kan være null.

Eksempel som skriver ut feilbeskrivelse for den siste feilen som har oppstått (error[0]):
$error[0].Exception.Message

De fleste CmdLets lar deg påvirke hvordan de enkle feilene skal håndteres (de som ikke øyeblikkelig stopper scriptet, men hvor det er mulig å fortsette. (non-terminating)). Dette påvirker du igjennom ErrorAction parametret.

Følgende verdier kan benyttes på ErrorAction parametret:

Continue Dette er default valget, og betyr at feilen blir skrevet ut, men kjøringen fortsetter uansett.
Stop Dette betyr at kjøringen skal stoppe ved feil
Inquire Valget stopper kjøringen, og ber brukeren bestemme om kjøringen skal fortsette eller ikke
SilentlyContinue Kjøringen av scriptet blir ikke avbrutt av feil. Feil blir heller ikke rapportert i resultatet.

Eksempel på bruk av ErrorAction (-ea) parameter:
$a=Get-WmiObject Win32_OperatingSystem –ea stop

Bruk av ErrorAction parameter

Du kan påvirke hva som er standardhandling når feil oppstår med variabelen $erroractionpreference.

Bruk av variabelen $erroractionpreference

Hvordan fange feil i Powershell 1.0?

Når feil oppstår sier vi at et ”unntak blir kastet”, eller ”throw exception”. Med unntak mener vi at det har oppstått en situasjon hvor vanlig planlagt prosessering ikke kan skje. La oss si at vi skal flytte ei fil fra mappe a til mappe b, men at fila ikke finnes. Da kan vi ikke flytte fila, og må kaste et unntak som sier vi ikke fant fila.

Når feil oppstår er det best practice å ta i mot feilen (catch exception), og til å gjøre dette benytter vi en errorhandler. (feilhåndterer).

I Powershell 1.0 benyttet vi en Trap til å håndtere feil som ble kastet:

Trap [Exception] {
#håndter feilen, eller gi informativ informasjon
# $_ representerer ErrorRecord som ble kastet
Return [argument] | break | continue
}

I en errorhandler er det to ting som er spesielt viktig å huske. For det første har du informasjon om feilen som har oppstått tilgjengelig i variabelen $_ . Denne variabelen inneholder det ErrorRecord objektet som ble kastet der feilen oppstod. Videre er det viktig å huske at den siste linja i errorhandleren kan være en av tre kommandoer ; Return, Break eller Continue. Med return kan vi returnere verdier, med break kan vi stanse kjøringen, og med continue fortsetter vi uten å returnere noen verdi.

Følgende forklarer hvordan feilhåndtering virker i Powershell: Hvis en errorhandler er definert, blir denne utført når det oppstår feil. Errorhandler har tilgang til variabelen $error som forklarer hva som gikk galt. Den kan også sette ErrorPolicy for å si om scriptet skal fortsette eller ikke (defineres i slutten av errorhandler- slik som break eller continue, eller et hvilket som helst argument av eget ønske). Vi kan også definere en errorhandler til kun å omfatte bestemte typer feil. Dette angir vi direkte etter nøkkelordet Trap.

Her er et enkelt eksempel på en errorhandler:

TrapTest.ps1
function CheckWMI ($computer)
{
trap
{
Write-host “Det oppstod en feil:”
Write-host “ID: ” $_.ErrorId
Write-host “Beskrivelse:” $_.Exception.Message
continue
}
$osinfo = get-wmiobject Win32_OperatingSystem -property ServicePackMajorVersion -computer $computer -ea stop
Write-host “Maskin: ” $osinfo.ServicePackMajorVersion
}
Write-host “Sjekker service pack versjoner:”
CheckWMI(“FinnesEi”)
CheckWMI(“FinnesHellerIkke”)

I eksemplet over er det viktig at –ea stop er med. Hvis ikke vil feilen blir håndtert i CmdLet’en, og ikke i ErrorHandleren vi definerte. Du kan selv teste dette ved å fjerne –ea stop (da blir default Continue benyttet som erroraction, og CmdLet Get-WMIObject håndterer feilen selv).

Du kan også kaste feil selv ved å benytte throw:
throw “Noe gikk galt…”

Dette kan du også benytte i errorhandler, for eksempel for å behandle en feil, og sende den videre til neste errorhandler (hvis det er flere definert i overliggende scope)

Trap
{
throw $_
}

Hvordan fange feil med Powershell 2.0?

Powershell 2.0 har fått fullverdig feilhåndtering gjennom try, catch og finally. Dette ligner med på ordinære programmeringspråk og lar oss skrive feilhåndtering på en annen måte enn med trap.

Typisk oppbygning for try,catch, finally:

try
{ kodeblokk for try , handlinger som kan kaste feil }
catch
{ kodeblokk for catch, håndter feil som oppstår under try}
finally
{ kodeblokk for finally – rydder opp uansett feil eller ikke}

Du må ikke ha med finally om du ikke trenger det.

Kodeblokken vi har definert i catch kjører om det oppstår feil i kodeblokken som ligger i try. Om kodeblokken som kjører i try ikke opplever feil vil kodeblokken(e) i catch setningen ikke kjøre.
Finally vil kjøres uavhengig om det går bra eller ikke med try.

Vi kan bygge inn flere catch setninger etter hverandre. Hver catch setning kan fange spesifikke feil, eller vi kan ha en åpen catch som fanger alle de feilene vi ikke eksplisitt ser etter.

Vi starter med de mest spesifikke, og kan avslutte med en generell catch til slutt.

La oss se på ett eksempel hvor vi laster ned en fil fra en webserver:

try
{
$wc = new-object System.Net.WebClient
$wc.DownloadFile(“http://www.itpro.no/dokumentet.doc”)
}
catch [System.Net.WebException],[System.IO.IOException]
{
“Kan ikke laste ned Dokumentet.doc fra http://www.itpro.no.”
}
catch
{
“En ukjent feil oppsto.”
}
Finally
{
Write-Host “Denne kjøres uansett”
}

Merk: Finally kjøres selv om du trykker CTRL+C eller har en exit kommando i skriptet.

Debugging med Powershell 2.0

Med Powershell 2.0 er debugging blitt enklere. Vi har fått mulighet til å sette breakpoints, og med ISE har vi fått ett grafisk grensesnitt som er enklere å forholde seg til under debugging. La oss starte med å se hvordan du kan debugge fra kommandolinjen i Powershell 2.0

Debugging fra kommandolinjen

I Powershell 2.0 bruker vi ikke Set-PSDebug som i Powershell 1.0, men vi benytter Set-PSBreakPoint. Set-PSBreakpoint kan sette breakpoint på linje, cmdlet eller variabel. Vi kan også benytte en scriptblokk, noe som lar oss sette betingelser for ett breakpoint.

Vi starter med å se hvordan vi kan sette breakpoint på en gitt linje i ett skript. Følgende eksempel setter breakpoint på linje 2 i scriptet testscript.ps1:
Set-PSBreakpoint –Script testscript.ps1 –Line 2

Når du nå kjører scriptet vil det stoppe før linje 2 utføres. Du har da mulighet til å bruke egne debugkommandoer.
Disse henter du frem ved å skrive h eller ? ved debugprompt. Kommandoene du har tilgjenglig er:

• s, stepInto
• v, stepOver
• o, stepOut
• c, Continue
• q, Quit
• k, Get-PSCallStack
• l, list
• < enter >
• h, ?

Av disse kommandoene bruker stepInto, stepOver, stepOut , quit og continue for å kontrollere kjøringen av scriptet. Om du ønsker å kjøre linje-for-linje velger du continue. Om du står på en linje som kaller en fuksjon eller ett annet script kan du bestemme om du skal debugge inn i funksjonen eller scriptet med stepInto og stepOver. StepInto tar deg inn i funsjonen eller scriptet, og stepOver utfører funksjonen eller scriptet, før den igjen stopper på neste linje i scriptet du allerde er i. StepOut kjører deg ut av funksjonen eller skriptet du nå er i. Quit avslutter kjøringen (og dermed også debuggingen) . Enter benyttes for å gjenta forrige valgte kommando.

Bruk av diverse kommandoer

Du kan også angi Actions som skal kjøres når ett breakpoint er aktivert. Dette gjør du med –Action paramteren. På Set-PSBreakpoint. I eksemplet under ser du at den ikke stopper når navnet er lik Pelle, men kun når navnet er lik Ragnar.

Bruk av Action parameteren

Se callstack under debugging

Ved debugprompten kan du se callstack for hvor du er med kommandoen k (ellet Get-PSCallStack). Det siste utførte steget er øverst, og det første er nederst i stakken. På eksemplet under ser du at sesjonen startet fra kommandolinjen (prompt) og vi står nå i scriptet testscript.ps1 på linje 2.

Callstack under debugging

Debugging med Powershell ISE

For de fleste er Powershell ISE det enkleste stedet å utføre debugging. Last inn scriptet, og trykk F9 på linjen du ønsker å plassere ett breakpoint. I Powershell ISE har du en egen meny “Debug” hvor du kan se hvilke alternativer som er tilgjenglig. Powershell ISE har også egne tastatursnarveier for å kontrollere kjøringen av scriptet.

Tastatursnarveier i Powershell ISE

Debug-meny i Powershell ISE

En annen fin detalj er at ved å holde musmarkøren over en variabel vil de se innholdet av variabelen.
På eksemplet under holder jeg musmarkøren over $Navn og får opp innholdet er lik Ragnar

Bruk av musmarkør for å se innhold av variabel

I denne artikkelen har vi sett på hvordan vi kan skrive robuste script med feilhåndtering, samt hvordan vi kan debugge scriptene våre med Powershell.