Как остановить PowerShell script при первой ошибке?

Я хочу, чтобы моя PowerShell script остановилась, когда какая-либо из команд, которые я запускаю, не работает (например, set -e в bash). Я использую команды Powershell (New-Object System.Net.WebClient) и программы (.\setup.exe).

Ответ 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

Ключевые отличия здесь:

  1. он использует глагол-существительное (имитирующий Invoke-Command)
  2. подразумевает, что он использует оператор вызова под прикрытием
  3. имитирует поведение -ErrorAction из встроенных командлетов
  4. завершает работу с тем же кодом завершения, а не создает исключение с новым сообщением

Ответ 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"}