Я хочу, чтобы моя PowerShell script остановилась, когда какая-либо из команд, которые я запускаю, не работает (например, set -e
в bash). Я использую команды Powershell (New-Object System.Net.WebClient
) и программы (.\setup.exe
).
Как остановить PowerShell script при первой ошибке?
Ответ 1
$ErrorActionPreference = "Stop"
предоставит вам часть пути (т.е. это отлично работает для командлетов).
Однако для EXE вам нужно будет проверить $LastExitCode
самостоятельно после каждого вызова exe и определить, не удалось ли это. К сожалению, я не думаю, что PowerShell может помочь здесь, потому что в Windows EXE не являются ужасно последовательными в отношении того, что представляет собой код выхода "успех" или "отказ". Большинство из них следуют стандарту UNIX 0, указывающему успех, но не все это делают. Ознакомьтесь с функцией CheckLastExitCode в этом сообщении в блоге. Вы можете найти это полезным.
Ответ 2
Вы должны выполнить это, используя инструкцию $ErrorActionPreference = "Stop"
в начале ваших скриптов.
Значение по умолчанию $ErrorActionPreference
равно Continue
, поэтому вы видите, что ваши скрипты продолжают идти после ошибок.
Ответ 3
К сожалению, из-за ошибок командлетов, таких как New-RegKey и Clear-Disk, ни одного из этих ответов недостаточно. В настоящее время я остановился на следующих строках в верхней части любой powershell script, чтобы поддерживать разумность.
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, поэтому предложения приветствуются.
Ответ 4
Вам нужно немного по-другому обрабатывать ошибки для функций 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 and check their exit code using Exec
Exec { setup.exe }
} Catch {
# tell the caller it has all gone wrong
$host.SetShouldExit(-1)
throw
}
Ответ 5
Небольшая модификация ответа от @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
из встроенных командлетов - завершает работу с тем же кодом завершения, а не создает исключение с новым сообщением
Ответ 6
Я пришел сюда, ища то же самое. $ErrorActionPreference = "Стоп" немедленно убивает мою оболочку, когда я предпочел бы увидеть сообщение об ошибке (пауза) до его завершения. Возвращаясь к моей чувствительности к партиям:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Я обнаружил, что это работает почти так же для моего конкретного ps1 script:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Ответ 7
Я новичок в powershell, но это, кажется, наиболее эффективно:
doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}