415 Stimmen

Wie kann ein PowerShell-Skript beim ersten Fehler angehalten werden?

Ich möchte, dass mein PowerShell-Skript anhält, wenn einer der von mir ausgeführten Befehle fehlschlägt (wie set -e in der Bash). Ich verwende beide Powershell-Befehle ( New-Object System.Net.WebClient ) und Programme ( .\setup.exe ).

487voto

Keith Hill Punkte 183005

$ErrorActionPreference = "Stop" bringt Sie einen Teil des Weges dorthin (d.h. dies funktioniert hervorragend für Cmdlets).

Für EXEs müssen Sie jedoch Folgendes überprüfen $LastExitCode selbst nach jedem Exe-Aufruf und stellen Sie fest, ob dieser fehlgeschlagen ist oder nicht. Leider glaube ich nicht, dass PowerShell hier helfen kann, denn unter Windows sind EXEs nicht sehr konsistent, was einen "Erfolg" oder "Misserfolg" als Exit-Code ausmacht. Die meisten folgen dem UNIX-Standard von 0, der Erfolg anzeigt, aber nicht alle tun dies. Schauen Sie sich die CheckLastExitCode-Funktion in diesem Blogbeitrag . Das könnte für Sie nützlich sein.

99voto

goric Punkte 11135

Sie sollten dies mit der Anweisung erreichen können $ErrorActionPreference = "Stop" am Anfang Ihrer Skripte.

Die Standardeinstellung von $ErrorActionPreference es Continue Das ist der Grund, warum Ihre Skripte nach dem Auftreten von Fehlern weiterlaufen.

58voto

aggieNick02 Punkte 2326

Traurig, aufgrund von fehlerhaften Cmdlets wie New-RegKey und Clear-Disk keine dieser Antworten ist ausreichend. Ich habe mich derzeit auf den folgenden Code in einer Datei namens ps_support.ps1 :

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
function ThrowOnNativeFailure {
    if (-not $?)
    {
        throw 'Native Failure'
    }
}

Dann in einer beliebigen Powershell-Datei, nach der CmdletBinding y Param für die Datei (falls vorhanden), habe ich folgendes:

$ErrorActionPreference = "Stop"
. "$PSScriptRoot\ps_support.ps1"

Die duplizierten ErrorActionPreference = "Stop" Linie ist beabsichtigt. Wenn ich gepatzt habe und irgendwie den Pfad zu ps_support.ps1 falsch, das muss nicht stillschweigend scheitern!

Ich behalte ps_support.ps1 an einem gemeinsamen Speicherort für mein Repo/Workspace, so dass sich der Pfad dazu für das Dot-Sourcing ändern kann, je nachdem, wo das aktuelle .ps1 Datei ist.

Jeder einheimische Anruf wird so behandelt:

native_call.exe
ThrowOnNativeFailure

Diese Datei als Dot-Source zu haben, hat mir geholfen, beim Schreiben von Powershell-Skripten den Verstand zu bewahren :-)

22voto

Lucas Punkte 12757

Eine leichte Änderung der Antwort von @alastairtree:

function Invoke-Call {
    param (
        [scriptblock]$ScriptBlock,
        [string]$ErrorAction = $ErrorActionPreference
    )
    & @ScriptBlock
    if (($lastexitcode -ne 0) -and $ErrorAction -eq "Stop") {
        exit $lastexitcode
    }
}

Invoke-Call -ScriptBlock { dotnet build . } -ErrorAction Stop

Die wichtigsten Unterschiede sind hier:

  1. er verwendet das Verb-Nomen (Nachahmung Invoke-Command )
  2. impliziert, dass es die Telefonistin unter der Bettdecke
  3. ahmt nach. -ErrorAction Verhalten von eingebauten Cmdlets
  4. wird mit demselben Exit-Code beendet, anstatt eine Exception mit einer neuen Nachricht auszulösen

17voto

alastairtree Punkte 3535

Sie benötigen eine leicht unterschiedliche Fehlerbehandlung für Powershell-Funktionen und für den Aufruf von Exe-Dateien, und Sie müssen sicher sein, dass Sie den Aufrufer Ihres Skripts über den Fehler informieren. Aufbauend auf Exec aus der Bibliothek Psake, wird ein Skript, das die folgende Struktur hat, bei allen Fehlern anhalten und kann als Grundvorlage für die meisten Skripte verwendet werden.

Set-StrictMode -Version latest
$ErrorActionPreference = "Stop"

# Taken from psake https://github.com/psake/psake
<#
.SYNOPSIS
  This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
  to see if an error occcured. If an error is detected then an exception is thrown.
  This function allows you to run command-line programs without having to
  explicitly check the $lastexitcode variable.
.EXAMPLE
  exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
#>
function Exec
{
    [CmdletBinding()]
    param(
        [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
        [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ("Error executing command {0}" -f $cmd)
    )
    & $cmd
    if ($lastexitcode -ne 0) {
        throw ("Exec: " + $errorMessage)
    }
}

Try {

    # Put all your stuff inside here!

    # powershell functions called as normal and try..catch reports errors 
    New-Object System.Net.WebClient

    # call exe's and check their exit code using Exec
    Exec { setup.exe }

} Catch {
    # tell the caller it has all gone wrong
    $host.SetShouldExit(-1)
    throw
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X