첫 번째 오류에서 PowerShell 스크립트를 중지하는 방법은 무엇입니까?


250

set -ebash에서 와 같이 실행하는 명령이 실패하면 PowerShell 스크립트를 중지하고 싶습니다 . Powershell 명령 ( New-Object System.Net.WebClient)과 프로그램 ( .\setup.exe) 을 모두 사용 하고 있습니다 .

답변:


303

$ErrorActionPreference = "Stop" 이 방법의 일부를 제공합니다 (즉, 이는 cmdlet에 효과적입니다).

그러나 EXE의 경우 $LastExitCode모든 exe ​​호출 후 자신 을 확인 하고 실패 여부를 결정해야합니다. 불행히도 Windows에서는 EXE가 "성공"또는 "실패"종료 코드를 구성하는 요소와 크게 일치하지 않기 때문에 PowerShell이 ​​여기에서 도움을 줄 수 없다고 생각합니다. 대부분의 성공을 나타내는 UNIX 표준 0을 따르지만 모두 그렇지는 않습니다. 이 블로그 게시물에서 CheckLastExitCode 함수를 확인하십시오 . 유용 할 수 있습니다.


3
합니까 $ErrorActionPreference = "Stop"잘 동작하는 프로그램에 대한 작업을 (를 돌려 성공 0)?
Andres Riofrio

14
아니요, EXE에서는 전혀 작동하지 않습니다. 프로세스 내에서 실행되는 PowerShell cmdlet에만 작동합니다. 고통 스럽지만 모든 EXE 호출 후에 $ LastExitCode를 확인하고 예상되는 종료 코드를 확인하고 테스트에 실패가 표시되면 스크립트 실행을 종료해야합니다 (예 : throw "$exe failed with exit code $LastExitCode"$ exe가 경로입니다) EXE.
Keith Hill

2
외부 프로그램과 함께 작동시키는 방법에 대한 정보가 포함되어 있으므로 허용됩니다.
Andres Riofrio


5
psake에는 "exec"라는 커맨드 렛이 있는데 LastExitCode를 확인하여 외부 프로그램에 대한 호출을 래핑하고 오류를 표시하고 원하는 경우 중지 할 수 있습니다.
enorl76

68

명령문을 사용하여이를 수행 할 수 있어야합니다. $ErrorActionPreference = "Stop"스크립트 시작 부분에 을 .

기본 설정은 $ErrorActionPreference입니다 Continue. 오류가 발생한 후에도 스크립트가 계속 표시되는 이유입니다.


21
프로그램에는 영향을 미치지 않으며 cmdlet에만 영향을줍니다.
Joey

18

안타깝게도 New-RegKey 및 Clear-Disk와 같은 버그가있는 cmdlet으로 인해 이러한 답변으로는 충분하지 않습니다. 나는 현재 나의 건강을 유지하기 위해 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'
}

그 기본 통화 패턴은 천천히 간결 해지기 때문에 옵션을 더 간결하게 만들기 위해 선택해야합니다. 저는 여전히 파워 쉘 초보자이므로 제안을 환영합니다.


14

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" }의는 -bailcmdlet은 매개 변수로 해석하려고하기 때문에 오류가 발생합니다? 따옴표로 묶는 것은 효과가없는 것 같습니다. 어떤 아이디어?
rcoup

Exec 메소드를 사용하려고 할 때 어떤 종류의 #include를 수행 할 수 있도록이 코드를 중앙에 배치하는 방법이 있습니까?
NickG

10

@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. 동사-명사 (mimicing Invoke-Command)를 사용합니다.
  2. 커버 아래에서 호출 연산자를 사용함을 의미합니다.
  3. -ErrorAction기본 제공 cmdlet의 동작 모방
  4. 새 메시지로 예외를 발생시키지 않고 동일한 종료 코드로 종료

1
매개 변수 / 변수를 어떻게 전달합니까? 예 :Invoke-Call { dotnet build $something }
Michael Blake

1
@MichaelBlake 당신의 질문이 맞습니다. 매개 변수 통과 가이 접근법을 금으로 만들 것입니다. 매개 변수 통과를 지원하도록 Invoke-Call을 조정하기 위해 adamtheautomator.com/pass-hashtables-invoke-command-argument 를 검사 하고 있습니다. 성공하면 여기에 다른 답변으로 게시합니다.
Maxim V. Pavlov

호출 중에 왜 splatting 연산자를 사용합니까? 당신은 무엇을 얻습니까? & @ScriptBlock& $ScriptBlock같은 일을 할 것으로 보인다. 차이가이 경우에 무엇 구글 수 없었다
pinkfloydx33

6

나는 powershell을 처음 사용하지만 이것이 가장 효과적인 것 같습니다.

doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}

2

나는 같은 것을 찾기 위해 여기에 왔습니다. $ ErrorActionPreference = "Stop"은 종료되기 전에 오류 메시지 (일시 중지)를보고 싶을 때 즉시 쉘을 종료합니다. 배치 감도로 폴백 :

IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF

나는 이것이 내 특정 ps1 스크립트와 거의 동일하게 작동한다는 것을 알았습니다.

Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}

0

재 지정 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.