🩹 失敗談・トラブル解決 2026.07.26 更新

終了コードの確認方法|PowerShell・コマンドプロンプト・GitHub Actionsの違い

Windowsでコマンドの終了コードを確認し、PowerShell、コマンドプロンプト、GitHub Actionsへ失敗を正しく引き渡す方法をコード例付きで解説します。

コマンドが画面上では動いているように見えても、自動処理では失敗を検知できないことがあります。Windowsでは、PowerShellの$LASTEXITCODE、コマンドプロンプトの%ERRORLEVEL%、GitHub Actionsのステップ結果が似た役割を持ちますが、確認方法は同じではありません。この記事では、外部プログラムの失敗を見つけ、後続処理を止めるところまでを、公式の一次情報に沿って比較します。

終了コードで分かること

終了コード(exit code)は、プログラムが終了時に呼び出し元へ返す数値です。最初に覚える結論は3つです。

  1. 一般には0を成功、非ゼロ(0以外)を失敗として扱う。
  2. ただし番号の意味はプログラムごとに違う。
  3. 画面に出るメッセージと終了コードは別物である。

1つ目は、GitHub Actionsの公式資料でも「終了コード0は成功、非ゼロは失敗」としてアクションの状態に対応づけられています(Setting exit codes for actions)。この資料はJavaScriptアクションとDockerコンテナアクション向けの説明ですが、0と非ゼロの基本の読み方はそのまま使えます。

2つ目の「番号の意味はプログラムごと」の実例が2つあります。Node.jsは、1を捕まえられなかった致命的な例外に、9を不正な引数に割り当てています(Node.jsのProcess公式資料)。番号の一覧は更新されることがあるので、利用時点の公式資料で確認してください。逆に、robocopyのように非ゼロへ「差分あり」など失敗以外の意味を持たせるプログラムもあります。Microsoftの公式例でも、robocopyは「8より大きい終了コードだけを失敗として扱う」形で判定しています(about_Preference_Variables)。つまり「非ゼロ=失敗」は目安であって、個別の終了コード表が最優先です。

3つ目は自動化で一番つまずく点です。警告が赤く表示されても、終了コードが0なら呼び出し元は成功と判断することがあります。画面の色ではなく、コードで分岐してください。

終了コードで判断できるのは、次のようなことです。

  • 次の処理へ進んでよいか
  • 再試行するか、人の確認へ回すか
  • CI(継続的インテグレーション=自動の検品と組み立て)を失敗として止めるか

確認方法の違いは、次の早見表のとおりです。

実行場所・対象直後に確認する値成功の目安失敗を上位へ返す方法注意点
PowerShell・外部プログラム$LASTEXITCODE0exit $code次の外部プログラムを実行する前に保存する
PowerShell・コマンドレット$?または例外$truethrowまたはexit <数値>$LASTEXITCODEは更新されないことがある
コマンドプロンプト%ERRORLEVEL%0exit /b %code%if errorlevel 1は「1以上」を表す
GitHub Actionsのrun使用シェルの終了コード0シェルから非ゼロを返すログへのエラー表示だけでは失敗にならない

PowerShellで確認する

この節の例は、PowerShell 7系(pwsh)を前提にしています。$LASTEXITCODE$?の基本はWindows PowerShell 5.1でも同じですが、版で挙動が変わる箇所はその都度明記します。

外部の実行ファイルやバッチを動かした直後は、$LASTEXITCODEで確認します。公式の定義では、これは「最後に実行したネイティブプログラム(=PowerShellの外のプログラム)またはPowerShellスクリプトの終了コード」です(about_Automatic_Variables)。

cmd /c "exit /b 7"
$code = $LASTEXITCODE

Write-Host "終了コード: $code"
if ($code -ne 0) {
    exit $code
}

要点は、対象コマンドの直後に値を変数へ退避することです。別の外部プログラムを実行すると、$LASTEXITCODEはその値へ上書きされます。

$?は、最後の操作が成功したかをTrueFalseで示します。ネイティブコマンドでは、終了コード0のとき$?True、非ゼロのときFalseになります。数値そのものを上位へ返したいなら$LASTEXITCODE、コマンドレット(PowerShell内部の命令)の成否だけ見たいなら$?や例外、という使い分けです。なお、PowerShell 7より前の版では、コマンドを丸括弧や部分式で囲むと$?Trueへリセットされる挙動がありました。5.1で$?を使うときは、囲まずに直後で見てください。

外部プログラムはtry/catchだけで捕まらない

外部プログラムが非ゼロを返しても、PowerShellの既定動作ではcatchへ入りません。公式資料は「外部プログラムはPowerShellのエラーの仕組みに直接参加せず、非ゼロでもエラーレコードを作らず、catchやtrapを起動しない」と明記しています(about_Error_Handling)。だから、外部プログラムの直後は$LASTEXITCODEの確認が必要です。

PowerShell 7.4以降では、$PSNativeCommandUseErrorActionPreference$trueにすると、非ゼロ終了をPowerShellのエラーとして扱えます(7.3で実験機能として入り、7.4で正式になりました)。さらに$ErrorActionPreference = 'Stop'と組み合わせると、catchできる停止エラーになります。ただしこの設定を入れても、robocopyのように非ゼロが失敗と限らないプログラムでは誤検知になります。対象コマンドごとに許容値を決めて明示的に判定する方が、あとから意図を追いやすくなります。

スクリプトの呼び方で$LASTEXITCODEの決まり方が変わる

同じスクリプトでも、呼び方で結果の受け取り方が変わります。

  • スクリプトを直接、または&で呼んだ場合: そのスクリプトがexitを実行するか、中でネイティブコマンドを動かさない限り、$LASTEXITCODEは変わりません。
  • pwsh -File スクリプト.ps1で呼んだ場合: 正常に最後まで走れば0exit 数値で終われば その数値、例外で終われば1が返ります。

「手元で動かすと取れるのに、タスクスケジューラや別プロセスから呼ぶと取れない」ときは、まずこの呼び方の差を疑ってください。

パイプ処理の注意点

パイプ(|でつなぐ処理)では、直後に確認できる状態が末尾の処理に対応することがあります。producer.exe | formatter.exeの直後に$LASTEXITCODEを見ても、どちらが失敗したかを安全に切り分けられません。重要な処理ではパイプを分け、各コマンドの直後に確認します。

& .\producer.exe --output result.txt
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

& .\formatter.exe result.txt
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

ログの読み方はCodexが途中で止まる原因をログから切り分ける方法も参考になります。

コマンドプロンプトで確認する

コマンドプロンプト(cmd)では、直前の終了コードをecho %ERRORLEVEL%で表示できます。バッチファイルでは、別のコマンドで値が変わる前に保存します。

@echo off
some-command.exe
set "code=%ERRORLEVEL%"

if not "%code%"=="0" (
  echo 処理に失敗しました。終了コード: %code%
  exit /b %code%
)

echo 処理に成功しました。
exit /b 0

exit /b <数値>は、Cmd.exe全体ではなく現在のバッチだけを終了し、その数値をERRORLEVELへ設定します(exitの公式資料)。バッチの外(コマンドラインに直接)で実行するとCmd.exe自体が終了する点も、同じ資料に書かれています。元の失敗を呼び出し元へ返すなら、保存した%code%を渡します。

cmd固有の落とし穴は2つあります(ifの公式資料)。

  1. if errorlevel 1は「1と等しい」ではなく「1以上なら真」です。特定値との一致を見るならif "%code%"=="1"のように書き、成功と失敗の分岐なら上の例のように0との不一致を見ます。
  2. %ERRORLEVEL%は、ERRORLEVELという同じ名前の環境変数を自分で作ってしまうと、本物の終了コードではなくその変数の値に置き換わります。set ERRORLEVEL=...は書かないでください。

GitHub Actionsで失敗を伝える

GitHub Actionsのrunステップの成否は、ログの色や表示ではなく、使用シェルが最後に返した終了コードで決まります。公式のワークフロー構文の資料によると、組み込みのpwshpowershellでは、ランナーがスクリプトの先頭に$ErrorActionPreference = 'stop'を、末尾に「$LASTEXITCODEがあればその値でexitする」処理を自動で追加します(Workflow syntax for GitHub Actions)。

同じ資料から、シェルごとの違いも分かります。

  • shell: bashを明示すると--noprofile --norc -eo pipefailで実行され、パイプの途中の失敗も検知されます。
  • shell: cmdには完全な即時停止の仕組みがなく、各コマンドのエラーコードをスクリプト側で自分で確認する必要があります。
  • shell:に自分でコマンドラインを書くカスタムシェルでは、組み込みシェルの自動追加を前提にできません。

複数の処理を1ステップに入れるときは、失敗した箇所で明示的に終了させると確実です。

- name: 検品を実行する
  shell: pwsh
  run: |
    & .\tools\verify.exe
    $code = $LASTEXITCODE

    if ($code -ne 0) {
      Write-Host "::error::検品に失敗しました(終了コード: $code)"
      exit $code
    }

    Write-Host "検品に成功しました"

注意したいのは、::error::の表示は見た目の注釈にすぎないことです。エラー表示だけ出してexit 0で終えると、ステップは成功扱いになり得ます。「ログへ表示すること」と「非ゼロを返すこと」は別です。

配信前の工程全体はGitHub Actionsで記事サイトを自動検品する方法も参照してください。キャッシュを使っても、GitHub Actionsのキャッシュ入門のとおり検品自体は省略しません。

自動化へ組み込む確認の型

どの環境でも、失敗を見逃さない書き方は同じ型になります。

  1. コマンドを実行する。
  2. 直後に終了コードを変数へ保存する。
  3. そのコマンド固有の許容値と比較する(既定は0、robocopyのような例外は公式の終了コード表に従う)。
  4. 非ゼロなら、秘密を含まない範囲でコマンド名と終了コードをログへ残す。
  5. 保存した同じコードで終了し、後続処理を実行しない。

終了コードは、表示しただけでは自動化を止めません。非ゼロを上位へ返し、後続を止めるところまでを一つの設計として扱います。

よくある質問

PowerShellで終了コードを表示するだけなら、何を入力しますか?

外部プログラムの実行直後に$LASTEXITCODEを入力します。説明付きならWrite-Host "終了コード: $LASTEXITCODE"です。あとで使う場合は、別の外部プログラムに上書きされる前に変数へ保存してください。

$LASTEXITCODE$?は同じものですか?

同じではありません。$LASTEXITCODEは数値の終了コード、$?は最後の操作が成功したかのTrue/Falseです。ネイティブコマンドでは終了コード0True、非ゼロがFalseに対応します。数値を上位へ返すなら$LASTEXITCODEを使います。

外部プログラムの失敗をtry/catchで捕まえられますか?

既定では捕まりません。外部プログラムの非ゼロ終了は、エラーレコードを作らずcatchも起動しないためです。PowerShell 7.4以降なら、$PSNativeCommandUseErrorActionPreference$trueにし、$ErrorActionPreferenceStopにすると、catchできる停止エラーにできます。版と対象コマンドの終了コード表を確認してから使ってください。

GitHub Actionsでエラーメッセージを出したのに成功扱いになるのはなぜですか?

メッセージの表示とステップの終了コードが別だからです。失敗させるには、使用中のシェルからexit 1などの非ゼロを返します。

失敗後も通知やログ保存のステップだけ動かせますか?

できます。後続ステップのiffailure()などのステータス確認関数を指定します。GitHubの式の公式資料によると、ステータス確認関数を含まないifにはsuccess()が既定で適用されるため、失敗後にも動かす処理は条件を明示する必要があります(Evaluate expressions in workflows and actions)。通知の作り方はGitHub Actionsで失敗通知を受け取る方法も参照できます。

まとめ

PowerShellの外部プログラムは$LASTEXITCODE、コマンドレットは$?か例外、コマンドプロンプトは%ERRORLEVEL%exit /b、GitHub Actionsは使用シェルの終了コード——確認する場所は違っても、「実行→直後に保存→許容値と比較→同じコードで返す」という型は共通です。次の3つから始めてください。

  • 手元のスクリプトで、外部コマンドの直後に終了コードを変数へ保存する1行を足し、非ゼロなら同じコードでexitする形に直す。
  • よく使うコマンドの公式資料で終了コードの一覧を開き、「どの値まで成功として許容するか」を決めてスクリプトに書く。番号の意味は変わることがあるので、利用時点の公式案内で確認してください。
  • GitHub Actionsを使っているなら、わざと失敗するコマンドを入れてステップが赤く止まるかを一度試す。AIへ自動化を頼むときも、「成功条件・許容する終了コード・失敗したら止める境界」を依頼文に含める。

公式一次情報

確認日: 2026-07-26

続き(結論と実データ)はnoteに置いています

ここでは手順のところまで書きました。実際に出た数字、うまくいかなかった条件、そのまま使える設定ファイルは、 note の記事にまとめてあります。

noteで続きを読む Xをフォローする