Meistern Sie PowerShell Try Catch Blöcke mit Beispielen

Haben Sie jemals ein Skript oder einen PowerShell-Cmdlet ausgeführt und wurden mit einer Wand aus Text – in Rot – wie der unten gezeigten konfrontiert?

Example of errors in PowerShell

Fehler können überwältigend und verwirrend sein. Und vor allem sind Fehler oft schwer lesbar, was es nahezu unmöglich macht, festzustellen, was und wo das Skript schief gelaufen ist.

Zum Glück haben Sie in PowerShell einige Optionen, um dies durch Fehlerbehandlung zu verbessern. Mit Fehlerbehandlung können Fehler gefiltert und in einer Weise angezeigt werden, die es einfacher macht, sie zu verstehen. Und das Verständnis des Fehlers erleichtert das Hinzufügen von mehr Logik zur Fehlerbehandlung.

In diesem Artikel erfahren Sie mehr über Fehler in PowerShell und wie sie abgefangen werden können, um Fehlerbehandlung mit den PowerShell Try Catch-Blöcken (und finally-Blöcken) durchzuführen.

Verständnis, wie Fehler in PowerShell funktionieren

Bevor wir uns mit der Fehlerbehandlung beschäftigen, wollen wir zunächst einige Konzepte rund um Fehler in PowerShell erläutern. Das Verständnis von Fehlern kann zu besseren Fehlerbehandlungsstrategien führen.

Die Automatische Variable $Error

In PowerShell gibt es viele automatische Variablen, und eine davon ist die Automatische Variable $Error. PowerShell verwendet die Variable $Error, um alle Fehler zu speichern, die in der Sitzung auftreten. Die Variable $Error ist ein Array von Fehlern, sortiert nach dem neuesten.

Wenn Sie eine PowerShell-Sitzung öffnen, ist die Variable $Error zu Beginn leer. Sie können dies überprüfen, indem Sie die Variable $Error aufrufen.

The $Error variable is empty

Wie Sie sehen können, ist die Variable $Error zu Beginn leer. Sobald jedoch ein Fehler auftritt, wird der Fehler zur $Error-Variable hinzugefügt und gespeichert.

Im folgenden Beispiel wird der Fehler absichtlich generiert, indem ein Dienstname angefordert wird, der nicht existiert.

PS> Get-Service xyz
PS> $Error
PS> $Error.Count
The error is added to the $Error variable

Wie Sie aus der obigen Ausgabe sehen können, wurde der generierte Fehler zur $Error-Variable hinzugefügt.

Die Variable $Error enthält eine Sammlung von Fehlern, die in der PowerShell-Sitzung generiert wurden. Jeder Fehler kann durch Aufrufen seiner Arrayposition abgerufen werden. Der neueste Fehler befindet sich immer an Index 0.

Zum Beispiel kann der neueste Fehler mit $Error[0] abgerufen werden.

Die Eigenschaften des Objekts $Error

Da in PowerShell alles ein Objekt ist, ist die Variable $Error ein Objekt und Objekte haben Eigenschaften. Wenn Sie die Variable $Error an den Befehl Get-Member weiterleiten, sollten Sie die Liste der verfügbaren Eigenschaften sehen können.

$Error | Get-Member
The $Error object properties

Um den Grund für den Fehler zu ermitteln, können Sie den Inhalt der Eigenschaft InvocationInfo mit dem folgenden Befehl anzeigen.

$Error[0].InvocationInfo
The InvocationInfo property

Nun können Sie dasselbe mit den anderen Eigenschaften tun und herausfinden, welche weiteren Informationen Sie finden können!

Beendigende Fehler

Beendigungsfehler unterbrechen den Ausführungsfluss, wenn sie von PowerShell im Gegensatz zu nicht beendigenden Fehlern festgestellt werden. Es gibt mehrere Möglichkeiten, wie ein Beendigungsfehler auftreten kann. Ein Beispiel ist, wenn Sie einen cmdlet mit einem nicht vorhandenen Parameter aufrufen.

Wie Sie unten auf dem Screenshot sehen können, wenn der Befehl Get-Process notepad ausgeführt wird, ist der Befehl gültig und die Details des notepad-Prozesses werden angezeigt.

The notepad process details

Aber wenn ein nicht vorhandener Parameter verwendet wird, wie z.B. Get-Process notepad -handle 251, zeigt das cmdlet einen Fehler an, dass der handle-Parameter ungültig ist. Dann beendet das cmdlet ohne Anzeige der Details des notepad-Prozesses.

Error is thrown because the parameter is invalid

Nicht-beendigende Fehler

Nicht-beendigende Fehler sind Fehler, die die Ausführung des Skripts oder Befehls nicht stoppen. Schauen Sie sich zum Beispiel den folgenden Code an. Dieser Code ruft die Liste der Dateinamen aus der Datei fileslist.txt ab. Anschließend geht das Skript jeden Dateinamen durch, liest den Inhalt jeder Datei und gibt ihn auf dem Bildschirm aus.

$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

Der Inhalt der Datei filelist.txt sind die Dateinamen in der untenstehenden Liste dargestellt.

File_1.log
File_2.log
File_3.log
File_4.log
File_5.log
File_6.log
File_7.log
File_8.log
File_9.log
File_10.log

Aber was ist, wenn File_6.log tatsächlich nicht existiert? Wenn Sie den Code ausführen, erwarten Sie einen Fehler, da das Skript die File_6.log-Datei nicht finden kann. Sie sehen eine ähnliche Ausgabe wie unten angezeigt.

Example of non-terminating error

Wie Sie am Screenshot des oben stehenden Ergebnisses sehen können, konnte das Skript die ersten fünf Dateien in der Liste lesen, aber als es versuchte, die Datei File_6.txt zu lesen, wurde ein Fehler zurückgegeben. Das Skript fuhr dann damit fort, den Rest der Dateien zu lesen, bevor es beendet wurde. Es wurde nicht beendet.

Die Variable $ErrorActionPreference

Bisher haben Sie gelernt, dass es terminierende und nicht-terminierende Fehler gibt und wie sie sich voneinander unterscheiden. Aber wussten Sie, dass ein nicht-terminierender Fehler dazu gezwungen werden kann, wie ein terminierender Fehler behandelt zu werden?

PowerShell hat ein Konzept namens Referenzvariablen. Diese Variablen werden verwendet, um das Verhalten von PowerShell auf viele verschiedene Arten zu ändern. Eine dieser Variablen heißt $ErrorActionPreference.

Die Variable $ErrorActionPreference wird verwendet, um die Art und Weise zu ändern, wie PowerShell nicht-terminierende Fehler behandelt. Standardmäßig ist der Wert von $ErrorActionPreference auf Continue festgelegt. Wenn Sie den Wert der Variable $ErrorActionPreference auf STOP ändern, zwingt PowerShell dazu, alle Fehler als terminierende Fehler zu behandeln.

Verwenden Sie den folgenden Code, um den Wert von $ErrorActionPreference zu ändern.

$ErrorActionPreference = "STOP"

Um mehr über andere gültige Werte der Variablen $ErrorActionPreference zu erfahren, besuchen Sie PowerShell ErrorActionPreference.

Verweisen Sie nun auf das Beispiel in Abschnitt Nicht-terminierende Fehler in diesem Artikel. Das Skript kann so geändert werden, dass die Änderung in $ErrorActionPreference wie im folgenden Code angezeigt wird:

# Setzen des Werts von $ErrorActionPreference auf STOP
$ErrorActionPreference = "STOP"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
    Get-Content $file
}

Wenn der oben modifizierte Code ausgeführt wird und der Wert von $ErrorActionPreference auf den Standardwert Continue gesetzt ist, verhält er sich anders als zuvor.

Forcing a terminating error using the $ErrorActionPreference variable

Wie im obigen Screenshot zu sehen ist, konnte das Skript die ersten fünf Dateien in der Liste lesen, aber als es versuchte, die Datei Datei_6.txt zu lesen, trat ein Fehler auf, da die Datei nicht gefunden wurde. Das Skript wurde dann beendet und der Rest der Dateien wurde nicht gelesen.

Der Wert von $ErrorActionPreference ist nur in der aktuellen PowerShell-Sitzung gültig. Er wird auf den Standardwert zurückgesetzt, sobald eine neue PowerShell-Sitzung gestartet wird.

Der gemeinsame Parameter ErrorAction

Wenn der Wert $ErrorActionPreference auf die PowerShell-Sitzung angewendet wird, gilt der Parameter ErrorAction für alle cmdlets, die allgemeine Parameter unterstützen. Der Parameter ErrorAction akzeptiert dieselben Werte wie die Variable $ErrorActionPreference.

Der Wert des Parameters ErrorAction hat Vorrang vor dem Wert der Variable $ErrorActionPreference.

Lassen Sie uns zum vorherigen Beispiel zurückkehren und denselben Code verwenden. Dieses Mal wird jedoch der Parameter ErrorAction zur Zeile Get-Content hinzugefügt.

# Setzen Sie den Wert von $ErrorActionPreference auf Standard (CONTINUE)
$ErrorActionPreference = "CONTINUE"
$file_list =  Get-Content .\filelist.txt
foreach ($file in $file_list) {
    Write-Output "Reading file $file"
		# Verwenden Sie den allgemeinen Parameter -ErrorAction
		Get-Content $file -ErrorAction STOP
}

Nach Ausführung des geänderten Codes sehen Sie, dass das Skript trotzdem beendet wird, obwohl $ErrorActionPreference auf Continue gesetzt ist. Das Skript wurde beendet, weil der Wert des PowerShell-ErrorAction-Parameters in Get-Content auf STOP gesetzt ist.

Forcing a terminating error using the PowerShell ErrorAction parameter

Verwendung von PowerShell Try Catch-Blöcken

Bis jetzt haben Sie etwas über PowerShell-Fehler und die Funktionsweise der Variable $ErrorActionPreference und des PowerShell-ErrorAction-Parameters gelernt. Jetzt ist es an der Zeit, dass Sie das Gute kennenlernen – die PowerShell-Try Catch Finally-Blöcke.

PowerShell try catch Blöcke (und optionaler finally block) dienen dazu, einen Bereich des Codes einzufassen und eventuelle Fehler abzufangen.

Der folgende Code zeigt die Syntax des Try Statements.

try {
    <statement list>
}
catch [[<error type>][',' <error type>]*]{
    <statement list>
}
finally {
    <statement list>
}

Der Try Block enthält den Code, den PowerShell „versuchen“ und auf Fehler überwachen soll. Wenn der Code im Try Block einen Fehler erzeugt, wird der Fehler der $Error Variable hinzugefügt und an den Catch Block übergeben.

Der Catch Block enthält die Aktionen, die ausgeführt werden sollen, wenn ein Fehler vom Try Block empfangen wird. Es können mehrere Catch Blöcke in einem Try Statement vorhanden sein.

Der Finally Block enthält den Code, der am Ende des Try Statements ausgeführt wird. Dieser Block wird unabhängig davon ausgeführt, ob ein Fehler aufgetreten ist oder nicht.

Auffangen von nicht spezifischen Fehlern (Catch-All) mit PowerShell ErrorAction

A simple Try statement contains a Try and a Catch block. The Finally block is optional.

Zum Beispiel, um eine nicht spezifische Ausnahme abzufangen, sollte der Catch Parameter leer sein. Der folgende Beispielcode verwendet das gleiche Skript wie im Abschnitt Die Variable $ErrorActionPreference, wurde jedoch so geändert, dass die Try Catch Blöcke verwendet werden.

Wie Sie aus dem folgenden Code sehen können, ist dieses Mal die foreach Anweisung im Try Block eingeschlossen. Dann enthält ein Catch Block den Code, um den Text „Ein Fehler ist aufgetreten“ anzuzeigen, falls ein Fehler auftritt. Der Code im Finally Block löscht einfach die $Error Variable.

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch {
    Write-Host "An Error Occured" -ForegroundColor RED
}
finally {
    $Error.Clear()
}

Der obenstehende Code gibt nach dem Ausführen in PowerShell die folgende Ausgabe zurück.

Script terminated when an error occurred

Die obige Ausgabe zeigt, dass das Skript einen Fehler festgestellt hat, den Code im Catch-Block ausgeführt und dann beendet hat.

Der Fehler wurde behandelt, was der Zweck der Fehlerbehandlung war. Allerdings war die angezeigte Fehlermeldung zu allgemein. Um einen detaillierteren Fehler anzuzeigen, könnten Sie auf die Exception-Eigenschaft des Fehlers zugreifen, der vom Try-Block übergeben wurde.

Der folgende Code wurde modifiziert, insbesondere der Code im Catch-Block, um die Ausnahmemeldung des aktuellen Fehlers anzuzeigen, der an die Pipeline übergeben wurde – $PSItem.Exception.Message

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch {
    Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
    $Error.Clear()
}

Wenn der modifizierte Code oben ausgeführt wird, wird die angezeigte Meldung diesmal viel detaillierter sein.

Script terminated with a descriptive error message

Auffangen spezifischer Fehler

Es gibt Situationen, in denen eine allgemeine Fehlerbehandlung nicht der geeignetste Ansatz ist. Möglicherweise möchten Sie, dass Ihr Skript eine Aktion ausführt, die von der Art des aufgetretenen Fehlers abhängt.

Wie bestimmen Sie den Fehlertyp? Indem Sie den Wert TypeName der Exception-Eigenschaft des letzten Fehlers überprüfen. Um den Fehlertyp aus dem vorherigen Beispiel zu ermitteln, verwenden Sie diesen Befehl:

$Error[0].Exception | Get-Member

Das Ergebnis des obigen Codes würde ähnlich wie im Screenshot unten aussehen. Wie Sie sehen können, wird der Wert von TypeName angezeigt – System.Management.Automation.ItemNotFoundException.

Getting the error TypeName value

Jetzt, da Sie den Fehlertyp kennen, den Sie abfangen müssen, ändern Sie den Code, um ihn spezifisch abzufangen. Wie Sie aus dem unten stehenden modifizierten Code sehen können, gibt es nun zwei Catch-Blöcke. Der erste Catch-Block fängt einen bestimmten Fehler ab (System.Management.Automation.ItemNotFoundException). Im Gegensatz dazu enthält der zweite Catch-Block die generische, alles abfangende Fehlermeldung.

$file_list = Get-Content .\filelist.txt
try {
    foreach ($file in $file_list) {
        Write-Output "Reading file $file"
        Get-Content $file -ErrorAction STOP
    }
}
catch [System.Management.Automation.ItemNotFoundException]{
    Write-Host "The file $file is not found." -ForegroundColor RED
}
catch {
    Write-Host $PSItem.Exception.Message -ForegroundColor RED
}
finally {
    $Error.Clear()
}

Der folgende Screenshot zeigt die Ausgabe des oben modifizierten Codes.

Script terminated with a specific error message

Schlussfolgerung

In diesem Artikel haben Sie Fehler in PowerShell, deren Eigenschaften und wie Sie den spezifischen Fehlertyp bestimmen können, kennengelernt. Sie haben auch den Unterschied zwischen der Verwendung der Variablen $ErrorActionPreference und dem PowerShell-Parameter ErrorAction gelernt, wie PowerShell nicht-terminierende Fehler behandelt.

Sie haben auch gelernt, wie Sie die PowerShell-Blöcke Try Catch Finally verwenden können, um Fehlerbehandlungen durchzuführen, egal ob für spezifische Fehler oder einen allgemeinen Ansatz.

Die in diesem Artikel gezeigten Beispiele demonstrieren nur die Grundlagen, wie die Try Catch Finally-Blöcke funktionieren. Das Wissen, das Sie hoffentlich in diesem Artikel gewonnen haben, sollte Ihnen helfen, Fehlerbehandlungen in Ihren Skripten anzuwenden.

Weiterführende Informationen

Source:
https://adamtheautomator.com/powershell-try-catch/