Quero que meu script do PowerShell seja interrompido quando qualquer um dos comandos executados falhar (como set -e
no bash). Estou usando os comandos do Powershell ( New-Object System.Net.WebClient
) e os programas ( .\setup.exe
).
Quero que meu script do PowerShell seja interrompido quando qualquer um dos comandos executados falhar (como set -e
no bash). Estou usando os comandos do Powershell ( New-Object System.Net.WebClient
) e os programas ( .\setup.exe
).
Respostas:
$ErrorActionPreference = "Stop"
você fará parte do caminho até lá (isto é, funciona muito bem para cmdlets).
No entanto, para EXEs, você precisará verificar a $LastExitCode
si mesmo após cada chamada de exe e determinar se isso falhou ou não. Infelizmente, acho que o PowerShell não pode ajudar aqui, porque no Windows, os EXEs não são terrivelmente consistentes com o que constitui um código de saída de "sucesso" ou "falha". A maioria segue o padrão UNIX de 0, indicando sucesso, mas nem todos o fazem. Confira a função CheckLastExitCode nesta postagem do blog . Você pode achar util.
throw "$exe failed with exit code $LastExitCode"
onde $ exe é apenas o caminho para o EXE.
Você deve conseguir isso usando a instrução $ErrorActionPreference = "Stop"
no início de seus scripts.
A configuração padrão de $ErrorActionPreference
é Continue
, e é por isso que você vê seus scripts continuarem após a ocorrência de erros.
Infelizmente, devido a cmdlets com erros como New-RegKey e Clear-Disk , nenhuma dessas respostas é suficiente. Atualmente, eu decidi as seguintes linhas no topo de qualquer script do PowerShell para manter minha sanidade.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
e qualquer chamada nativa recebe este tratamento:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Esse padrão de chamada nativa está lentamente se tornando comum o suficiente para mim, para que eu provavelmente deva procurar opções para torná-lo mais conciso. Eu ainda sou um novato em PowerShell, então sugestões são bem-vindas.
Você precisa de um tratamento de erro um pouco diferente para as funções do PowerShell e para chamar exe, além de informar ao chamador do seu script que ele falhou. Construindo sobre Exec
a biblioteca Psake, um script que tem a estrutura abaixo irá parar com todos os erros e é utilizável como modelo base para a maioria dos 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" }
a -bail
causa um erro, uma vez que está tentando interpretá-lo como um parâmetro Cmdlet? O agrupamento de aspas não parece funcionar. Alguma ideia?
Uma pequena modificação na resposta 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
As principais diferenças aqui são:
Invoke-Command
)-ErrorAction
comportamento dos cmdlets internosInvoke-Call { dotnet build $something }
& @ScriptBlock
e & $ScriptBlock
parece fazer a mesma coisa. Não têm sido capazes de google qual é a diferença neste caso
Eu vim aqui procurando a mesma coisa. $ ErrorActionPreference = "Stop" mata meu shell imediatamente quando eu preferir ver a mensagem de erro (pausa) antes de terminar. Recorrendo às minhas sensibilidades de lote:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Descobri que isso funciona da mesma forma para o meu script ps1 específico:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Redirecionar stderr
para stdout
parece também fazer o truque sem quaisquer outros comandos / wrappers de scriptblock, embora eu não consiga encontrar uma explicação por que funciona dessa maneira.
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Isso produzirá o seguinte conforme o esperado (o comando aws s3 ...
retorna $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
para programas bem comportados (que retornam 0 em caso de sucesso)?