【テクニカル・上級編】【外部コマンド戻り値制御】Shell.Run の bWaitOnReturn による ERRORLEVEL 完全キャッチ – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【外部コマンド戻り値制御】Shell.Run の bWaitOnReturn による ERRORLEVEL 完全キャッチ

レガシーシステムの深部、あるいは日常の自動化スクリプトの土台において、VBScript(Visual Basic Scripting Edition)はいまだに現役のインフラストラクチャとして機能している。GUIを持たないサーバー環境、あるいはグループポリシーやタスクスケジューラから叩かれるバッチ処理の裏側で、OSの根幹を支え続けているのはこうした軽量なスクリプトだ。

しかし、多くの自称「中級者」が書くVBScriptは、外部コマンドの実行において致命的な欠陥を抱えている。特に、`WScript.Shell` の `Run` メソッドにおける第2引数・第3引数の挙動を正しく理解せず、「コマンドを投げっぱなしにして後続処理が進み、エラーを見逃す」というシステム障害を幾度となく引き起こしているのだ。

今回は、外部プロセスの終了コード(ERRORLEVEL)を完全にキャッチし、同期実行(Synchronous Execution)を確実に担保するための極限の知見を公開する。

1. なぜ `WScript.Shell` の `Run` なのか? (`WScript.CreateObject` の本質)

VBScriptから外部プログラムを起動する手段として、しばしば `WScript.Shell` の `Exec` メソッドと混同されることがある。
`Exec` は確かに標準入出力(StdIn/StdOut/StdErr)のストリームをリアルタイムで取得できる魅力的なオブジェクトを返す。しかし、レガシー環境や堅牢性が求められるバッチ処理において、`Exec` はメモリリークやプロセスハンドルの解放漏れを引き起こす温床となりやすい。

一方、`Run` メソッドは非常にシンプルでありながら、パラメータを適切に制御することで、OSのプロセス管理機構と完全に同期することができる。

`Run` メソッドの構文と罠

object.Run(strCommand [, intWindowStyle] [, bWaitOnReturn])

  • `strCommand`: 実行するコマンドライン文字列。
  • `intWindowStyle`: ウィンドウの表示スタイル(通常、バックグラウンド実行なら `0` を指定)。
  • `bWaitOnReturn`: ここが生死を分ける最重要パラメータ。 `True` に設定することで、スクリプトの実行は外部プロセスの終了まで完全にブロック(同期)される。

この第3引数 `bWaitOnReturn` を省略するか `False` にした場合、VBScriptは非同期(Asynchronous)でコマンドを投げる。結果、外部コマンドが失敗していなかろうが成功していなかろうが、次の行のコードが実行される。これが「ERRORLEVELが取れない」「エラーを検知できない」と嘆くエンジニアの敗因の9割を占めている。

2. 実装パターン:ERRORLEVEL 完全キャッチのアーキテクチャ

以下のコードは、単に `Run` を使うだけでなく、オブジェクトのライフサイクル管理、一時ファイルや標準出力に頼らずに確実に終了コードを変数へ格納する、プロフェッショナル・スタンダードの設計パターンである。

‘ ==============================================================================
‘ 外部コマンド同期実行 & 終了コード(ERRORLEVEL)完全キャッチテンプレート
‘ Architecture: Chief Architect Edition
‘ ==============================================================================
Option Explicit

Const 3_RETVAL_SUCCESS = 0
Dim lngExitCode
Dim strTargetCommand

‘ 実行するコマンド(例: 存在しないファイルをコピーして強制的にエラーを発生させる)
strTargetCommand = “cmd.exe /c xcopy C:\nonexistent_file.txt C:\temp\ /Y”

lngExitCode = ExecuteCommandSync(strTargetCommand)

‘ 終了コードに基づく厳密な分岐制御
If lngExitCode = 0 Then
WScript.Echo “[INFO] 外部コマンドは正常終了しました。ExitCode: ” & lngExitCode
‘ 後続の正常系処理…
Else
WScript.Echo “[ERROR] 外部コマンドが異常終了しました。ExitCode: ” & lngExitCode
‘ 異常系処理・アラート発報・ログ出力…
WScript.Quit lngExitCode
End If

‘ ——————————————————————————
‘ Function: ExecuteCommandSync
‘ Desc: 指定されたコマンドを同期実行し、正確な終了コードを返す
‘ ——————————————————————————
Function ExecuteCommandSync(ByVal strCommand)
Dim objShell
Dim intWindowStyle
Dim bWaitOnReturn
Dim intRet

‘ オブジェクトの生成 (WScript.Shell)
Set objShell = WScript.CreateObject(“WScript.Shell”)

‘ パラメータの定義
‘ 0: ウィンドウを非表示にする (WindowStyle_Hidden)
intWindowStyle = 0

‘ True: プロセスが終了するまでスクリプトの実行をブロックする (Sync)
bWaitOnReturn = True

On Error Resume Next
‘ Runメソッドの戻り値は、OSが返したプロセスの終了コード(ERRORLEVEL)そのものである
intRet = objShell.Run(strCommand, intWindowStyle, bWaitOnReturn)

If Err.Number <> 0 Then
‘ シェル自体の実行に失敗した場合(コマンドが見つからない等)
WScript.Echo “[FATAL] Shell.Run 実行時例外発生: ” & Err.Description
intRet = -999 ‘ 独自のエラーコードを割り当て
Err.Clear
End If
On Error GoTo 0

‘ メモリ最適化:オブジェクトの明示的破棄
‘ ※VBScriptの参照カウンタ方式において、スコープ抜ける前の解放は
‘ 多重起動やリソース枯渇を防ぐためのシニアの鉄則。
Set objShell = Nothing

ExecuteCommandSync = intRet
End Function

3. チーフアーキテクトが解説する「知見と罠」

① `Run` の戻り値の正体

多くの開発者が勘違いしているが、`objShell.Run(…)` の戻り値は「そのプロセスがOSに返した終了コード(Exit Code / ERRORLEVEL)」である。
バッチファイル (`.bat` / `.cmd`) やネイティブEXE (`.exe`) の中で `exit /b 1` や `return 1` と記述された値が、そのままこの `intRet` に代入される。ここを正しくキャッチできれば、VBScriptからPowerShell、あるいはサードパーティ製のCUIツールに至るまで、すべての成否をコードレベルで統制できる。

② VBScriptにおける「メモリの罠」とオブジェクト解放

VBScriptのCOMコンポーネント(`WScript.Shell` など)は、スクリプトの終了時に自動解放されるが、これは「ループ内で何度もオブジェクトを生成するバッチ処理」において致命的なメモリリーク(COMコンポーネントの参照解放漏れによるプロセス肥大化)を引き起こす。
上記のコードのように、関数内で局所的に生成し、処理の終端で必ず `Set objShell = Nothing` を明示的に実行する。これが、何百万行ものログを処理する常駐型WSHスクリプトを安定稼働させるための絶対条件である。

③ 環境変数・カレントディレクトリの罠

`Shell.Run` は、スクリプトを実行しているカレントディレクトリではなく、`c:\windows\system32` などを起点としてコマンドを実行してしまう場合がある
もし相対パスでツールを呼び出す必要がある場合は、事前に `WScript.Shell` の `CurrentDirectory` プロパティを書き換えるか、完全パス(Absolute Path)でコマンドを指定すること。ここを怠ると、テスト環境では動くが本番のタスクスケジューラ(C:\Windows\System32 から実行される)で突如として「ファイルが見つかりません」という謎のエラーに直面することになる。

4. 総括

VBScriptは古びた技術のように見えて、Windowsの根底にあるAPIとダイレクトに対話できる極めて強力なツールである。
その力を最大限に引き出すか、あるいは脆弱な「動くだけのスクリプト」で終わらせるかは、プロセス管理とエラーハンドリングに対するエンジニアの哲学にかかっている。

`bWaitOnReturn = True` による同期実行と、正確な終了コードのキャッチ。この基本にして究極のイディオムをコードベースに組み込み、レガシー環境の要塞を揺るぎないものに構築してほしい。

タイトルとURLをコピーしました