Voglio che il mio script PowerShell si fermi quando uno qualsiasi dei comandi che eseguo fallisce (come set -e
in bash). Sto usando sia i comandi Powershell ( New-Object System.Net.WebClient
) che i programmi ( .\setup.exe
).
Voglio che il mio script PowerShell si fermi quando uno qualsiasi dei comandi che eseguo fallisce (come set -e
in bash). Sto usando sia i comandi Powershell ( New-Object System.Net.WebClient
) che i programmi ( .\setup.exe
).
Risposte:
$ErrorActionPreference = "Stop"
ti farà parte del percorso (cioè funziona benissimo per i cmdlet).
Tuttavia, per gli EXE dovrai controllare $LastExitCode
te stesso dopo ogni chiamata exe e determinare se fallisce o no. Sfortunatamente non credo che PowerShell possa essere d'aiuto in questo caso perché su Windows gli EXE non sono terribilmente coerenti su ciò che costituisce un codice di uscita "successo" o "errore". La maggior parte segue lo standard UNIX di 0 che indica il successo, ma non tutti lo fanno. Scopri la funzione CheckLastExitCode in questo post del blog . Potresti trovarlo utile.
throw "$exe failed with exit code $LastExitCode"
dove $ exe è solo il percorso per il EXE.
Dovresti essere in grado di farlo utilizzando la dichiarazione $ErrorActionPreference = "Stop"
all'inizio dei tuoi script.
L'impostazione predefinita $ErrorActionPreference
è è Continue
, motivo per cui si vedono gli script continuare dopo che si sono verificati errori.
Purtroppo, a causa di cmdlet con errori come New-RegKey e Clear-Disk , nessuna di queste risposte è sufficiente. Attualmente ho optato per le seguenti righe nella parte superiore di qualsiasi script PowerShell per mantenere la mia sanità mentale.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
e quindi qualsiasi chiamata nativa ottiene questo trattamento:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Quel modello di chiamata nativo sta lentamente diventando abbastanza comune per me che dovrei probabilmente esaminare le opzioni per renderlo più conciso. Sono ancora un principiante di PowerShell, quindi i suggerimenti sono benvenuti.
Hai bisogno di una gestione degli errori leggermente diversa per le funzioni di PowerShell e per la chiamata di exe, e devi essere sicuro di dire al chiamante del tuo script che non è riuscito. Costruito sopra Exec
dalla libreria Psake, uno script che ha la struttura seguente si fermerà su tutti gli errori ed è utilizzabile come modello di base per la maggior parte degli script.
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" }
la -bail
causa un errore in quanto si sta cercando di interpretarlo come parametro cmdlet? Avvolgere le cose tra virgolette non sembra funzionare. Qualche idea?
Una leggera modifica alla risposta di @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
Le differenze chiave qui sono:
Invoke-Command
)-ErrorAction
comportamento dai cmdlet integratiInvoke-Call { dotnet build $something }
& @ScriptBlock
e & $ScriptBlock
sembrano fare la stessa cosa. Non sono stato in grado di cercare su Google la differenza in questo caso
Sono venuto qui alla ricerca della stessa cosa. $ ErrorActionPreference = "Stop" uccide immediatamente la mia shell quando preferisco vedere il messaggio di errore (pausa) prima che termini. Ripiegando sulla mia sensibilità batch:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Ho scoperto che questo funziona praticamente allo stesso modo per il mio particolare script ps1:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Reindirizzamento stderr
al stdout
sembra fare anche il trucco, senza altri comandi / involucri scriptblock anche se non riesco a trovare una spiegazione perché funziona in questo modo ..
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Questo produrrà quanto segue come previsto (il comando aws s3 ...
restituisce $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
il lavoro per i programmi ben educati (che il ritorno 0 in caso di successo)?