- 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-Error
nem 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-Error
egycatch
vé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-Error
nyilatkozatok 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 catch
fö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 catch
blokk, van egy automatikus változó ($PSItem
vagy$_
) 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 aScriptLineNumber
ahol 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ábanFileNotFoundException
IOException
ö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ó.