PowerShell の ErrorAction で業務SE が踏む3パターンの落とし穴 — Continue/Stop/SilentlyContinue と try-catch

みなさんこんにちは!ヒロポンです!

Xを見てると「PowerShellでtry-catch書いたのにcatchに入らない」「赤字エラー出てるのに例外飛ばなくて後続が普通に走る」って嘆いてる多いなーって思う。

同業から「ErrorActionPreferenceと-ErrorActionとtry-catchの組み合わせで挙動変わりすぎ、仕様作ったヤツ絶対変態」って聞いたこともあるし現場でよく聞くやつ。

特にM365とかOffice365のAPI叩く系で「コンソールには赤字出てるのにcatchスルー、後で別途確認せなあかんパターン多発」って声も。

try {
    Get-ChildItem -Path '/notexist'
    Write-Host "ここが何故か実行される"
} catch {
    Write-Host "なぜここに来ない?"
}

私もこれでマジで30分ハマって「なんでcatch入らんねん!!!!!!!!」とコードを睨み続けた記憶があります。

画面の前で完全に固まりましたよ。。。。。try書いたんやからcatchに入るやろ普通、と。いや普通で考えたらあかんのか?え?なに?

っと。C#感覚で書いた瞬間に裏切られる、あの脱力感。

PowerShell初心者あるあるで、C#の例外処理感覚で書くと普通に詰まる場所なんですわ。

正体はNon-terminatingエラーというPowerShell固有の概念。で、これを制御するのがErrorActionというcmdletパラメータです。

今回はErrorActionの3パターン(Continue / Stop / SilentlyContinue)の挙動を、Dockerで実走したターミナル出力つきで解説します。

目次

忙しいあなた向けに最初にまとめ

  • PowerShellのエラーはTerminatingNon-terminatingの2種類で、多くのcmdletエラーはNon-terminating
  • try-catchが効くのはTerminatingだけ。-ErrorAction Stopを付けてNon-terminatingをTerminatingに変換するのが正解
  • 業務SEが押さえるErrorActionは3つ: Continue (デフォルト・catch効かない)/ Stop (catch効く)/ SilentlyContinue (エラー抑制)
  • ハマりポイントは3つ: $ErrorActionPreference全域設定の副作用/ SilentlyContinue乱用/ catch内で$_を見落とす
  • Docker (verify-pwsh container)検証はPowerShell言語仕様レベルのみ。Active DirectoryやExchangeなどモジュール固有cmdletはWindows実機環境で別途確認してください

以上!

原因— Non-terminatingエラーの正体

C# / Java出身者がPowerShellでハマる最大の落とし穴がこれ。

PowerShellのエラーには2種類あります。

種類 try-catch 挙動
Terminating 構文エラー/ throw / .NET 例外 ◎ catchされる 実行が即停止
Non-terminating Get-ChildItemのNot Found / Write-Error × catchされない エラー出力後に続行

問題なのは業務系で使うcmdletの大半はNon-terminatingエラーを返すこと。

ファイルが無い、ユーザーが無い、ネットワーク到達不可、全部Non-terminating。なんと業務でよく触るやつほどこっち側。

つまり「try-catchで安心」と書いたつもりが、エラー出力が赤字で出るだけで後続コードがそのまま実行される

これが一番怖い挙動です。これが罠の正体。

ハンズオン#1 — Continue (デフォルト)でcatchされない

実際にやってみます。Write-Errorで意図的にNon-terminatingエラーを出して、try-catchがどう動くか確認。

Write-Host "=== Block 1: ErrorAction Continue (デフォルト) ==="
Write-Host "[1] try ブロックの直前"

try {
    Write-Error "ファイルが見つかりません: /notexist-12345"
    Write-Host "[2] Write-Error の直後 — Continue だとここが実行される"
} catch {
    Write-Host "[CATCH] 捕捉メッセージ: $($_.Exception.Message)"
}

Write-Host "[3] スクリプト末尾"

で、実走した結果がこちら。

ErrorAction Continueでtry-catchが効かず後続実行される様子

注目ポイントは3つ。

  • [2]実行されている →エラーが出ても後続コードが走った
  • [CATCH]出ていない → try-catchが機能していない
  • 赤字でWrite-Error: ファイルが見つかりません →エラー自体はstderrに出力されている

これがNon-terminatingエラーの典型挙動。「エラーは出るけど例外じゃない」という、C# / Java出身者の直感を裏切るやつ。

ちなみにGet-ChildItem -Path '/notexist'でも同じ挙動になります(cmdlet内部でWrite-Errorを呼んでいるため)。

業務系で多用するInvoke-WebRequest Get-ADUser Test-Connectionも同類。マジで全部Non-terminating。

ハンズオン#2 — Stopを付けるとcatchが効く

同じコードに-ErrorAction Stopを1つ追加するだけで挙動が変わります。

Write-Host "=== Block 2: ErrorAction Stop ==="
Write-Host "[1] try ブロックの直前"

try {
    Write-Error "ファイルが見つかりません: /notexist-12345" -ErrorAction Stop
    Write-Host "[2] この行は実行されない (Stop で例外発生)"
} catch {
    Write-Host "[CATCH] 捕捉メッセージ: $($_.Exception.Message)"
}

Write-Host "[3] スクリプト末尾"

実行結果。

ErrorAction Stopでcatchブロックに飛ぶ挙動

今度は3点ぜんぶ逆転。

  • [2]出ていない → tryブロックはWrite-Errorの時点で中断
  • [CATCH]メッセージが捕捉された→ catchブロックが実行された
  • stderrが → catchで握ったのでerror streamに流れていない

これが正解の挙動。

-ErrorAction StopでNon-terminatingをTerminatingに変換することで、ようやくtry-catchがいい感じに機能します。マジで良かった。

3 ErrorActionの比較表— 3軸で違いを並べる

ErrorActionには全部で6種類ありますが、我々が押さえるのは3パターンで十分。

try-catch連携/再実行可能性/ログ残し方の3軸でまとめたのが下の表です。

PowerShell ErrorAction 3パターン比較表(try-catch連携/再実行可能性/ログ残し方)

要点:

  • Stop — try-catch効く・catch内で構造化ログ出せる・冪等性確保→ 業務系の止めるべき処理に最適
  • Continue (デフォルト)— try-catch効かない・赤字エラーは出る→ 通知だけで済む処理向け
  • SilentlyContinue —エラー痕跡ゼロ・失敗に気付けない→ 想定済みエラーの抑制のみ

Ignore / Inquire / Suspendもありますが、我々が日常使いするのはこの3つだけ!!!

ハマりポイント3つ(現場で踏みがちなやつ)

ここまで「ErrorAction Stopを付ければ大丈夫」みたいに書いてきましたが、そうじゃないケースが3つあります

あなたのために、現場で実際に踏んだやつを共有しておきます。

$ErrorActionPreference = 'Stop'の副作用

スクリプト全体にStopを効かせるなら、先頭にこう書けば一発です。

$ErrorActionPreference = 'Stop'

ただしこれ、想定外のcmdletまでStopになる

私もある日、ログイン履歴チェック用のスクリプトに$ErrorActionPreference = 'Stop'を仕込んだんです。よっしゃこれで全部Stopになるから安心や、と。

そしたらTest-Connectionのタイムアウトでスクリプト全体がガッツリ落ちて、朝1時間原因に辿り着けなかった経験があります。

朝出社直後のまだコーヒーも淹れてないタイミングで「は?なんで動かんの??」って画面とにらめっこ。。。。。隣の先輩に「これStopの副作用やで」と言われて初めて気付いた、まじか!!!!!というアハ体験。

対策はtry-catchで囲んだ範囲だけStopにするか、cmdlet単位で-ErrorAction Stopを付ける。

グローバル設定は使う場面を絞るのが安全。

② SilentlyContinue乱用の弊害

「エラーが赤字で出るのが鬱陶しい」という理由で-ErrorAction SilentlyContinueを多用すると、本当に止めるべきエラーまで握り潰すことになります。

ある夜間バッチでCopy-Item -ErrorAction SilentlyContinueを使ってたんです。

そしたらコピー先のディスクがfullで、なんと3日分のファイルが消失していたのを翌朝まで把握できなかった経験もあります。色々な経験してるでしょ?

朝出社してログ見て気付いて、焦る。。。「3日分」 って数字を見た瞬間に背中に冷や汗。上司に報告しに行く時の足の重さ、今でも覚えてます。これもやらかしの原因。

対策はSilentlyContinueを想定済みのエラー(例:ファイル存在チェックで無くてもOKな場面)のみに絞る。

デフォルトはContinue (赤字で出るほう)のままにしておく。

③ catch内で$_を見落とす

catchブロックは入ってる前提だけど、どんなエラーかをログに残さないと後でデバッグできない。

# ✗ 中身ゼロ
} catch {
    Write-Host "エラーが発生しました"
}

# ✓ $_ でエラー情報を取り出す
} catch {
    Write-Host "エラー: $($_.Exception.Message)"
    Write-Host "発生位置: $($_.InvocationInfo.PositionMessage)"
    Write-Host "スタックトレース: $($_.ScriptStackTrace)"
}

これは去年、後輩が書いたスクリプトのデバッグを2時間やった時の話。

$_見てないせいで原因が一切分からん」という事態に踏み込んで、「エラーが発生しました」 だけ出力するcatch句を見つけた瞬間、口から出たのは「いやそれ何のエラーやねん」 でした。。。。。後輩本人も横で苦笑い。

catch句は$_の中身をログに残すのが鉄則。

まとめ

PowerShellのエラー処理はC# / Javaの直感が通用しない最大の落とし穴領域。

ポイントを3つだけ:

  • try-catchを書く時は-ErrorAction Stopもセットで書く
  • $ErrorActionPreference = 'Stop'はスクリプト先頭で全体適用できるが副作用に注意
  • SilentlyContinueは想定済みエラーのみに絞り込む・乱用しない

これでPowerShellエラー処理の地雷踏みはいい感じに9割回避できます!!!!!!

ぶっちゃけ、業務SEがPowerShellに手を出した時の「なんでtry-catch効かないんだ??」はこんな感じで全員一度は通る道です。

ここを早期に踏んでおくと、後輩が同じところで悩んでる時に「ああそれErrorAction Stop付けてないだろ」と即座に救えるようになるので、結構美味しいスキルです。

よくある質問

Q1. try-catchを書いたのにcatchブロックが実行されないのはなぜですか?

A. PowerShellの多くのcmdletが出すのはNon-terminatingエラーで、デフォルトのErrorAction Continueではtry-catchでは捕捉できません。-ErrorAction Stopを付けるとTerminatingに変換されてcatchが効きます。これがPowerShell初心者あるある№1です。

Q2. ErrorActionを全体に効かせるには?

A.スクリプト先頭に$ErrorActionPreference = 'Stop'を書くと、その配下のcmdlet全てにErrorAction Stopが適用されます。ただしハマりポイント①で書いた通り、想定外のcmdletまでStopになる副作用があるので、使う場面は絞るのが安全。

Q3. SilentlyContinueはどんな時に使う?

A. 想定済みの軽微なエラー (例:ファイル存在チェックで無くてもOK・テンポラリ削除で既に消えてた場面)を抑制したい時だけ。乱用すると重大なエラーまで無視して、デバッグ困難になります。デフォルトはContinue (赤字で出る方)のままにしておくのが推奨です。

関連記事

以上!

執筆者

バイブス父さん — 業務 SE 7 年 (正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SES 複数社・フリーランスエージェント複数経由の経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。

🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る

この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次