web-dev-qa-db-fra.com

Comment arrêter un script PowerShell à la première erreur?

Je veux que mon script PowerShell s'arrête en cas d'échec de l'une des commandes que j'exécute (comme set -e dans bash). J'utilise à la fois les commandes Powershell (New-Object System.Net.WebClient) et les programmes (.\setup.exe).

216
Andres Riofrio

$ErrorActionPreference = "Stop" vous fera faire une partie du chemin (c'est-à-dire que cela fonctionne très bien pour les applets de commande).

Cependant, pour les fichiers EXE, vous devrez vérifier vous-même $LastExitCode après chaque invocation exe et déterminer si cela a échoué ou non. Malheureusement, je ne pense pas que PowerShell puisse aider ici car sous Windows, les fichiers 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 le succès, mais pas tous. Découvrez le fonction CheckLastExitCode dans cet article de blog . Vous pourriez le trouver utile.

261
Keith Hill

Vous devriez pouvoir accomplir cela en utilisant l'instruction $ErrorActionPreference = "Stop" au début de vos scripts.

Le paramètre par défaut de $ErrorActionPreference est Continue, ce qui explique pourquoi vos scripts continuent à fonctionner après des erreurs.

61
goric

Malheureusement, en raison d'applets de commande buggy comme New-RegKey et Clear-Disk , aucune de ces réponses n'est suffisante. Je suis actuellement sur les lignes suivantes au sommet de tout script PowerShell pour maintenir ma santé mentale.

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'

et 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 assez commun pour moi et je devrais probablement chercher des options pour le rendre plus concis. Je suis toujours un novice PowerShell, donc les suggestions sont les bienvenues.

12
aggieNick02

Vous avez besoin d'une gestion des erreurs légèrement différente pour les fonctions powershell et pour appeler des EXE, et vous devez être sûr d'informer l'appelant de votre script qu'il a échoué. S'appuyant sur Exec de la bibliothèque Psake, un script dont la structure est la suivante s'arrête sur toutes les erreurs et peut être utilisé 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
}
11
alastairtree

Une légère modification du 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:

  1. il utilise le nom verbal (imitant Invoke-Command)
  2. implique qu'il utilise le opérateur d'appel sous les couvertures
  3. imite -ErrorAction comportement à partir des applets de commande intégrées
  4. sorties avec le même code de sortie plutôt que de lancer une exception avec un nouveau message
6
Lucas

Je suis venu ici pour chercher la même chose. $ ErrorActionPreference = "Stop" tue mon shell immédiatement lorsque je préfère voir le message d'erreur (pause) avant qu'il ne se termine. Je retombe sur la sensibilité de mon lot:

IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF

J'ai trouvé que cela fonctionne à peu près la même chose pour mon script ps1 particulier:

Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
2
harvey263

Je suis nouveau sur Powershell mais cela semble être le plus efficace:

doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}
0
Peter L