2013-10-09 3 views
5

Ich versuche, mein Skript zu stoppen, wenn es einen Fehler trifft, und try ... catch zu verwenden, um mir eine einfache Möglichkeit zu geben, den Fehler zu behandeln. Das einfachste Ding der Welt hätte ich mir gedacht, aber ich mache offensichtlich etwas Dummes. Ich habe für ein paar Stunden gelesen und ich bin fest, jede Hilfe wäre sehr praktisch, danke!Wie kann ich versuchen ... fangen und mein Skript stoppen, wenn es einen Fehler gibt?

Hier ist ein Beispiel Code, ich habe erroraction überall platziert, kann nicht scheinen, das verdammte Ding zu stoppen!

$ErrorActionPreference = "Stop" 
try { 
    get-content "c:\GarbageFileName.txt" -ErrorAction stop 
} 
catch { 
    write-output "in catch, I want it to stop now" 
} 
write-output "try-catch finished, script is continuing" 

dieser Text hinzugefügt nächsten Tag * Fantastische Antworten von Leuten, ich wünschte, ich könnte mehr als 1 Antwort auswählen oder hatte genug Ruf für diejenigen zu wählen, die ich ungern didn‘ t Wählen Sie als Antwort, oder sagen Sie Dank irgendwie!

+0

werfen Sie die Ausnahme, die Sie fangen? Ich weiß Powershell nicht, aber das ist, was Sie in Java tun würden. –

+0

In diesem Fall, warum nicht einfach ein 'Test-Path $ TargetFile' und dann' Get-Content' verwenden, wenn es erfolgreich ist? – Eris

Antwort

8

Die ganze Idee einer try/catch Steuerung ist, dass Sie das Skript sagen, was es tun, wenn ein Abschluss Fehler auftritt, statt der Standardaktion der Fehler zu werfen und Stoppen der Skript. Wenn Ihr catch-Block nur eine Nachricht an das Terminal mit Write-Host anzeigt, ist das die einzige Fehlerbehandlung, die es gibt, und das Skript wird von dort fortgesetzt. Wenn Sie darüber nachdenken, würde es teilweise den Zweck von versuchen/fangen besiegen, wenn das Skript automatisch gestoppt wurde, wenn ein Fehler auftritt.

Im catch Block, _ $ wird den Abschluss Fehler an das Errorrecord Objekt festgelegt wird, darstellt, von den Block (das gleiches, die in $ Fehlern gespeichert werden [0]) versuchen.So ist der einfachste Weg, um das Skript zu beenden, ist der Fehler erneut auslösen, die ausgelöst worden wäre, wenn Sie nicht benutzt hatten ein try/catch:

try { 
    Get-Content "c:\GarbageFileName.txt" -ErrorAction stop 
} catch { 
    # Custom action to perform before terminating 
    throw $_ 
} 

Oder, wenn Sie eine benutzerdefinierte Meldung angezeigt werden sollen statt die Standarderrorrecord:

try { 
    Get-Content "c:\GarbageFileName.txt" -ErrorAction stop 
} catch { 
    throw 'Custom error message' 
} 

Oder Sie Pause in Joost Antwort wie vorgeschlagen verwenden können, wenn Sie wollen einfach nur beenden, nachdem Sie mit Ihrem eigenen Fehlerbehandlung fertig sind, ohne einen Fehler an den Fehlerstrom zu werfen.

Oder Sie könnten anspruchsvoller und erstellen Sie Ihr eigenes ErrorRecord-Objekt. Es gibt eine Menge, die Sie damit tun können, es ist ein zu großes Thema, das hier umfassend behandelt werden kann, aber Sie können weitere Informationen über die Syntax erhalten, indem Sie googlen System.Management.Automation.ErrorRecord. Hier ist ein Beispiel von einem meines Skripte zu Ihnen (aus einer Funktion, die eine SQL-Abfrage ausführt, in dem definierten $ query Variable für eine SQL Server-Datenbank) loszuzulegen:

} catch { 
    $ErrorRecord = New-Object System.Management.Automation.ErrorRecord(
    (New-Object Exception("Exception executing the query: $($_.Exception.InnerException.Message)")), 
    $query, 
    [System.Management.Automation.ErrorCategory]::InvalidArgument, 
    $null 
) 
    $ErrorRecord.CategoryInfo.Reason = $_.CategoryInfo.Reason; 
    $ErrorRecord.CategoryInfo.Activity = $_.InvocationInfo.InvocationName; 
    $PSCmdlet.ThrowTerminatingError($ErrorRecord); 
} 

Ein paar Anmerkungen:

  • Sie werden sehen, dass meine benutzerdefinierte Errorrecord schaffen, ich bin mit $ _, die ich das Objekt Errorrecord gerade gesagt enthält der Abschluss Fehler zugeordnet, die in der Block versuchen gefangen wurde. Die Idee besteht darin, einen Teil der Fehlerausgabe anzupassen, während Teile des Standard-ErrorRecord verwendet werden, indem sie den entsprechenden Eigenschaften für das benutzerdefinierte ErrorRecord zugewiesen werden.
  • $ PSCmdlet ist nur verfügbar, wenn Sie am Anfang der Funktion oder des Skripts [CmdletBinding()] deklarieren. Andernfalls können Sie einfach throw $ErrorRecord verwenden, um Ihren benutzerdefinierten Fehler zu werfen. Das Ergebnis wird jedoch mehr Cmdletstil sein, wenn Sie $ PSCmdlet.ThrowTerminatingError verwenden. (throw spuckt die Linie von der Funktion zurück, die den Fehler erzeugte, während $ PSCmdlet.ThrowTerminatingError Ihnen die Linie vom aufrufenden Kontext gibt, in dem die Funktion verwendet wurde. Es ist schwer, in einer Weise zu beschreiben, die ohne Sinn sinnvoll ist zu aufwendig bekommen, aber wenn Sie mit ihm experimentieren werden Sie sehen, was ich meine.)

BTW, ist es überflüssig $ErrorActionPreference = "Stop", zu setzen und dann -ErrorAction Stop verwenden. Die Einstellungsvariable setzt die Standardaktion für alle Cmdlets, und der Schalter -ErrorAction überschreibt die Standardaktion für ein bestimmtes Cmdlet. Sie müssen also nicht zuerst den Standardwert angeben und dann -ErrorAction verwenden, um dieselbe Aktion anzugeben, die Sie gerade ausführen Als Standard festlegen. Was Sie wahrscheinlich tun möchten, ist $ErrorActionPreference = "Stop" weglassen.

+0

Wow, ich wusste nichts über $ PSCmdlet.ThrowTerminatingError - das ist definitiv etwas, das ich bald implementieren werde. Sehr hilfreicher Kommentar in der Tat! – Joost

1

Try-Catch wird eine Ausnahme abfangen und Ihnen erlauben, damit umzugehen, und vielleicht bedeutet es, die Ausführung zu stoppen ... aber das wird das nicht implizit tun. Es wird tatsächlich die Ausnahme konsumieren, es sei denn, Sie wiederholen es. Aber Ihr Problem ist einfacher als das - der try-Block hat Vorrang vor dem -ErrorAction stop in Ihrem Get-Content-Cmdlet. Anstatt also die Ausführung anzuhalten, werden Sie zum Block Catch weitergeleitet und fahren fort, weil im catch-Block keine Fehlerbehandlung stattfindet.

Versuchen Sie, die Try-Catch-Logik aus Ihrem Skript zu entfernen, und lassen Sie das Cmdlet Fehler aus:

get-content "c:\GarbageFileName.txt" -ErrorAction stop 
write-output "You won't reach me if GarbageFileName doesn't exist." 

Und Sie sollten das gewünschte Ergebnis der Ausführung erhalten nicht write-output erreicht:

PS C:\> .\so-test.ps1 
Get-Content : Cannot find path 'C:\GarbageFileName.txt' because it does not exist. 
At C:\so-test.ps1:2 char:12 
+ get-content <<<< "c:\GarbageFileName.txt" -ErrorAction stop 
    + CategoryInfo   : ObjectNotFound: (C:\GarbageFileName.txt:String) [Get-Content], ItemNotFoundException 
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand 
5

Das einzige, was fehlt ist Ihre break-Anweisung im Catch-Block. PowerShell stoppt das Skript nicht, wenn Sie es nicht anweisen.

try { 
    get-content "c:\GarbageFileName.txt" -ErrorAction stop 
} 
catch { 
    write-output "in catch, I want it to stop now" 
    break 
} 
write-output "try-catch finished, script is continuing" 

Und ein kleiner Nachtrag, falls es hilft Ihnen: mit finally, können Sie einige Zeilen Code hinzufügen, die immer dann ausgeführt werden, unabhängig davon, ob eine Ausnahme ausgelöst wurde oder nicht.

try { 
    get-content "c:\GarbageFileName.txt" -ErrorAction stop 
} 
catch { 
    write-output "in catch, I want it to stop now" 
    break 
} 
finally { 
    #do some stuff here that is executed even after the break-statement, for example: 
    Set-Content -Path "f:\GarbageFileName.txt" -Value $null 
} 

#the line below is executed only if the error didn't happen 
write-output "try-catch finished, script is continuing" 
Verwandte Themen