Freigeben über


Alles, was Sie über Ausnahmen wissen wollten

Die Fehlerbehandlung ist nur ein Teil des Lebenszyklus, wenn es um das Schreiben von Code geht. Wir können häufig Bedingungen für das erwartete Verhalten überprüfen und validieren. Wenn das Unerwartete geschieht, wenden wir uns an die Ausnahmebehandlung. Sie können ausnahmen, die vom Code anderer Personen generiert werden, ganz einfach behandeln, oder Sie können eigene Ausnahmen für andere generieren, die behandelt werden sollen.

Hinweis

Die originale Version dieses Artikels erschien auf dem Blog, der von @KevinMarquette geschrieben wurde. Das PowerShell-Team danke Kevin für das Teilen dieser Inhalte mit uns. Bitte schauen Sie sich seinen Blog bei PowerShellExplained.com an.

Grundlegende Terminologie

Wir müssen einige grundlegende Begriffe durchgehen, bevor wir zu diesem Thema übergehen.

Exception

Eine Ausnahme ist wie ein Ereignis, das erstellt wird, wenn die normale Fehlerbehandlung das Problem nicht behandeln kann. Beim Versuch, eine Zahl durch Null zu dividieren oder nicht genügend Arbeitsspeicher zu haben, handelt es sich um Beispiele für etwas, das eine Ausnahme erzeugt. Manchmal erstellt der Autor des codes, den Sie verwenden, Ausnahmen für bestimmte Probleme, wenn sie auftreten.

Werfen und Fangen

Wenn eine Ausnahme auftritt, sagen wir, dass eine Ausnahme ausgelöst wird. Um eine ausgelöste Ausnahme zu behandeln, müssen Sie sie abfangen. Wenn eine Ausnahme ausgelöst wird und sie nicht von etwas abgefangen wird, wird die Ausführung des Skripts beendet.

Der Aufrufstapel

Der Aufrufstapel ist die Liste der Funktionen, die einander aufgerufen haben. Wenn eine Funktion aufgerufen wird, wird sie dem Stapel oder dem Anfang der Liste hinzugefügt. Wenn die Funktion beendet oder zurückgegeben wird, wird sie aus dem Stapel entfernt.

Wenn eine Ausnahme ausgelöst wird, wird dieser Aufrufstapel überprüft, damit ein Ausnahmehandler sie abfangen kann.

Beenden und Nichtbeendungsfehler

Eine Ausnahme ist in der Regel ein Beendigungsfehler. Eine ausgelöste Ausnahme wird entweder abgefangen oder beendet die aktuelle Ausführung. Standardmäßig wird ein nicht beendeter Fehler generiert Write-Error und fügt dem Ausgabedatenstrom einen Fehler hinzu, ohne eine Ausnahme auszuwerfen.

Ich zeige dies, weil Write-Error und andere nicht beendete Fehler dies catchnicht auslösen.

Verschlucken einer Ausnahme

Dies ist der Fall, wenn Sie einen Fehler abfangen, um ihn zu unterdrücken. Machen Sie dies mit Vorsicht, da sie die Problembehandlung sehr schwierig machen kann.

Grundlegende Befehlssyntax

Hier ist eine kurze Übersicht über die grundlegende Syntax für die Ausnahmebehandlung, die in PowerShell verwendet wird.

Werfen

Zum Erstellen eines eigenen Ausnahmeereignisses lösen wir eine Ausnahme mit dem throw Schlüsselwort aus.

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

Dadurch wird eine Laufzeitausnahme erstellt, bei der es sich um einen Abbruchfehler handelt. Es wird von einer catch in einer aufrufenden Funktion behandelt oder beendet das Skript mit einer Nachricht dieser Art.

PS> Start-Something

Bad thing happened
At line:1 char:1
+ throw "Bad thing happened"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Bad thing happened:String) [], RuntimeException
    + FullyQualifiedErrorId : Bad thing happened

Write-Error -ErrorAction Beenden

Ich habe erwähnt, dass Write-Error standardmäßig keinen Beendigungsfehler auslöst. Wenn Sie -ErrorAction Stop angeben, wird von Write-Error ein Beendigungsfehler generiert, der mit einem catch behandelt werden kann.

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

Vielen Dank an Lee Dailey dafür, dass er daran erinnert hat, -ErrorAction Stop auf diese Weise zu verwenden.

Cmdlet -ErrorAction Beenden

Wenn Sie -ErrorAction Stop für eine erweiterte Funktion oder ein Cmdlet angeben, werden alle Write-Error Anweisungen in kritische Fehler umgewandelt, die die Ausführung beenden oder von einer catch behandelt werden können.

Start-Something -ErrorAction Stop

Weitere Informationen zum ErrorAction-Parameter finden Sie unter about_CommonParameters. Weitere Informationen zur Variable $ErrorActionPreference finden Sie unter about_Preference_Variables.

Versuch/Fangen

Die Funktionsweise der Ausnahmebehandlung in PowerShell (und vielen anderen Sprachen) besteht darin, dass Sie zuerst try einen Codeabschnitt verwenden und wenn ein Fehler ausgelöst wird, können catch Sie ihn ausführen. Hier ist ein schnelles Beispiel.

try
{
    Start-Something
}
catch
{
    Write-Output "Something threw an exception"
    Write-Output $_
}

try
{
    Start-Something -ErrorAction Stop
}
catch
{
    Write-Output "Something threw an exception or used Write-Error"
    Write-Output $_
}

Das catch Skript wird nur ausgeführt, wenn ein Beendigungsfehler auftritt. Wenn die try Ausführung ordnungsgemäß erfolgt, überspringt sie die catch. Sie können mithilfe der catch Variablen auf die Ausnahmeinformationen im $_ Block zugreifen.

Try/Finally

Manchmal müssen Sie keinen Fehler behandeln, aber dennoch Code zum Ausführen benötigen, wenn eine Ausnahme auftritt oder nicht. Ein finally Skript macht genau das.

Sehen Sie sich dieses Beispiel an:

$command = [System.Data.SqlClient.SqlCommand]::new(queryString, connection)
$command.Connection.Open()
$command.ExecuteNonQuery()
$command.Connection.Close()

Wenn Sie eine Ressource öffnen oder eine Verbindung herstellen, sollten Sie sie schließen. Wenn die ExecuteNonQuery() Ausnahme ausgelöst wird, wird die Verbindung nicht geschlossen. Hier sehen Sie denselben Code innerhalb eines try/finally Blocks.

$command = [System.Data.SqlClient.SqlCommand]::new(queryString, connection)
try
{
    $command.Connection.Open()
    $command.ExecuteNonQuery()
}
finally
{
    $command.Connection.Close()
}

In diesem Beispiel wird die Verbindung geschlossen, wenn ein Fehler auftritt. Sie wird auch geschlossen, wenn kein Fehler auftritt. Das finally Skript wird jedes Mal ausgeführt.

Da Sie die Ausnahme nicht abfangen, wird sie trotzdem an den Aufrufstapel weitergegeben.

Try/Catch/Endlich

Es ist völlig in Ordnung, catch und finally zusammen zu verwenden. Die meiste Zeit verwenden Sie eine oder die andere, aber Sie können Szenarien finden, in denen Sie beide verwenden.

$PSItem

Da wir nun die Grundlagen hinter uns haben, können wir uns ein wenig vertiefen.

Innerhalb des catch Blocks gibt es eine automatische Variable ($PSItem oder $_) vom Typ ErrorRecord , die die Details zur Ausnahme enthält. Hier ist eine kurze Übersicht über einige der wichtigsten Eigenschaften.

Für diese Beispiele habe ich einen ungültigen Pfad ReadAllText verwendet, um diese Ausnahme zu generieren.

[System.IO.File]::ReadAllText( '\\test\no\filefound.log')

PSItem.ToString()

Dadurch erhalten Sie die sauberste Nachricht, die sie bei der Protokollierung und der allgemeinen Ausgabe verwenden können. ToString() wird automatisch aufgerufen, wenn $PSItem in einer Zeichenfolge platziert ist.

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

catch
{
    Write-Output "Ran into an issue: $PSItem"
}

$PSItem.InvocationInfo

Diese Eigenschaft enthält zusätzliche Informationen, die von PowerShell über die Funktion oder das Skript gesammelt werden, in der die Ausnahme ausgelöst wurde. Dies ist die InvocationInfo Beispiel-Ausnahme, die ich erstellt habe.

PS> $PSItem.InvocationInfo | Format-List *

MyCommand             : Get-Resource
BoundParameters       : {}
UnboundArguments      : {}
ScriptLineNumber      : 5
OffsetInLine          : 5
ScriptName            : C:\blog\throwerror.ps1
Line                  :     Get-Resource
PositionMessage       : At C:\blog\throwerror.ps1:5 char:5
                        +     Get-Resource
                        +     ~~~~~~~~~~~~
PSScriptRoot          : C:\blog
PSCommandPath         : C:\blog\throwerror.ps1
InvocationName        : Get-Resource

Die wichtigen Details hier zeigen den ScriptName, den Line-Code und den ScriptLineNumber, an dem der Aufruf begonnen hat.

$PSItem.ScriptStackTrace

Diese Eigenschaft zeigt die Reihenfolge der Funktionsaufrufe, die zum Code geführt haben, in dem die Ausnahme generiert wurde.

PS> $PSItem.ScriptStackTrace
at Get-Resource, C:\blog\throwerror.ps1: line 13
at Start-Something, C:\blog\throwerror.ps1: line 5
at <ScriptBlock>, C:\blog\throwerror.ps1: line 18

Ich mache nur Aufrufe an Funktionen im selben Skript, aber dies würde die Aufrufe nachverfolgen, wenn mehrere Skripts beteiligt waren.

$PSItem.Exception

Dies ist die tatsächliche Ausnahme, die ausgelöst wurde.

$PSItem.Exception.Message

Dies ist die allgemeine Meldung, die die Ausnahme beschreibt und ein guter Ausgangspunkt bei der Problembehandlung ist. Die meisten Ausnahmen weisen eine Standardmeldung auf, können aber auch auf einen benutzerdefinierten Wert festgelegt werden, wenn die Ausnahme ausgelöst wird.

PS> $PSItem.Exception.Message

Exception calling "ReadAllText" with "1" argument(s): "The network path was not found."

Dies ist auch die Nachricht, die zurückgegeben wird, wenn $PSItem.ToString() aufgerufen wird, falls keine auf ErrorRecord festgelegt wurde.

$PSItem.Exception.InnerException

Ausnahmen können innere Ausnahmen enthalten. Dies ist häufig der Fall, wenn der Code, den Sie aufrufen, eine Ausnahme abfängt und eine andere Ausnahme auslöst. Die ursprüngliche Ausnahme wird in der neuen Ausnahme platziert.

PS> $PSItem.Exception.InnerExceptionMessage
The network path was not found.

Ich werde später darauf zurückkommen, wenn ich über das erneute Auslösen von Ausnahmen spreche.

$PSItem.Exception.StackTrace

Dies ist das StackTrace für die Ausnahme. Ich habe ScriptStackTrace oben gezeigt, aber dieser ist für die Aufrufe von verwaltetem Code.

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 )

Sie erhalten diese Stapelablaufverfolgung nur, wenn das Ereignis aus verwaltetem Code ausgelöst wird. Ich rufe eine .NET Framework-Funktion direkt auf, daher ist das alles, was wir in diesem Beispiel sehen können. Im Allgemeinen suchen Sie beim Betrachten eines Stapel-Traces nach dem Punkt, an dem der Code gestoppt wird und die Systemaufrufe beginnen.

Arbeiten mit Ausnahmen

Es gibt mehr Ausnahmen als die grundlegenden Syntax- und Ausnahmeeigenschaften.

Abfangen von typierten Ausnahmen

Sie können mit den ausnahmen, die Sie abfangen, selektiv sein. Ausnahmen haben einen Typ, und Sie können den Typ der Ausnahme angeben, die Sie abfangen möchten.

try
{
    Start-Something -Path $path
}
catch [System.IO.FileNotFoundException]
{
    Write-Output "Could not find $path"
}
catch [System.IO.IOException]
{
        Write-Output "IO error with the file: $path"
}

Der Ausnahmetyp wird für jeden catch Block überprüft, bis ein Block gefunden wird, der Ihrer Ausnahme entspricht. Es ist wichtig zu erkennen, dass Ausnahmen von anderen Ausnahmen erben können. Im obigen FileNotFoundException Beispiel erbt von IOException. Wenn IOException zuerst käme, würde es stattdessen aufgerufen werden. Es wird nur ein Catch-Block aufgerufen, selbst wenn es mehrere Treffer gibt.

Wenn wir ein System.IO.PathTooLongException hätten, würde das IOException übereinstimmen, aber wenn wir ein InsufficientMemoryException hätten, würde nichts es auffangen, und es würde sich im Stapel nach oben ausbreiten.

Gleichzeitiges Abfangen mehrerer Typen

Es ist möglich, mehrere Ausnahmetypen mit derselben catch Anweisung abzufangen.

try
{
    Start-Something -Path $path -ErrorAction Stop
}
catch [System.IO.DirectoryNotFoundException],[System.IO.FileNotFoundException]
{
    Write-Output "The path or file was not found: [$path]"
}
catch [System.IO.IOException]
{
    Write-Output "IO error with the file: [$path]"
}

Vielen Dank an Redditor u/Sheppard_Ra für das Vorschlagen dieser Ergänzung.

Auslösen von typierten Ausnahmen

Sie können typierte Ausnahmen in PowerShell auslösen. Statt mit einer Zeichenfolge aufzurufen throw :

throw "Could not find: $path"

Verwenden Sie einen Ausnahmebeschleuniger wie folgt:

throw [System.IO.FileNotFoundException] "Could not find: $path"

Sie müssen jedoch eine Nachricht angeben, wenn Sie dies tun.

Sie können auch eine neue Instanz einer Ausnahme erstellen, die ausgelöst werden soll. Die Nachricht ist optional, wenn Sie dies tun, da das System Standardmeldungen für alle integrierten Ausnahmen enthält.

throw [System.IO.FileNotFoundException]::new()
throw [System.IO.FileNotFoundException]::new("Could not find path: $path")

Wenn Sie PowerShell 5.0 oder höher nicht verwenden, müssen Sie den älteren New-Object Ansatz verwenden.

throw (New-Object -TypeName System.IO.FileNotFoundException )
throw (New-Object -TypeName System.IO.FileNotFoundException -ArgumentList "Could not find path: $path")

Mithilfe einer eingegebenen Ausnahme können Sie (oder andere) die Ausnahme anhand des Typs abfangen, wie im vorherigen Abschnitt erwähnt.

Write-Error -Exception

Wir können diese typisierten Ausnahmen zu Write-Error hinzufügen, und weiterhin können wir die Fehler nach Ausnahmetyp erfassen. Verwenden Sie Write-Error wie in den folgenden Beispielen:

# with normal message
Write-Error -Message "Could not find path: $path" -Exception ([System.IO.FileNotFoundException]::new()) -ErrorAction Stop

# With message inside new exception
Write-Error -Exception ([System.IO.FileNotFoundException]::new("Could not find path: $path")) -ErrorAction Stop

# Pre PS 5.0
Write-Error -Exception ([System.IO.FileNotFoundException]"Could not find path: $path") -ErrorAction Stop

Write-Error -Message "Could not find path: $path" -Exception (New-Object -TypeName System.IO.FileNotFoundException) -ErrorAction Stop

Dann können wir es auf folgende Weise fangen:

catch [System.IO.FileNotFoundException]
{
    Write-Log $PSItem.ToString()
}

Die große Liste der .NET-Ausnahmen

Ich habe eine Masterliste mit Hilfe der Reddit-Community r/PowerShell kompiliert, die Hunderte von .NET-Ausnahmen enthält, um diesen Beitrag zu ergänzen.

Ich beginne mit der Suche nach dieser Liste nach Ausnahmen, die sich so fühlen, als wären sie gut für meine Situation geeignet. Sie sollten versuchen, Ausnahmen im Basisnamespace System zu verwenden.

Ausnahmen sind Objekte

Wenn Sie mit der Verwendung vieler typierter Ausnahmen beginnen, denken Sie daran, dass sie Objekte sind. Verschiedene Arten von Ausnahmen haben unterschiedliche Konstruktoren und Eigenschaften. Wenn wir uns die FileNotFoundException-DokumentationSystem.IO.FileNotFoundExceptionansehen, sehen wir, dass wir eine Nachricht und einen Dateipfad übergeben können.

[System.IO.FileNotFoundException]::new("Could not find file", $path)

Außerdem verfügt sie über eine FileName Eigenschaft, die diesen Dateipfad verfügbar macht.

catch [System.IO.FileNotFoundException]
{
    Write-Output $PSItem.Exception.FileName
}

Weitere Konstruktoren und Objekteigenschaften finden Sie in der .NET-Dokumentation .

Erneutes Auslösen einer Ausnahme

Wenn Sie in Ihrem catch Block nur die gleiche Ausnahme throw behandeln, dann catchen Sie es nicht. Sie sollten nur catch eine Ausnahme werfen, die Sie behandeln möchten oder eine Aktion ausführen möchten, wenn dies geschieht.

Es gibt Zeiten, in denen Sie eine Aktion bei einer Ausnahme ausführen möchten, aber die Ausnahme erneut werfen möchten, damit etwas Nachgelagertes damit umgehen kann. Wir könnten eine Nachricht schreiben oder das Problem in der Nähe der Stelle protokollieren, an der wir es entdecken, aber das Problem weiter oben im Stapel behandeln.

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

Interessanterweise können wir throw von innerhalb des catch die aktuelle Ausnahme erneut auslösen.

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

Wir möchten die Ausnahme erneut auslösen, um die ursprünglichen Ausführungsinformationen wie Quellskript und Zeilennummer beizubehalten. Wenn an diesem Punkt eine neue Ausnahme ausgelöst wird, wird dadurch verschleiert, wo die Ausnahme ursprünglich begann.

Erneutes Auslösen einer Ausnahme

Wenn Sie eine Ausnahme abfangen, aber eine andere auslösen möchten, sollten Sie die ursprüngliche Ausnahme in die neue Ausnahme schachteln. Dies ermöglicht es jemandem, in der Stapelreihenfolge darauf zuzugreifen als die $PSItem.Exception.InnerException.

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

$PSCmdlet.ThrowTerminatingError()

Das eine, was ich bei der Verwendung von throw für direkte Ausnahmen nicht mag, ist, dass die Fehlermeldung auf die throw Anweisung zeigt und angibt, dass diese Zeile der Ort ist, an dem das Problem liegt.

Unable to find the specified file.
At line:31 char:9
+         throw [System.IO.FileNotFoundException]::new()
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], FileNotFoundException
    + FullyQualifiedErrorId : Unable to find the specified file.

Wenn die Fehlermeldung besagt, dass mein Skript fehlerhaft ist, weil ich throw in Zeile 31 aufgerufen habe, ist das eine schlechte Nachricht für die Benutzer Ihres Skripts. Es teilt ihnen nichts Nützliches mit.

Dexter Dhami wies darauf hin, dass ich ThrowTerminatingError() verwenden kann, um das zu korrigieren.

$PSCmdlet.ThrowTerminatingError(
    [System.Management.Automation.ErrorRecord]::new(
        ([System.IO.FileNotFoundException]"Could not find $Path"),
        'My.ID',
        [System.Management.Automation.ErrorCategory]::OpenError,
        $MyObject
    )
)

Wenn wir davon ausgehen, dass ThrowTerminatingError() innerhalb einer Funktion namens Get-Resource aufgerufen wurde, dann ist dies der Fehler, den wir sehen würden.

Get-Resource : Could not find C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework\.NETPortable\v4.6\System.IO.xml
At line:6 char:5
+     Get-Resource -Path $Path
+     ~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Get-Resource], FileNotFoundException
    + FullyQualifiedErrorId : My.ID,Get-Resource

Sehen Sie, wie sie auf die Get-Resource Funktion als Quelle des Problems verweist? Das teilt dem Benutzer etwas Nützliches mit.

Da $PSItem ein ErrorRecord ist, können wir ThrowTerminatingError auf diese Weise verwenden, um es erneut auszulösen.

catch
{
    $PSCmdlet.ThrowTerminatingError($PSItem)
}

Dies ändert die Quelle des Fehlers auf das Cmdlet und verbirgt die Interna Ihrer Funktion vor den Benutzern Ihres Cmdlets.

Versuchen Sie, Beendigungsfehler zu erstellen

Kirk Munro weist darauf hin, dass einige Ausnahmen nur Fehler beenden, wenn sie in einem try/catch Block ausgeführt werden. Hier ist das Beispiel, das er mir gegeben hat, die eine Trennlinie durch null Laufzeit-Ausnahme generiert.

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

Rufen Sie es dann wie folgt auf, um den Fehler zu erzeugen und die Nachricht weiterhin auszugeben.

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

Aber durch das Platzieren desselben Codes in einem try/catch sehen wir, dass etwas anderes passiert.

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

Wir sehen, dass der Fehler zu einem Endfehler wird und die erste Nachricht nicht ausgegeben wird. Was mir an diesem hier nicht gefällt, ist, dass man diesen Code in einer Funktion verwenden kann und er sich anders verhält, wenn jemand eine try/catch verwendet.

Ich bin selbst nicht auf Probleme gestoßen, aber es ist ein Sonderfall, dessen man sich bewusst sein sollte.

$PSCmdlet.ThrowTerminatingError() innerhalb von try/catch

Eine Nuance von $PSCmdlet.ThrowTerminatingError() besteht darin, dass innerhalb des Cmdlets ein Beendigungsfehler entsteht, der jedoch zu einem nicht-terminierenden Fehler wird, nachdem das Cmdlet verlassen wurde. Dadurch liegt die Verantwortung beim Aufrufer Ihrer Funktion, zu entscheiden, wie der Fehler behandelt werden soll. Sie können ihn wieder in einen Beendigungsfehler umwandeln, indem sie -ErrorAction Stop verwenden oder es aus einem try{...}catch{...} heraus aufrufen.

Vorlagen für öffentliche Funktionen

Eine letzte Erfahrung aus meiner Unterhaltung mit Kirk Munro war, dass er einen try{...}catch{...} um jeden begin, process und end Block in all seinen erweiterten Funktionen platziert. In diesen generischen Catch-Blöcken hat er eine einzige Zeile$PSCmdlet.ThrowTerminatingError($PSItem), um alle Ausnahmen zu behandeln, die beim Verlassen seiner Funktionen auftreten.

function Start-Something
{
    [CmdletBinding()]
    param()

    process
    {
        try
        {
            ...
        }
        catch
        {
            $PSCmdlet.ThrowTerminatingError($PSItem)
        }
    }
}

Da sich alles in einer try Aussage innerhalb seiner Funktionen befindet, wirkt alles konsequent. Dies führt dazu, dass Endbenutzer klare Fehlermeldungen erhalten, die den internen Code aus dem generierten Fehler ausblenden.

Falle

Ich habe mich auf den try/catch Aspekt der Ausnahmen konzentriert. Aber es gibt ein veraltetes Feature, das ich erwähnen muss, bevor wir zum Ende kommen.

A trap wird in ein Skript oder eine Funktion eingefügt, um alle Ausnahmen abzufangen, die in diesem Bereich auftreten. Wenn eine Ausnahme auftritt, wird der Code in trap ausgeführt, und der normale Code wird weiter ausgeführt. Wenn mehrere Ausnahmen auftreten, wird die Falle immer wieder aufgerufen.

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

throw [System.Exception]::new('first')
throw [System.Exception]::new('second')
throw [System.Exception]::new('third')

Ich habe diesen Ansatz persönlich nie übernommen, aber ich kann den Wert in Administrator- oder Controllerskripts sehen, die alle Ausnahmen protokollieren und dann weiterhin ausgeführt werden.

Schlusswort

Das Hinzufügen einer ordnungsgemäßen Ausnahmebehandlung zu Ihren Skripts macht sie nicht nur stabiler, sondern erleichtert ihnen auch die Problembehandlung für diese Ausnahmen.

Ich habe viel Zeit damit verbracht, darüber zu sprechen throw, weil es ein Kernkonzept bei der Behandlung von Ausnahmen ist. PowerShell hat uns auch Write-Error gegeben, die alle Situationen behandeln, in denen Sie throw verwenden würden. Denken Sie nicht, dass Sie throw nach dem Lesen verwenden müssen.

Da ich mir nun die Zeit genommen habe, so ausführlich über die Ausnahmebehandlung zu schreiben, werde ich zu Write-Error -Stop wechseln, um Fehler in meinem Code zu erzeugen. Ich werde auch Kirks Rat befolgen und ThrowTerminatingError zu meinem Goto-Ausnahmebehandler für jede Funktion machen.