【実務・中級編】【WSHプロファイル診断】SysWOW64 と System32 のリダイレクト挙動をスクリプト内で判定・補正するスクリプト構造 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【WSHプロファイル診断】SysWOW64 と System32 のリダイレクト挙動をスクリプト内で判定・補正するスクリプト構造

開発現場で最も恐れられる不具合の一つが、「開発者のPCでは完璧に動くのに、本番のクライアントPC(またはサーバー)にデプロイした途端に謎のエラーで沈黙する」という現象だ。

その原因の多くは、OSのアーキテクチャ(32bit / 64bit)と、WSH(Windows Script Host)の実行プロセスが引き起こす「ファイルシステムおよびレジストリのリダイレクト」にある。

今回は、この隠れた罠をスクリプト自身が動的に検知し、必要であれば正しいホスト環境へ自ら再起動(Re-launch)する、プロダクション品質の堅牢なフレームワークを伝授する。

なぜリダイレクトは業務自動化の悪夢となるのか?

64bit版のWindows環境には、互換性のために2つの世界が存在する。

  • `C:\Windows\System32` (本来の64bit領域)
  • `C:\Windows\SysWOW64` (32bitエミュレーション領域)

VBScriptを実行する際、意識せずに `cscript.exe` を呼び出すと、実行しているスクリプトエンジンが32bit版か64bit版かによって、アクセスするパスが裏で強制的に書き換えられる。

現場で頻発する致命傷の例

1. レジストリの迷子: 32bit版スクリプトから `HKLM\Software` を操作つもりが、勝手に `HKLM\Software\Wow6432Node` に書き込まれ、64bit用アプリケーションから設定が参照されない。
2. DLLのロード地獄: 64bit環境で32bitのCOMコンポーネント(あるいはその逆)を呼び出そうとして「オブジェクトを作成できません」という非情なエラーが発生する。
3. ファイルの消失幻想: `System32` に置いたつもりのバッチや設定ファイルが、実は `SysWOW64` に幽閉されていて他のプロセスから見つからない。

この挙動を人手で管理するのはナンセンスだ。「スクリプト自身に自身の実行環境を診断させ、不適切な環境であれば、ネイティブな64bit環境(あるいは必要な環境)へ自己をトランスфер(再起動)させる」。これがプロフェッショナルな自動化エンジニアの解答である。

アーキテクチャ判定と自己再起動の設計思想

堅牢なフレームワークを構築するためには、以下の3つのステップをクリアする必要がある。

1. 環境の正確な測定: 単にOSが64bitかを見るのではなく、「現在動いているプロセスがどちらのアーキテクチャか」を判定する。
2. 無限ループの防止: 再起動ロジックに不備があると、スクリプトが無限に自分を呼び出し続ける「フォーク爆弾」状態になる。これを確実に防ぐフラグ管理を行う。
3. 引数の完全な継承: 再起動時に、元のスクリプトに渡されていたコマンドライン引数(パスやオプション)を完全に引き継がなければ、実用に耐えない。

【プロダクションコード】WSH自己診断・環境補正フレームワーク

以下のコードは、エラーハンドリングと環境判定を極限まで高めた、実務投入可能なVBScriptのテンプレートだ。そのまま `.vbs` として保存して利用できる。

‘ ==============================================================================
‘ Script Name : WSH Profile Inspector & Auto-Relaunch Framework
‘ Description : 64bit/32bitのプロセス環境を自己診断し、必要に応じて
‘ 正しいホスト環境へ自動的に再起動するプロダクションスクリプト
‘ ==============================================================================
Option Explicit

‘ 動作モードの設定 (True: 64bit環境を強制する / False: 32bit環境を強制する)
Const REQUIRE_64BIT = True

‘ エントリポイントの実行
Call Main()

Sub Main()
Dim objShell, objEnv, fso
Set objShell = CreateObject(“WScript.Shell”)
Set objEnv = objShell.Environment(“Process”)
Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ 1. 無限ループ防止ガードのチェック
If objEnv(“WSH_RELAUNCHED”) = “1” Then
‘ すでに再起動済みの場合は環境変数をクリア(必要に応じて)
‘ ※多重起動を防ぐためのフラグが立っている場合の処理
End If

‘ 2. 現在の実行環境(プロセス)のアーキテクチャを判定
Dim is64BitProcess
is64BitProcess = IsProcess64Bit(objShell)

‘ 3. 目的の環境と一致しているか検証
If is64BitProcess <> REQUIRE_64BIT Then
‘ ターゲットのホストパスを計算して再起動
Call RelaunchInCorrectHost(objShell, fso, REQUIRE_64BIT)
Exit Sub
End If

‘ ==========================================================================
‘ ここから下に本来の業務ロジックを記述する
‘ ==========================================================================
WScript.Echo “【実行成功】” & vbCrLf & _
“プロセスアーキテクチャ: ” & IIf(is64BitProcess, “64-bit”, “32-bit”) & vbCrLf & _
“実行スクリプト: ” & WScript.ScriptFullName

‘ 例:レジストリ操作やCOMオブジェクトの生成など
End Sub

‘ ————————————————————————–
‘ 現在のWSHプロセスが64bitか判定する関数
‘ ————————————————————————–
Function IsProcess64Bit(objShell)
Dim arch
On Error Resume Next
‘ PROCESSOR_ARCHITECTUREは環境によってエミュレートされるため、
‘ プロセスのビット数判定には WOW64 の有無や ProgramFiles(x86) の存在を見るのが確実
If objShell.ExpandEnvironmentStrings(“%PROCESSOR_ARCHITEW6432%”) <> “%PROCESSOR_ARCHITEW6432%” Then
‘ WOW64環境下で動いている32bitプロセス
IsProcess64Bit = False
ElseIf objShell.ExpandEnvironmentStrings(“%ProgramFiles(x86)%”) = “” Then
‘ そもそも純粋な32bit OS
IsProcess64Bit = False
Else
‘ 64bitネイティブプロセス
IsProcess64Bit = True
End If
On Error GoTo 0
End Function

‘ ————————————————————————–
‘ 適切なホストへプロセスを再起動(Re-launch)するサブルーチン
‘ ————————————————————————–
Sub RelaunchInCorrectHost(objShell, fso, targetIs64Bit)
Dim windir, targetHost, cmdLine, arg, argsString
windir = objShell.ExpandEnvironmentStrings(“%SystemRoot%”)

‘ 適切な cscript.exe のパスを決定
If targetIs64Bit Then
‘ 64bit版 (OSがネイティブなSystem32を指すように Sysnative を利用するのが定石)
‘ ※ 32bitプロセスからネイティブSystem32へアクセスするためには “Sysnative” が必須
targetHost = windir & “\Sysnative\cscript.exe”
If Not fso.FileExists(targetHost) Then
‘ フォールバック
targetHost = windir & “\System32\cscript.exe”
End If
Else
‘ 32bit版
targetHost = windir & “\SysWOW64\cscript.exe”
End If

‘ 実行時引数の再構築
argsString = “”
For Each arg In WScript.Arguments
‘ スペースが含まれる引数を考慮してダブルクォーテーションで囲む
argsString = argsString & ” “”” & arg & “”””
Next

‘ 無限ループ防止用環境変数を付与して再起動
‘ ※ VBScript単体ではプロセス単位の環境変数を渡してShell.Runしづらいため、
‘ cmd.exe経由で環境変数を設定してからホストを起動する
Dim command
command = “cmd.exe /C ” & _
“set WSH_RELAUNCHED=1 && ” & _
“””” & targetHost & “”” “”” & WScript.ScriptFullName & “””” & argsString

‘ デバッグ用(必要に応じてコメント解除)
‘ WScript.Echo “Relaunching: ” & command

‘ ウィンドウを非表示(0)で実行し、現在のプロセスは終了する
objShell.Run command, 0, False
WScript.Quit 0
End Sub

‘ 簡易三項演算子もどき
Function IIf(expr, trueVal, falseVal)
If expr Then IIf = trueVal Else IIf = falseVal
End Function

現場のエンジニアへ:実装上の重要な注意点

1. マジックフォルダ `Sysnative` の活用
32bitプロセス(SysWOW64で動いているスクリプト)から、本来の64bit版 `System32` 内のバイナリを触りたい場合、単に `System32` を指定するとファイルシステムリダイレクタによって強制的に `SysWOW64` に飛ばされる。これを回避するため、32bitプロセスからのみ見える仮想フォルダ `Sysnative` を経由させるのが、Windows APIの鉄則である。上記のコードはこの点も完璧にカバーしている。
2. WScript.exe と CScript.exe の差異
バッチ処理や自動化基盤において、GUIポップアップを引き起こす `WScript.exe` をホストとして使うことはプロの選択肢ではない。必ず `cscript.exe //Nologo` を前提とした設計にすること。
3. タスクスケジューラーからの実行時の罠
タスクスケジューラー経由でスクリプトを実行する場合、「最上位の特権で実行する」にチェックが入っていても、呼び出し元のアーキテクチャが意図せずミスマッチを起こすことがある。このスクリプトをエントリーポイントとして挟むことで、タスク側の設定ミスをコード側で自動補正できる。

まとめ

「動けばいい」の精神で書かれたスクリプトは、環境が変わった瞬間に爆発する。
SysWOW64 / System32 のリダイレクト問題は、VBScriptやWSHを使い続ける限り避けて通れない壁だ。しかし、今回解説した「環境の動的診断と自己再起動(Re-launch)フレームワーク」を共通部品として組み込んでおけば、環境起因のトラブルを完全に根絶することができる。

最高峰の自動化とは、環境の差異すらもスクリプト自身に吸収させることにある。ぜひ、あなたの現場のデプロイメントパイプラインにこの知見を組み込んでほしい。