Я хочу, чтобы мой скрипт PowerShell останавливался, когда любая из команд, которые я запускаю, не срабатывает (как set -e
в bash). Я использую обе команды Powershell ( New-Object System.Net.WebClient
) и программ ( .\setup.exe
).
Я хочу, чтобы мой скрипт PowerShell останавливался, когда любая из команд, которые я запускаю, не срабатывает (как set -e
в bash). Я использую обе команды Powershell ( New-Object System.Net.WebClient
) и программ ( .\setup.exe
).
Ответы:
$ErrorActionPreference = "Stop"
поможет вам в этом (например, это прекрасно работает для командлетов).
Однако для EXE вы должны будете проверять $LastExitCode
себя после каждого вызова exe и определять, произошел ли сбой или нет. К сожалению, я не думаю, что PowerShell может помочь в этом, потому что в Windows EXE-файлы не очень согласуются с тем, что представляет собой код завершения «успех» или «отказ». Большинство из них следуют стандарту UNIX 0, что указывает на успех, но не все. Проверьте функцию CheckLastExitCode в этом сообщении в блоге . Вы можете найти это полезным.
throw "$exe failed with exit code $LastExitCode"
где $ exe - просто путь к EXE.
Вы должны быть в состоянии сделать это, используя оператор $ErrorActionPreference = "Stop"
в начале ваших сценариев.
Значение по умолчанию $ErrorActionPreference
IS Continue
, поэтому вы видите ваши сценарии продолжает идти после возникновения ошибок.
К сожалению, из-за ошибочных командлетов, таких как New-RegKey и Clear-Disk , ни одного из этих ответов недостаточно. В настоящее время я остановился на следующих строках в верхней части любого сценария powershell, чтобы сохранить здравомыслие.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
и тогда любой родной звонок получает это лечение:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Этот собственный шаблон вызовов постепенно становится достаточно распространенным для меня, поэтому я, вероятно, должен рассмотреть варианты, чтобы сделать его более кратким. Я все еще новичок в PowerShell, поэтому предложения приветствуются.
Вам нужно немного по-другому обрабатывать ошибки для функций powershell и для вызова exe-файлов, и вы должны быть уверены, что сообщили вызывающему скрипту, что он потерпел неудачу. Построенный поверх Exec
библиотеки Psake, скрипт со структурой ниже остановит все ошибки и будет использоваться в качестве базового шаблона для большинства скриптов.
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" }
, то -bail
вызывает ошибку , так как он пытается интерпретировать его в качестве параметра командлета? Упаковка вещей в кавычки, похоже, не работает. Любые идеи?
Небольшая модификация ответа от @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
Ключевые отличия здесь:
Invoke-Command
)-ErrorAction
поведение встроенных командлетовInvoke-Call { dotnet build $something }
& @ScriptBlock
и, & $ScriptBlock
кажется, делают то же самое. Не удалось гуглить, какая разница в этом случае
Я пришел сюда в поисках того же. $ ErrorActionPreference = "Stop" немедленно убивает мою оболочку, когда я предпочитаю увидеть сообщение об ошибке (пауза) до его завершения. Возвращаясь к моей партии чувств:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Я обнаружил, что это работает примерно так же для моего конкретного сценария PS1:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Перенаправление stderr
в, stdout
кажется, также помогает без каких-либо других оболочек команд / скриптовых блоков, хотя я не могу найти объяснение, почему это работает так ...
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Это выведет следующее, как и ожидалось (команда aws s3 ...
возвращает $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
для хороших программ (которые возвращают 0 в случае успеха)?