Je veux que mon script PowerShell s'arrête lorsqu'une des commandes que j'exécute échoue (comme set -e
dans bash). J'utilise à la fois les commandes Powershell ( New-Object System.Net.WebClient
) et les programmes ( .\setup.exe
).
Je veux que mon script PowerShell s'arrête lorsqu'une des commandes que j'exécute échoue (comme set -e
dans bash). J'utilise à la fois les commandes Powershell ( New-Object System.Net.WebClient
) et les programmes ( .\setup.exe
).
Réponses:
$ErrorActionPreference = "Stop"
vous permettra d'obtenir une partie du chemin (c'est-à-dire que cela fonctionne très bien pour les applets de commande).
Cependant, pour les EXE, vous devrez vous vérifier $LastExitCode
après chaque appel exe et déterminer si cela a échoué ou non. Malheureusement, je ne pense pas que PowerShell puisse aider ici car sous Windows, les EXE ne sont pas très cohérents sur ce qui constitue un code de sortie "succès" ou "échec". La plupart suivent la norme UNIX de 0 indiquant la réussite, mais pas tous. Découvrez la fonction CheckLastExitCode dans cet article de blog . Vous pourriez trouver cela utile.
throw "$exe failed with exit code $LastExitCode"
où $ exe n'est que le chemin vers l'EXE.
Vous devriez pouvoir accomplir ceci en utilisant l'instruction $ErrorActionPreference = "Stop"
au début de vos scripts.
Le paramètre par défaut de $ErrorActionPreference
est Continue
, c'est pourquoi vous voyez vos scripts continuer après que des erreurs se soient produites.
Malheureusement, en raison d'applets de commande boguées comme New-RegKey et Clear-Disk , aucune de ces réponses ne suffit. Je me suis actuellement installé sur les lignes suivantes en haut de tout script PowerShell pour maintenir ma santé mentale.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
puis tout appel natif reçoit ce traitement:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Ce modèle d'appel natif devient lentement assez courant pour moi que je devrais probablement chercher des options pour le rendre plus concis. Je suis toujours un débutant PowerShell, donc les suggestions sont les bienvenues.
Vous avez besoin d'une gestion des erreurs légèrement différente pour les fonctions PowerShell et pour appeler des exes, et vous devez être sûr de dire à l'appelant de votre script qu'il a échoué. En s'appuyant sur Exec
la bibliothèque Psake, un script qui a la structure ci-dessous s'arrêtera sur toutes les erreurs, et est utilisable comme modèle de base pour la plupart des scripts.
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" }
le -bail
provoque une erreur car il essaie de l'interpréter comme un paramètre d'applet de commande? Envelopper les choses entre guillemets ne semble pas fonctionner. Des idées?
Une légère modification de la réponse de @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
Les principales différences sont les suivantes:
Invoke-Command
)-ErrorAction
comportement des applets de commande intégréesInvoke-Call { dotnet build $something }
& @ScriptBlock
et & $ScriptBlock
semblent faire la même chose. N'ont pas été en mesure de google quelle est la différence dans ce cas
Je suis venu ici à la recherche de la même chose. $ ErrorActionPreference = "Stop" tue mon shell immédiatement quand je préfère voir le message d'erreur (pause) avant qu'il ne se termine. Se replier sur mes sensibilités batch:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
J'ai trouvé que cela fonctionne à peu près de la même manière pour mon script PS1 particulier:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
La redirection stderr
vers stdout
semble également faire l'affaire sans aucune autre commande / encapsuleur scriptblock bien que je ne trouve pas d'explication pourquoi cela fonctionne de cette façon ..
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Cela produira ce qui suit comme prévu (la commande aws s3 ...
retourne $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
pour des programmes bien comportés (qui retournent 0 en cas de succès)?