最初のエラーでPowerShellスクリプトを停止する方法は?


250

set -ebashのように)実行するコマンドのいずれかが失敗したときにPowerShellスクリプトを停止します。Powershellコマンド(New-Object System.Net.WebClient)とプログラム(.\setup.exe)の両方を使用しています。

回答:


303

$ErrorActionPreference = "Stop" 方法の一部を取得します(つまり、これはコマンドレットに最適です)。

ただし、EXEの場合は$LastExitCode、exeを呼び出すたびに自分自身をチェックして、失敗したかどうかを判断する必要があります。残念ながら、Windowsでは、EXEは「成功」または「失敗」の終了コードを構成するものに関して非常に一貫性がないため、PowerShellがここでは役に立たないと思います。ほとんどの場合、UNIX標準の0に準拠していますが、すべてが成功しているわけではありません。このブログ投稿でCheckLastExitCode関数を確認してください。あなたはそれが役に立つかもしれません。


3
DOESの$ErrorActionPreference = "Stop"行儀プログラムのワーク(成功時にそのリターン0)?
Andres Riofrio 2012年

14
いいえ、EXEに対してはまったく機能しません。インプロセスで実行されるPowerShellコマンドレットでのみ機能します。ちょっと面倒ですが、EXEを呼び出すたびに$ LastExitCodeをチェックし、予想される終了コードと照らし合わせてチェックし、そのテストが失敗を示している場合は、スクリプトの実行を終了するためにスローする必要があります。たとえばthrow "$exe failed with exit code $LastExitCode"、$ exeは、 EXE。
Keith Hill

2
外部プログラムで動作させる方法に関する情報が含まれているため、受け入れられました。
Andres Riofrio 2012


5
psakeには "exec"と呼ばれるコマンドレットがあることに注意してください。これを使用して、LastExitCodeのチェックで外部プログラムへの呼び出しをラップし、エラーを表示できます(必要に応じて停止します)
enorl76

68

$ErrorActionPreference = "Stop"スクリプトの先頭にあるステートメントを使用することで、これを実現できるはずです。

のデフォルト設定は$ErrorActionPreferenceですContinue。このため、エラーが発生した後もスクリプトが続行されます。


21
これはプログラムには影響せず、コマンドレットにのみ影響します。
Joey

18

悲しいことに、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初心者なので、提案は大歓迎です。


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" }-bailコマンドレットパラメータとしてそれを解釈しようとしているので、エラーの原因は?引用符で囲むのはうまくいかないようです。何か案は?
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. それは動詞-名詞を使用します(模倣Invoke-Command
  2. それはカバーの下で呼び出し演算子を使用することを意味します
  3. -ErrorAction組み込みコマンドレットの動作を模倣します
  4. 新しいメッセージで例外をスローするのではなく、同じ終了コードで終了する

1
パラメータ/変数をどのように渡しますか?例Invoke-Call { dotnet build $something }
Michael Blake、

1
@MichaelBlakeあなたの問い合わせはとても正しいので、paramsパススルーを許可すると、このアプローチは成功します。私はadamtheautomator.com/pass-hashtables-invoke-command-argument調べて、paramsパススルーをサポートするようにInvoke-Callを調整しています。成功した場合は、別の回答としてここに投稿します。
Maxim V. Pavlov

呼び出し中にスプラッティング演算子を使用するのはなぜですか?それで何ができるの?& @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と、他のコマンド/ scriptblockラッパーなしでトリックが実行されるようですが、そのように動作する理由についての説明はありません。

# 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.