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
).
Antworten
Zu viele Anzeigen?$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.
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 :-)
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:
- er verwendet das Verb-Nomen (Nachahmung
Invoke-Command
) - impliziert, dass es die Telefonistin unter der Bettdecke
- ahmt nach.
-ErrorAction
Verhalten von eingebauten Cmdlets - wird mit demselben Exit-Code beendet, anstatt eine Exception mit einer neuen Nachricht auszulösen
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
}
- See previous answers
- Weitere Antworten anzeigen