Welcome to Our Website

Minden, amit tudni akartál kivételek

  • 05/23/2020
  • 14 perc olvasni
    • j
    • – f
    • s

Hiba kezelése csak az élet része, amikor kódot írni. Gyakran ellenőrizhetjük és érvényesena várható viselkedés feltételei. Amikor a váratlan történik, fordulunk Kivétel kezelése., Könnyen kezelheti a más emberek kódja által generált kivételeket,vagy létrehozhatja sajátjátkivételek mások számára.

Megjegyzés

a cikk eredeti változata megjelent a @KevinMarquette által írt blogban. ThePowerShell csapat köszönöm Kevin megosztására ezt a tartalmat velünk. Kérjük, nézd meg a blogját atPowerShellExplained.com.

alapvető terminológia

néhány alapvető kifejezést le kell fednünk, mielőtt beleugrunk ebbe.

Exception

a kivétel olyan esemény, amely akkor jön létre, amikor a normál hibakezelés nem képes kezelni a problémát.,Megpróbálja megosztani a számot nullával vagy elfogy a memória példák valamit, ami létrehoz anexception. Előfordul, hogy a szerző a kódot használ létrehoz kivételeket bizonyos kérdésekamikor azok megtörténnek.

dobás és fogás

Ha kivétel történik, azt mondjuk, hogy kivételt dobnak. Ahhoz, hogy kezelni tudja a dobott kivételt, akkormeg kell fogni. Ha egy kivételt dobnak, és valami nem ragadja meg, akkor a szkript leáll.

A híváscsomag

a híváscsomag azon funkciók listája, amelyek egymást hívták., Ha EGY függvényt hívunk, akkor hozzáadódik a veremhez vagy a lista tetejéhez. Amikor a funkció kilép vagy visszatér, eltávolításra kerüla veremből.

Ha egy kivételt dobnak, akkor a hívásköteg be van jelölve annak érdekében, hogy egy kivételkezelő elkaphassa.

megszüntető és nem megszüntető hibák

a kivétel általában megszüntető hiba. A dobott kivétel vagy elkapható, vagy ezmegsérti a jelenlegi végrehajtást. Alapértelmezés szerint a Write-Errornem megszüntető hibát generál, és kivétel nélkül hibát ad a kimeneti adatfolyamhoz.,

rámutatok erre, mert aWrite-Error és más nem végződő hibák nem váltják ki acatchértéket.

kivétel lenyelése

Ez az, amikor hibát észlel, csak hogy elnyomja. Tegye ezt óvatosan, mert ez megtehetia problémák megoldása nagyon nehéz.

Basic command syntax

itt egy gyors áttekintést az alapvető kivétel kezelési szintaxis használt PowerShell.

dobás

saját kivételeseményünk létrehozásához kivételt teszünk a throw kulcsszóval.,

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

Ez létrehoz egy futásidejű kivételt, amely megszüntető hiba. Ezt egy catch kezeli az acalling funkcióban, vagy egy ilyen üzenettel kilép a szkriptből.

Write-Error-ErrorAction Stop

megemlítettem, hogyWrite-Error alapértelmezés szerint nem dobja el a megszüntetési hibát. Ha megadja a-ErrorAction Stop, Write-Erroregycatchvégződési hibát generál.,

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

Köszönjük Lee Dailynek, hogy emlékeztette a -ErrorAction Stop használatát.

Parancsmagot -ErrorAction Abba

Ha meg a -ErrorAction Stop bármilyen speciális funkciót, vagy parancsmagot, kiderül, hogy minden Write-Errornyilatkozatok a hibák megszüntetéséről, hogy ne végrehajtás, vagy az, hogy lehet kezelni egy catch.,

Start-Something -ErrorAction Stop

Try/Catch

Az út kivételkezelés működik a PowerShell (sok egyéb nyelvek), hogy első try asection a kódot, ha dob egy hiba, akkor a catch ez. Itt van egy gyors minta.

acatch script csak akkor fut, ha van egy záró hiba. Ha a try helyesen hajt végre, akkor a catchfölé ugrik.,

Try / Finally

néha nem kell kezelni a hibát, de még mindig szükség van néhány kódot végrehajtani, ha egy exceptionhappens vagy sem. Afinally script pontosan ezt teszi.

vessen egy pillantást erre a példára:

bármikor, amikor megnyitja vagy csatlakozik egy erőforráshoz, zárja be. Ha aExecuteNonQuery() throwsan kivétel, a kapcsolat nincs lezárva. Itt van ugyanaz a kód a try/finally blokkban.

ebben a példában a kapcsolat bezáródik, ha hiba van. Azt is zárva van, ha nincserror., Afinally szkript minden alkalommal fut.

mivel nem kapja meg a kivételt, még mindig szaporodik a híváscsomag.

Try/Catch/Finally

It ‘ s ideally valid to use catch and finally together. Az idő nagy részében használni fogja az egyik vagya másik, de előfordulhat, hogy olyan forgatókönyveket talál, ahol mindkettőt használja.

$PSItem

most, hogy megkaptuk az alapokat az útból, egy kicsit mélyebbre áshatunk.,

belül a catchblokk, van egy automatikus változó ($PSItemvagy$_) típusúErrorRecord, amely tartalmazza a kivétel részleteit. Itt van egy gyors áttekintés néhány billentyűzetrőltulajdonságait.

ezekre a példákra aReadAllText érvénytelen elérési utat használtam a kivétel létrehozásához.

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

PSItem.ToString ()

Ez adja a legtisztább üzenetet a naplózásban és az Általános kimenetben., ToString() isautomatically called if $PSItem isautomatically placed inside a string.

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

$PSItem.InvocationInfo

Ez a tulajdonság a PowerShell által gyűjtött további információkat tartalmazza a funkcióról vagy a szkriptről, ahol a kivételt dobták. Itt található aInvocationInfo az Icreated minta kivételéből.

a fontos részletek itt aScriptName, aLine kód és aScriptLineNumberahol a meghívás megkezdődött.

$PSItem.,ScriptStackTrace

Ez a tulajdonság a függvényhívások sorrendjét mutatja, amelyek eljutottak a kódhoz, ahol a kivételt generálták.

csak ugyanabban a szkriptben lévő funkciókhoz hívok, de ez nyomon követné a hívásokat, ha a multiplescripteket bevonják.

$PSItem.Kivétel

Ez a tényleges kivétel, amelyet dobtak.

$PSItem.Kivétel.Üzenet

Ez az általános üzenet, amely leírja a kivételt, és egy jó kiindulási pont, amikorbleshooting. A legtöbb kivételnek van egy alapértelmezett üzenete, de beállítható valami szokásosra is, amikora kivételt dobják.,

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

Ez az üzenet akkor is visszatér, amikor$PSItem.ToString() ha nem volt egy készlet aErrorRecord.

$PSItem.Kivétel.InnerException

kivételek tartalmazhatnak belső kivételeket. Ez gyakran előfordul, amikor a kód, amit hívsz, kivételt képez,és egy másik kivételt dob. Az eredeti kivétel belsejébe kerülaz új kivétel.

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

ezt később újra megvizsgálom, amikor a kivételek újbóli dobásáról beszélek.

$PSItem.Kivétel.,StackTrace

Ez aStackTrace kivétel. A fenti ScriptStackTrace – ot mutattam, de ez a felügyelt kód hívása.

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 )

csak akkor kapja meg ezt a kötegnyomot, ha az eseményt a felügyelt kódból dobják. Hívom a-T .A NETframework közvetlenül működik, így ez minden, amit ebben a példában láthatunk. Általában, amikor egy stack trace-t nézel, azt keresed, hogy hol áll meg a kódod, és mikor kezdődik a rendszerhívás.

kivételekkel dolgozva

Több kivétel van, mint az alapvető szintaxis és kivétel tulajdonságai.,

fogása gépelt kivételek

szelektív lehet a kivételekkel, hogy elkapja. A kivételeknek van egy típusa, amelyet megadhata kifogni kívánt kivétel típusa.

a kivétel típusát minden catch blokk esetén ellenőrizzük, amíg meg nem találjuk az Ön exception.It fontos felismerni, hogy a kivételek örökölhetnek más kivételektől. A fenti példábanFileNotFoundExceptionIOException örökli. Tehát, ha aIOException volt az első, akkor helyette hívnák., Csak egy fogási blokkot hívunk meg, még akkor is, ha több mérkőzés van.

Ha lenneSystem.IO.PathTooLongException, aIOException megegyezik, de ha lenne egyInsufficientMemoryException, akkor semmi sem fogná fel, és szaporítaná a veremet.

fogjon egyszerre több típust

lehetséges több kivételtípust elkapni ugyanazzal a catch állítással.

Köszönjük /u/Sheppard_Ra hogy ezt a kiegészítést javasolta.

dobás gépelt kivételek

akkor dobja gépelt kivételek PowerShell., A throw karakterlánccal történő hívása helyett:

throw "Could not find: $path"

használjon egy ilyen kivételgyorsítót:

throw "Could not find: $path"

de meg kell adnia egy üzenetet, amikor ezt megteszi.

létrehozhat egy új kivételt is, amelyet el kell dobni. Az üzenet nem kötelező, ha ezt megteszi, mert a rendszer alapértelmezett üzenetekkel rendelkezik az összes beépített kivételhez.

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

Ha nem használ PowerShell 5.0 vagy újabb, akkor a régebbi New-Object megközelítést kell használnia.,

gépelt kivétel használatával Ön (vagy mások) a kivételt a korábbi szakaszban említett típus szerint elkaphatja.

Write-Error-Exception

ezeket a gépelt kivételeket hozzáadhatjuk aWrite-Error – hoz, és továbbra iscatch a hibák exceptiontype szerint. Use Write-Error like in these examples:

akkor elkaphatjuk így:

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

a. net kivételek nagy listája

összeállítottam egy mesterlistát a Reddit/r/PowerShell közösség segítségével, amely tartalmaztöbb száz.,Nettó kivételek kiegészítik ezt a bejegyzést.

  • a. net kivételek nagy listája

elkezdem keresni ezt a listát olyan kivételekre, amelyek úgy érzik, hogy jól illeszkednek a misztifikációhoz. Meg kell próbálnia kivételeket használni a System névtérben.

kivételek objektumok

ha sok gépelt kivételt használ, ne feledje, hogy objektumok. Különböző kivételekkülönböző konstruktorokkal és tulajdonságokkal rendelkeznek., Ha megnézzük a FileNotFoundExceptiondocumentation-t a System.IO.FileNotFoundException – hoz, látjuk, hogy egy üzenetben és egy filepath-ban tudunk átadni.

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

és van egy FileName tulajdonság, amely felfedi a fájl elérési útját.

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

egyéb konstruktorok és objektumtulajdonságok esetén olvassa el a.net dokumentációt.

kivétel újbóli dobása

ha minden, amit a catch blokk throw ugyanaz a kivétel, akkor ne catch it., Csak catch kivétel, amelyet kezelni vagy végrehajtani tervez, amikor ithappens.

vannak esetek, amikor azt szeretnénk, hogy végre egy műveletet egy kivétel, de újra dobja a kivétel sosomething downstream tud foglalkozni vele. Tudunk írni egy üzenetet, vagy jelentkezzen a probléma közel, ahol wediscover, de kezelni a problémát tovább a verem.

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

érdekes módon a throw-t a catch – ból hívhatjuk, és újra dobja a currentexceptiont.,

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

szeretnénk újra dobni a kivételt, hogy megőrizze az eredeti végrehajtási információkat, például a forrás scriptand sorszámát. Ha dobunk egy új kivétel ezen a ponton, elrejti, ahol a kivétel kezdődött.

új kivétel újbóli dobása

ha kivételt kap, de egy másikat szeretne dobni, akkor az originalexception-t az újba kell helyeznie. Ez lehetővé teszi, hogy valaki le a verem elérni, mint a$PSItem.Exception.InnerException.

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

$PSCmdlet.,ThrowTerminatingError ()

az egyetlen dolog, amit nem szeretek használni a throw raw kivételeknél az, hogy a hiba messagepoints a throw utasítás, és azt jelzi, hogy a vonal, ahol a probléma.

miután a hibaüzenet azt mondja, hogy a script törött, mert az úgynevezett throw on line 31 abad üzenetet a felhasználók a script látni. Nem mond nekik semmi hasznosat.

Dexter Dhami rámutatott ,hogy aThrowTerminatingError() segítségével kijavíthatom.,

ha feltételezzük, hogyThrowTerminatingError() egyGet-Resource nevű függvény belsejében hívták, akkorez az a hiba, amelyet látnánk.

látja, hogyan mutat aGet-Resource funkcióra, mint a probléma forrására? Ez valami hasznosat mond a felhasználónak.

mert $PSItem egy ErrorRecord, akkor is használhatja ThrowTerminatingError így újra dobni.,

catch{ $PSCmdlet.ThrowTerminatingError($PSItem)}

Ez megváltoztatja a hiba forrását a Parancsmagra, és elrejti a funkció belső oldalait a parancsmag felhasználóitól.

próbálja hozhat létre megszüntető hibák

Kirk Munro rámutat arra, hogy néhány kivétel csak megszüntető hibák, ha végre belültry/catch blokk. Itt van a példa, amit adott nekem, hogy létrehoz egy szakadék nulla futásidejű kivétel.

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

ezután így hívja fel, hogy lássa a hiba generálását, majd továbbra is kiadja az üzenetet.,

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

de azáltal, hogy ugyanazt a kódot a try/catch, látunk valami mást történni.

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

látjuk, hogy a hiba megszüntető hibává válik, és nem adja ki az első üzenetet. Amit nem szeretek, az az, hogy ezt a kódot egy függvényben lehet használni, és másképp működik, ha valaki egy try/catch – t használ.

még nem találkoztam ezzel a kérdéssel, de sarok eset, hogy tisztában legyek.

$PSCmdlet.,ThrowTerminatingError() belül try/catch

Egy árnyalatot a $PSCmdlet.ThrowTerminatingError() az, hogy létrehoz egy megszüntetéséről hiba belül yourCmdlet de kiderült, hogy egy nem megszüntetéséről hiba után elhagyja a Parancsmagot. Ez elhagyja a terheta funkció hívóján, hogy eldöntse, hogyan kell kezelni a hibát. A -ErrorAction Stop vagy egy try{...}catch{...} – ból hívhatják vissza.,

Public function templates

egy utolsó út volt a beszélgetésem Kirk Munro volt, hogy ő helyezi atry{...}catch{...} körül minden begin, process és end blokk minden az ő advancedfunctions. Ezekben az Általános fogási blokkokban egyetlen sorral rendelkezik a$PSCmdlet.ThrowTerminatingError($PSItem) használatával, hogy foglalkozzon a funkcióit elhagyó kivételekkel.

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

mivel minden egy try nyilatkozatban van a funkcióiban, minden következetesen működik., Eztiszta hibákat is ad a végfelhasználónak, amely elrejti a belső kódot a generált hibából.

Trap

a kivételektry/catch aspektusára összpontosítottam. De van egy legacy funkció, amit meg kell említenemmielőtt lezárjuk ezt.

a trap egy szkriptbe vagy függvénybe kerül, hogy elkapjon minden kivételt, amely ebben a hatókörben történik. Amikor egy kivétel történik, a trap kódja végrehajtásra kerül, majd a normál kód folytatódik. Ha több kivétel történik, akkor a csapdát újra meg újra hívják.,

személy szerint soha nem fogadtam el ezt a megközelítést, de látom az értéket admin vagy controller szkriptekben, amelyek minden kivételt tartalmaznak, majd továbbra is végrehajtják.

Záró megjegyzések

a megfelelő kivételkezelés hozzáadása a szkriptekhez nem csak stabilabbá teszi őket, hanem könnyebbé teszi a kivételek elhárítását.

sok időt töltöttem a throw beszélgetéssel, mert ez egy alapvető koncepció, amikor az exceptionhandling-ről beszélünk., PowerShell is adott nekünk Write-Error, amely kezeli az összes olyan helyzetet, ahol athrow. Tehát ne gondolja, hogy a throw – ot kell használnia, miután elolvasta ezt.

most, hogy időt vettem arra, hogy ebben a részletben írjak a kivételkezelésről, átkapcsolom a Write-Error -Stop használatával, hogy hibákat generáljak a kódomban. Én is megyek, hogy takeKirk tanácsát, és hogy ThrowTerminatingError én Goto kivétel kezelő minden funkció.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük