Welcome to Our Website

Alt du ønsket å vite om unntak

  • 05/23/2020
  • 14 minutter på å lese
    • j
    • f
    • s

Feil håndtering er bare en del av livet når det kommer til å skrive kode. Vi kan ofte kontrollere og validateconditions for forventet atferd. Når det uventede skjer, slår vi til unntak håndtering., Youcan enkelt håndtere unntak som er generert av andre mennesker koden eller du kan generere ownexceptions for andre å håndtere.

Merk

Den opprinnelige versjonen av denne artikkelen dukket opp på bloggen skrevet av @KevinMarquette. ThePowerShell team takk Kevin for å dele denne innhold med oss. Sjekk ut bloggen hans atPowerShellExplained.com.

Grunnleggende terminologi

Vi trenger for å dekke noen grunnleggende begreper før vi hoppe inn i dette.

Unntak

Et Unntak er som en hendelse som er opprettet ved normal håndtering av feil ikke kan håndtere problemet.,Prøver å dele et tall med null eller kjører ut av minnet er eksempler på noe som skaper anexception. Noen ganger forfatteren av den koden du bruker skaper unntak for visse issueswhen de skjer.

Kaste og Fange

Når et unntak skjer, sier vi at et unntak er kastet. For å håndtere en kastet unntak, dere trenger for å fange det. Hvis et unntak er kastet, og det er ikke fanget opp av noe, skriptet stopsexecuting.

call stack

call stack er listen over funksjoner som har ringt hverandre., Når en funksjon er kalt, itgets lagt til stakken eller toppen av listen. Når funksjonen avsluttes eller returnerer, det er removedfrom stabelen.

Når et unntak er kastet, som kaller stack er sjekket for et unntak fra behandler til å catchit.

Avslutning, og ikke-terminerende feil

Et unntak er generelt en avslutning feil. En kastet unntak er enten være fanget eller itterminates dagens kjøring. Standard, et ikke-terminerende feil er generert av Write-Errorog det legger en feil til output stream uten å kaste et unntak.,

jeg påpeke dette fordi Write-Error og andre ikke-terminerende feil ikke utløsecatch.

Svelge et unntak

Dette er når du fange en feil bare for å undertrykke det. Gjør dette med forsiktighet fordi det kan maketroubleshooting problemer svært vanskelig.

Grunnleggende kommandosyntaksen

Her er en rask oversikt over de grunnleggende unntak håndtering syntaks brukt i PowerShell.

Kaste

for Å lage vår egen unntak hendelse, vi kaste et unntak med throw søkeord.,

function Start-Something{ throw "Bad thing happened"}

Dette skaper en runtime unntak som er en avslutning feil. Det er håndtert av en catch i acalling funksjon i eller ut av manus med en melding som dette.

Skrive-Feil -ErrorAction Stoppe

jeg nevnte at Write-Error ikke kaste en avslutning feil som standard. Hvis du vil angi-ErrorAction Stop, Write-Errorgenererer en avslutning feil som kan bli behandlet med encatch.,

Write-Error -Message "Houston, we have a problem." -ErrorAction Stop

Takk til Lee Dailey for at du minner om bruk av -ErrorAction Stop denne måten.

Cmdlet -ErrorAction Stoppe

Hvis du vil angi -ErrorAction Stop på en avansert funksjon eller cmdlet, det viser alle Write-Erroruttalelser til avslutning feil som stopper utførelsen eller som kan håndteres av en catch.,

Start-Something -ErrorAction Stop

Try/Catch

Den måten unntak håndtering fungerer i PowerShell (og mange andre språk) er at du først try asection av kode, og hvis det kaster en feilmelding, kan du catch det. Her er et kjapt eksempel.

catch skriptet kjører bare hvis det er en avslutning feil. Hvis try utføres på riktig måte, thenit hopper over catch.,

Prøv/Endelig

noen Ganger trenger du ikke å håndtere en feil, men fortsatt trenger noen kode for å utføre hvis en exceptionhappens eller ikke. En finally skriptet gjør akkurat det.

Ta en titt på dette eksempelet:

Når du åpner eller koble til en ressurs, bør du lukke den. Hvis ExecuteNonQuery() throwsan unntak, – tilkoblingen ikke er lukket. Her er den samme koden i en try/finally blokker.

I dette eksempelet, forbindelsen er lukket, dersom det er en feil. Det også er lukket hvis det er noerror., finally skriptet kjøres hver gang.

Fordi du er ikke fanger unntak, er det likevel blir dyrket opp samtalen stabelen.

Try/Catch/Endelig

Det er helt gyldig å bruke catch og finally sammen. Mesteparten av tiden vil du bruke det ene eller andre, men du kan finne scenarier der du kan bruke begge.

$PSItem

Nå som vi har fått den grunnleggende ute av veien, kan vi grave litt dypere.,

i catch blokker, det er en automatisk variabel ($PSItem eller $_) av type ErrorRecordsom inneholder detaljer om unntak. Her er en rask oversikt over noen av de keyproperties.

For disse eksemplene har jeg brukt en ugyldig bane i ReadAllText for å generere dette unntaket.

::ReadAllText( '\\test\no\filefound.log')

PSItem.ToString()

Dette gir deg den reneste melding til bruk i logging og generell utgang., ToString() isautomatically kalt hvis $PSItem er plassert inne i en streng.

catch{ Write-Output "Ran into an issue: $($PSItem.ToString())"}catch{ Write-Output "Ran into an issue: $PSItem"}

$PSItem.InvocationInfo

Denne eiendommen inneholder ekstra informasjon som samles inn av PowerShell om funksjonen eller scriptwhere unntak ble kastet. Her er InvocationInfo fra prøven unntak av at Icreated.

De viktige detaljene her viser ScriptName, Line av koden ScriptLineNumberhvor bruken i gang.

$PSItem.,ScriptStackTrace

Denne eiendommen viser rekkefølgen av funksjonskall som fikk deg til koden der unntaket wasgenerated.

jeg kan bare ringe til funksjoner i det samme skriptet men dette ville spore samtaler om multiplescripts var involvert.

$PSItem.Unntak

Dette er faktisk unntaket som ble kastet.

$PSItem.Unntak.Melding

Dette er de generelle melding som beskriver de unntak og er et godt utgangspunkt whentroubleshooting. De fleste unntakene har en standard melding, men kan også være satt til noe tilpasset whenthe unntak blir kastet.,

PS> $PSItem.Exception.MessageException calling "ReadAllText" with "1" argument(s): "The network path was not found."

Dette er også melding tilbake når du ringer $PSItem.ToString() hvis det var ikke ett sett påErrorRecord.

$PSItem.Unntak.InnerException

Unntak kan inneholde indre unntak. Dette er ofte tilfellet når koden du callingcatches et unntak, og kaster et annet unntak. Den opprinnelige unntak er plassert insidethe nye unntak.

PS> $PSItem.Exception.InnerExceptionMessageThe network path was not found.

jeg vil tilbake til dette senere når jeg snakker om re-kaste unntak.

$PSItem.Unntak.,StackTrace

Dette er StackTrace for unntak. Jeg viste en ScriptStackTrace ovenfor, men denne er forthe samtaler til å forvaltet kode.

at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean checkHost)at System.IO.File.InternalReadAllText(String path, Encoding encoding, Boolean checkHost)at CallSite.Target(Closure , CallSite , Type , String )

Du får bare denne stack trace når arrangementet er kastet ut forvaltet kode. Jeg kaller en .NETframework funksjon direkte, så det er alt vi kan se i dette eksemplet. Vanligvis når du’relooking på en stack trace, du er på jakt etter hvor koden slutter og systemet samtaler begynne.

Arbeide med unntak

Det er mer unntak enn de grunnleggende syntaks og unntak egenskaper.,

Fange skrevet unntak

Du kan være selektiv med det unntak at du fange. Unntak har type og du kan specifythe type unntak du ønsker å fange.

unntak typen er sjekket for hver catch blokker før man er funnet som passer dine unntak.Det er viktig å innse at unntak kan arve fra andre unntak. I eksempelet ovenfor,FileNotFoundException arver fra IOException. Så hvis IOException var først, deretter itwould får ringt i stedet., Bare én catch-blokk er påberopt, selv om det er flere kamper.

Hvis vi hadde en System.IO.PathTooLongException, IOException ville kampen, men hvis vi hadde enInsufficientMemoryException så ingenting skulle få det, og det ville spre opp stakken.

Fange flere typer på en gang

Det er mulig å ta flere unntak typer med samme catch uttalelse.

Takk /u/Sheppard_Ra for å foreslå dette tillegg.

Kaster skrevet unntak

Du kan kaste skrevet unntak i PowerShell., I stedet for å ringe throw med en streng:

throw "Could not find: $path"

Bruk et unntak akselerator som dette:

throw "Could not find: $path"

Men du må angi en melding når du gjør det på den måten.

Du kan også opprette en ny instans av et unntak fra å bli kastet. Meldingen er valgfritt når du dothis fordi systemet har standard meldinger for alle innebygde unntak.

throw ::new()throw ::new("Could not find path: $path")

Hvis du ikke bruker PowerShell 5.0 eller høyere, må du bruke eldre New-Object tilnærming.,

Ved hjelp av et maskinskrevet unntak, kan du (eller andre) kan fange unntak av den type som er nevnt i theprevious delen.

Skrive-Feil -Unntak

Vi kan legge til disse skrev unntak til Write-Error og vi kan fortsatt catch feil ved exceptiontype. Bruk Write-Error som i disse eksemplene:

Så vi kan ta det som dette:

catch { Write-Log $PSItem.ToString()}

Den store listen over .NET unntak

jeg samlet en master liste med hjelp av Reddit/r/PowerShell samfunnet som containshundreds av .,NET unntak for å utfylle dette innlegget.

  • Den store listen over .NET unntak

jeg starter ved å søke på at listen for unntak som føler at de ville passe godt for mysituation. Du bør prøve å bruke unntakene i basen System navnerom.

Unntak er objekter

Hvis du begynner å bruke mye av skrevet unntak, husk at de er objekter. Ulike exceptionshave forskjellige konstruktører og egenskaper., Hvis vi ser på FileNotFoundExceptiondocumentation for System.IO.FileNotFoundException, ser vi at vi kan passere i en melding og en filepath.

::new("Could not find file", $path)

Og det har en FileName eiendom som avslører at filbanen.

catch { Write-Output $PSItem.Exception.FileName}

Du bør konsultere .NET dokumentasjon som for andre konstruktører og objekt egenskaper.

Re-kaster et unntak

Hvis alt du kommer til å gjøre i catch blokker er throw samme unntak, så ikke catchdet., Du bør bare catch et unntak som du har tenkt å håndtere eller utføre noen handling når ithappens.

Det er tider hvor du ønsker å utføre en handling på et unntak, men re-kast unntak sosomething nedstrøms kan håndtere det. Vi kan skrive en melding eller logg problemet i nærheten av der wediscover det, men håndterer problemet lenger opp i stabelen.

catch{ Write-Log $PSItem.ToString() throw $PSItem}

det er Interessant nok, vi kan kalle throw fra catch og det re-kaster currentexception.,

catch{ Write-Log $PSItem.ToString() throw}

Vi ønsker å re-kast unntak for å bevare den opprinnelige utførelse informasjon som kilde scriptand linje nummer. Hvis vi kaster et nytt unntak på dette punktet, det skjuler der unntaket i gang.

Re-lanserer en ny unntak

Hvis du fange et unntak, men du vil kaste en annen en, så bør du nest originalexception inne i det nye. Dette gjør at noen ned stabelen for å få tilgang til det som$PSItem.Exception.InnerException.

catch{ throw ::new('Could not access field',$PSItem.Exception)}

$PSCmdlet.,ThrowTerminatingError()

en ting som jeg ikke liker om bruk av throw for raw unntak er at feilen messagepoints på throw uttalelse, og angir at linjen er der problemet er.

etter å Ha feilmeldingen forteller meg at min skriptet er ødelagt fordi jeg kalt throw på linje 31 er abad melding til brukere av skriptet for å se. Det trenger ikke fortelle dem noe nyttig.

Dexter Dhami påpekt at jeg kan bruke ThrowTerminatingError() for å korrigere det.,

Hvis vi antar at ThrowTerminatingError() ble kalt inne i en funksjon kalt Get-Resource, thenthis er feil at vi ville se.

vil du se hvordan det poeng til Get-Resource funksjon som er kilden til problemet? Som forteller theuser noe nyttig.

Fordi $PSItem er en ErrorRecord, kan vi også bruke ThrowTerminatingError denne måten å re-kast.,

catch{ $PSCmdlet.ThrowTerminatingError($PSItem)}

Dette endrer kilde til feil å Cmdleten og skjule det innvendige av ditt arrangement suge brukere av Cmdleten.

Prøv kan opprette avslutte feil

Kirk Munro peker på at noen unntak er det bare å avslutte feil når den utføres inne i entry/catch blokker. Her er det eksempel han ga meg som genererer en dividere med null runtime unntak.

function Start-Something { 1/(1-1) }

Deretter starter det som dette for å se det generere feil og fortsatt utgang meldingen.,

&{ Start-Something; Write-Output "We did it. Send Email" }

Men ved å plassere den samme koden i en try/catch, ser vi at noe annet skjer.

try{ &{ Start-Something; Write-Output "We did it. Send Email" }}catch{ Write-Output "Notify Admin to fix error and send email"}

Vi se feilen bli en avslutning feil og ikke sende ut den første meldingen. Det jeg ikke likeabout denne er at du kan ha denne koden i en funksjon, og det fungerer annerledes hvis someoneis ved hjelp av en try/catch.

jeg har ikke løp inn problemer med dette selv, men det er hjørne tilfelle å være klar over.

$PSCmdlet.,ThrowTerminatingError() inne i try/catch

En nyanse av $PSCmdlet.ThrowTerminatingError() er at det skaper en avslutning feil i yourCmdlet men det blir til en ikke-terminerende feil etter at den forlater Cmdleten. Dette etterlater burdenon anroper-av-funksjon for å bestemme hvordan de skal håndtere feil. De kan slå den tilbake i aterminating feil ved å bruke -ErrorAction Stop eller kall det fra innenfor en try{...}catch{...}.,

Offentlig funksjon maler

En siste ta en måte jeg hadde med min samtale med Kirk Munro var at han plasserer entry{...}catch{...} rundt hver begin, process og end blokker i alle hans advancedfunctions. I de generiske catch-blokker, han har en enkelt linje med$PSCmdlet.ThrowTerminatingError($PSItem) for å håndtere alle unntak forlate sine funksjoner.

function Start-Something{ param() process { try { ... } catch { $PSCmdlet.ThrowTerminatingError($PSItem) } }}

Fordi alt er i en try uttalelse innen sine funksjoner, alt fungerer konsekvent., Thisalso gir rene feil til sluttbruker som skjuler den interne koden fra den genererte feil.

Felle

jeg fokuserte på try/catch aspekt av unntak. Men det er en arv har jeg trenger å mentionbefore vi pakker opp dette.

En trap er plassert i et script eller funksjon å fange alle unntak som skjer i det omfang. Whenan unntak skjer, koden i trap utføres, og deretter normal kode fortsetter. Ifmultiple unntak skje, så den fellen er kalt over og over.,

jeg personlig aldri vedtatt denne tilnærmingen, men jeg kan se verdien i admin eller controller skript thatlog alle unntak, så fortsette å kjøre.

avslutning

å Legge til rette unntaksbehandling å lesa ikke bare gjøre dem mer stabil, men også gjør iteasier for deg å feilsøke disse unntakene.

jeg brukte mye tid på å snakke throw fordi det er et sentralt begrep når vi snakker om exceptionhandling., PowerShell også ga oss Write-Error som håndterer alle situasjoner hvor du ville brukethrow. Så tror ikke at du trenger å bruke throw etter å ha lest dette.

Nå som jeg har tatt deg tid til å skrive om unntak håndtering i denne detalj, kommer jeg til toswitch over til å bruke Write-Error -Stop for å generere feil i koden min. Jeg er også tenkt å takeKirk råd og foreta ThrowTerminatingError min goto unntak handler for hver funksjon.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *