エラー処理は大事

PowerShellで「初期処理でループしながらファイルの削除とかやって、そのあとメイン処理に入ろう」なんてときに「コマンドレット実行結果NGでも空回って進んで欲しい!」って思うことありますよね。

Shellなので、コマンドのリターンコード見て条件分岐する、という発想でよいのですが、せっかくのPowerShellだし例外処理で実装してみよう、と思うわけです。ところが普通に書くとなかなかcatch節に入ってくれないです。

これは、デフォルトの$ErrorActionPreference(デバッグモード変数みたいなもん)の値が"Continue"であり、この時、「Write-Errorコマンドレットからエラー表示される処理はcatch節で補足されない」という仕様にヒットしているせいっぽいです。Remove-Itemがファイル削除に失敗してIOExceptionを投げる時、Write-Errorを使ってるのですね。


コマンドレットごとに、エラー時の動作を制御する引数として"-ErrorAction"というのが用意されていて、それを使って実行したコマンドレットについては$ErrorActionPreferenceの値をオーバーライドできます。
こいつを使って"Stop"にオーバーライドしてあげると、try/catchできるようになります。

試しに"hoge.txt"を作り、ロックを取得できるエディタ等で開いた状態で削除してみましょう。

New-Item hoge.txt -type file #ここでファイルを開いてロック

try{ Remove-Item hoge.txt }catch{ Write-Output "ナイスキャッチ" } # 削除を試みる
Remove-Item : 項目 E:\tmp\test\hoge.txt を削除できません: 別のプロセスで使用されているため、プロセスはファイル 'E:\tmp\test\hoge.txt' にアクセスできません。
発生場所 行:1 文字:17
+ try{ Remove-Item <<<<  "hoge.txt" }catch{ Write-Output "ナイスキャッチ" }
    + CategoryInfo          : WriteError: (E:\tmp\test\hoge.txt:FileInfo) [Remove-Item]、IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand

ぬふう。
それでは、ErrorActionを指定してみる。

New-Item hoge.txt -type file #ここでファイルを開いてロック

try{ Remove-Item hoge.txt -ErrorAction:Stop }catch{ Write-Output "ナイスキャッチ" } # 削除を試みる
ナイスキャッチ

catch節に入った。

マニュアルは以下のコマンドから。

Get-Help about_CommonParameters