Quiero que mi script de PowerShell se detenga cuando alguno de los comandos que ejecuto falla (como set -e
en bash). Estoy usando los comandos de Powershell ( New-Object System.Net.WebClient
) y los programas ( .\setup.exe
).
Quiero que mi script de PowerShell se detenga cuando alguno de los comandos que ejecuto falla (como set -e
en bash). Estoy usando los comandos de Powershell ( New-Object System.Net.WebClient
) y los programas ( .\setup.exe
).
Respuestas:
$ErrorActionPreference = "Stop"
te llevará a una parte del camino (es decir, esto funciona muy bien para cmdlets).
Sin embargo, para los EXE, tendrá que comprobarse $LastExitCode
después de cada invocación de exe y determinar si eso falló o no. Desafortunadamente, no creo que PowerShell pueda ayudar aquí porque en Windows, los EXE no son terriblemente consistentes en lo que constituye un código de salida de "éxito" o "fracaso". La mayoría sigue el estándar UNIX de 0 que indica éxito, pero no todos lo hacen. Echa un vistazo a la función CheckLastExitCode en esta publicación de blog . Tu podrias encontrar esto útil.
throw "$exe failed with exit code $LastExitCode"
donde $ exe es solo la ruta a El EXE.
Debería poder lograr esto utilizando la declaración $ErrorActionPreference = "Stop"
al comienzo de sus scripts.
La configuración predeterminada de $ErrorActionPreference
es Continue
, por lo que está viendo que sus scripts continúan después de que ocurran los errores.
Lamentablemente, debido a errores de cmdlets como New-RegKey y Clear-Disk , ninguna de estas respuestas es suficiente. Actualmente me he decidido por las siguientes líneas en la parte superior de cualquier script de PowerShell para mantener mi cordura.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
y luego cualquier llamada nativa recibe este tratamiento:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Ese patrón de llamadas nativas se está volviendo lo suficientemente común para mí que probablemente debería buscar opciones para hacerlo más conciso. Todavía soy un novato de PowerShell, así que las sugerencias son bienvenidas.
Necesita un manejo de errores ligeramente diferente para las funciones de PowerShell y para llamar a los exe, y debe asegurarse de informarle al llamador de su script que ha fallado. Sobre la base de Exec
la biblioteca Psake, un script que tiene la estructura a continuación se detendrá en todos los errores, y se puede usar como plantilla base para la mayoría de los 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" }
la -bail
provoca un error, ya que está tratando de interpretarlo como un parámetro de cmdlet? Envolver cosas entre comillas no parece funcionar. ¿Algunas ideas?
Una ligera modificación a la respuesta 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
Las diferencias clave aquí son:
Invoke-Command
)-ErrorAction
comportamiento de los cmdlets integradosInvoke-Call { dotnet build $something }
& @ScriptBlock
y & $ScriptBlock
parecen hacer lo mismo. No he podido
Vine aquí buscando lo mismo. $ ErrorActionPreference = "Stop" mata mi shell inmediatamente cuando prefiero ver el mensaje de error (pausa) antes de que termine. Recurriendo a mis sensibilidades de lote:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Descubrí que esto funciona más o menos igual para mi script ps1 particular:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Redirigir stderr
a stdout
parece que también funciona sin ningún otro comando / envoltorio de bloque de script, aunque no puedo encontrar una explicación de por qué funciona de esa manera ...
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Esto generará lo siguiente como se esperaba (el comando aws s3 ...
regresa $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
Funciona para programas con buen comportamiento (que devuelven 0 en caso de éxito)?