Ich möchte, dass mein PowerShell-Skript beendet wird, wenn einer der von mir ausgeführten Befehle fehlschlägt (wie set -e
in Bash). Ich verwende sowohl Powershell-Befehle ( New-Object System.Net.WebClient
) als auch Programme ( .\setup.exe
).
Ich möchte, dass mein PowerShell-Skript beendet wird, wenn einer der von mir ausgeführten Befehle fehlschlägt (wie set -e
in Bash). Ich verwende sowohl Powershell-Befehle ( New-Object System.Net.WebClient
) als auch Programme ( .\setup.exe
).
Antworten:
$ErrorActionPreference = "Stop"
Sie erhalten einen Teil des Weges dorthin (dh dies funktioniert hervorragend für Cmdlets).
Für EXEs müssen Sie $LastExitCode
sich jedoch nach jedem Exe-Aufruf selbst überprüfen und feststellen, ob dies fehlgeschlagen ist oder nicht. Leider glaube ich nicht, dass PowerShell hier helfen kann, da EXEs unter Windows nicht besonders konsistent sind, was einen Exit-Code für "Erfolg" oder "Fehler" ausmacht. Die meisten folgen dem UNIX-Standard 0, was auf Erfolg hinweist, aber nicht alle. Überprüfen Sie die CheckLastExitCode-Funktion in diesem Blog-Beitrag . Vielleicht finden Sie es nützlich.
throw "$exe failed with exit code $LastExitCode"
wo $ exe nur der Pfad zu ist die EXE.
Sie sollten dies erreichen können, indem Sie die Anweisung $ErrorActionPreference = "Stop"
am Anfang Ihrer Skripte verwenden.
Die Standardeinstellung $ErrorActionPreference
ist Continue
, weshalb Ihre Skripte nach Auftreten von Fehlern weiterhin ausgeführt werden.
Leider reicht aufgrund fehlerhafter Cmdlets wie New-RegKey und Clear-Disk keine dieser Antworten aus. Ich habe mich derzeit in den folgenden Zeilen oben in einem Powershell-Skript niedergelassen, um meine geistige Gesundheit zu erhalten.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
und dann bekommt jeder native Anruf diese Behandlung:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Dieses native Anrufmuster wird für mich langsam so häufig, dass ich wahrscheinlich nach Optionen suchen sollte, um es prägnanter zu gestalten. Ich bin immer noch ein Powershell-Neuling, daher sind Vorschläge willkommen.
Sie benötigen eine etwas andere Fehlerbehandlung für Powershell-Funktionen und zum Aufrufen von Exes, und Sie müssen dem Aufrufer Ihres Skripts unbedingt mitteilen, dass es fehlgeschlagen ist. Aufbauend auf Exec
der Bibliothek Psake stoppt ein Skript mit der folgenden Struktur alle Fehler und kann als Basisvorlage 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
}
Exec { sqlite3.exe -bail some.db "$SQL" }
, die -bail
einen Fehler verursacht , da er es als Cmdlets Parameter zu interpretieren versucht? Dinge in Anführungszeichen zu setzen scheint nicht zu funktionieren. Irgendwelche Ideen?
Eine geringfügige Ä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 Hauptunterschiede hier sind:
Invoke-Command
)-ErrorAction
Verhalten von eingebauten Cmdlets nachInvoke-Call { dotnet build $something }
& @ScriptBlock
und & $ScriptBlock
scheinen das gleiche zu tun. Ich konnte nicht googeln, was der Unterschied in diesem Fall ist
Ich bin hierher gekommen, um dasselbe zu suchen. $ ErrorActionPreference = "Stop" beendet meine Shell sofort, wenn ich die Fehlermeldung (Pause) lieber sehen möchte, bevor sie beendet wird. Auf meine Batch-Sensibilität zurückgreifen:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Ich fand, dass dies für mein spezielles ps1-Skript ziemlich gleich funktioniert:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Das Umleiten stderr
nach stdout
scheint den Trick auch ohne andere Befehle / Scriptblock-Wrapper zu tun, obwohl ich keine Erklärung dafür finden kann, warum es so funktioniert.
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Dies gibt wie erwartet Folgendes aus (der Befehl gibt aws s3 ...
zurück $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
für gut erzogene Programme (die bei Erfolg 0 zurückgeben)?