【PowerShell】PowerShellの$LASTEXITCODEとcmdの%ERRORLEVEL%が一致しないケース
前書き
約二年ぶりの更新です。元々メモ書きのようなブログですが、ここ二年ほどメモするほどの内容がありませんでした。
Spring Boot とか、Flutter とか、vue.js とか、Azure のアレコレとか、AWS のアレコレとか、Firebase のアレコレとか、色々やってたんですけどね。
上記のうち、Flutter の話はいつかしますが、今日は PowerShell の話です。
$LASTEXITCODE
とは
PowerShell には自動変数と呼ばれる、一種の予約語のような変数があります。
$LASTEXITCODE
はその中の一つであり、
最後に実行された Windows ベースのプログラムの終了コードが格納されます。
と書いてある通り、他プロセスの実行結果が格納されます。
.bat
でバリバリとバッチ処理を作ったことがある人なら「あ、%ERRORLEVEL%
みたいなもんね。」と思うかもしれません。合ってます。合っていますが、完全に%ERRORLEVEL%
と互換性があるわけではなく、それが原因でめちゃめちゃにハマりました。
$LASTEXITCODE
と%ERRORLEVEL%
が一致しなくなるバッチ
こんな.bat
ファイルを作ります。サブルーチンの方でexit /b 1
を返し、メイン処理は特に何も返さない、それだけの処理です。
@echo off call :hoge exit /b :hoge exit /b 1
作った.bat
ファイルをコマンドプロンプトで呼び出し、%ERRORLEVEL%
を調べます。普通に1
が返ってきます。
> test.bat > echo %ERRORLEVEL% 1
PowerShell で同じように呼び出し、$LASTEXITCODE
を調べます。
> .\test.bat > $LASTEXITCODE 0
$LASTEXITCODE
は%ERRORLEVEL%
を見ているわけではないので、メイン処理の返り値を取得してしまいます。よって、0
が表示されます。
ワークアラウンド
自分で作った.bat
ならメイン処理でexit /b %ERRORLEVEL%
とすればいいんですが、諸々の事情*1で.bat
の方を直せない場合、PowerShell 側で何とかする必要があります。
考え方は簡単です。明示的にcmd.exe /C
でバッチを叩いた後、exit %ERRORLEVEL%
すればいいだけです。
&
でコマンドを連続実行してやればワンライナーで楽勝です。遅延環境変数を展開できるよう/V:ON
の指定を忘れずに。
> cmd /V:ON /C "test.bat & exit !ERRORLEVEL!" > $LASTEXITCODE 1
まとめ
うーん。めんどくさい。