【WSHプロファイル診断】SysWOW64 と System32 のリダイレクト挙動を検知・補正する極限のアーキテクチャ
レガシーシステムの保全、あるいはキッティングの自動化において、VBScriptとWSH(Windows Script Host)はいまだに現場のインフラを陰から支える縁の下の力持ちだ。しかし、64bit Windows環境が標準となった現代において、開発者を最も絶望の淵に追い込む罠が 「WOW64(Windows on Windows 64)によるファイルシステムおよびレジストリのリダイレクト」 である。
何気なく記述した `C:\Windows\System32` へのアクセスや、レジストリの `HKLM\Software` への書き込みが、知らぬ間に `SysWOW64` や `Wow6432Node` へとすり替えられる。この暗黙の介入を見抜けなければ、基幹システムのバッチ処理はサイレントエラーの海をさまようことになる。
今回は、64bit OS上で32bit版 `cscript.exe` が意図せず起動された瞬間を動的に検知し、真のネイティブ環境へ自らを安全に再起動(Re-launch)させる、極限のWSHプロファイル診断フレームワークを解説する。
—
1. 影の罠:なぜリダイレクトはエンジニアを殺すのか
64bit版のWindowsには、互換性を維持するために32bitプロセスを隔離・保護するサブシステムが存在する。
- 32bitプロセスから `System32` へのアクセス $\rightarrow$ 自動的に `SysWOW64` へ転送
- 32bitプロセスからレジストリの `HKLM\Software` へのアクセス $\rightarrow$ 自動的に `HKLM\Software\Wow6432Node` へ転送
VBScriptを実行する際、タスクスケジューラの設定ミスや、偶発的な32bitランタイムからの呼び出しにより、意図せず32bit版の `cscript.exe` がロードされるケースは後を絶たない。この状態でシステムファイルを操作したり、64bitネイティブのCOMコンポーネントをLate Bindingで初期化しようものなら、オブジェクトの生成失敗やファイル迷子が引き起こされる。
真のエンジニアであれば、環境依存の運任せにするのではなく、「スクリプト自身が実行コンテキストを診断し、必要であれば自律的にネイティブ環境へ身を翻す」 仕組みをコードレベルで担保しなければならない。
—
2. アーキテクチャの設計思想:自己診断と再起動のループ回避
今回構築するフレームワークの要件は以下の通りである。
1. OSアーキテクチャの判別: 現在のOSが真に64bitであるか(WOW64環境を含めて)を判定する。
2. ホストプロセスのビット数判定: 現在動いている `cscript.exe` / `wscript.exe` が32bit版か64bit版かを暴く。
3. 無限ループの防止: 再起動をかけた結果、ネイティブ環境に移行できず無限にプロセスが生成される破局(デス・ループ)をコマンドライン引数で制御する。
4. 完全なオブジェクトのライフサイクル管理: 不要になったCOMオブジェクトは即座に解放し、メモリリークを根絶する。
—
3. 実装コード:WSHプロファイル自己防衛フレームワーク
以下のコードは、妥協を排したプロダクション品質のVBScriptである。そのままコピー&ペーストし、ミッションクリティカルな環境のエンントリポイントとして活用してほしい。
‘ ==============================================================================
‘ @Title: WSH Profile Diagnostics & Native Re-launcher
‘ @Description: 32bit WSHホストの検知と、64bitネイティブ環境への安全な自己再起動フレームワーク
‘ @Author: Chief Architect
‘ ==============================================================================
Option Explicit
‘ 定数の定義
Const CONST_RECURSION_FLAG = “/RERUN_NATIVE”
Const ERROR_SUCCESS = 0
Call Main()
Sub Main()
Dim objShell, objEnv, fso
Dim strScriptPath, strWScriptPath, strCommandLine
Dim is64BitOS, is32BitProcess, isAlreadyRerun
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set objShell = CreateObject(“WScript.Shell”)
Set objEnv = objShell.Environment(“Process”)
‘ 1. 無限ループ防止フラグのチェック(コマンドライン引数を走査)
isAlreadyRerun = False
Dim arg
For Each arg In WScript.Arguments
If UCase(arg) = UCase(CONST_RECURSION_FLAG) Then
isAlreadyRerun = True
Exit For
End If
Next
‘ 2. OSおよびプロセスのアーキテクチャ診断
is64BitOS = CheckIs64BitOS(objShell)
is32BitProcess = CheckIs32BitProcess(fso)
‘ ログ出力(必要に応じてイベントログやファイル出力へ変更可能)
WScript.Echo “=== WSH Profile Diagnostics ===” & vbCrLf & _
“OS is 64-bit capable : ” & is64BitOS & vbCrLf & _
“Current process is 32bit: ” & is32BitProcess & vbCrLf & _
“Rerun Guard Flag : ” & isAlreadyRerun
‘ 3. 64bit OS上かつ32bitプロセスで動作しており、かつ再起フラグ未設定の場合のみ再起動
If is64BitOS And is32BitProcess And Not isAlreadyRerun Then
WScript.Echo “[WARNING] 32-bit WSH host detected on 64-bit OS. Relaunching in Native 64-bit mode…”
‘ 64bitネイティブのcscript.exeのパスを強制構築
‘ Sysnativeは32bitプロセスからのみ見えるマジックフォルダであり、真のSystem32を指す
strWScriptPath = fso.GetSpecialFolder(0) & “\sysnative\cscript.exe”
If Not fso.FileExists(strWScriptPath) then
‘ フォールバック: 環境によってはsysnativeが使えない場合の対策
strWScriptPath = Replace(fso.GetSpecialFolder(1), “SysWOW64”, “System32”, 1, -1, vbTextCompare) & “\cscript.exe”
End If
strScriptPath = WScript.ScriptFullName
‘ 再起動コマンドの構築(//nologo とガードフラグを付与)
strCommandLine = “””” & strWScriptPath & “”” //nologo “”” & strScriptPath & “”” ” & CONST_RECURSION_FLAG
‘ 引数を引き継いで再実行
Dim i
For i = 0 To WScript.Arguments.Count – 1
If WScript.Arguments(i) <> CONST_RECURSION_FLAG Then
strCommandLine = strCommandLine & ” “”” & WScript.Arguments(i) & “”””
End If
Next
‘ プロセス起動
objShell.Run strCommandLine, 1, False
‘ オブジェクトの明示的解放(メモリ最適化)
Set objEnv = Nothing
Set objShell = Nothing
Set fso = Nothing
‘ 32bitホスト側のプロセスを終了
WScript.Quit(ERROR_SUCCESS)
End If
‘ ==========================================================================
‘ ここから先は、保証されたネイティブ環境(または純粋な32bit環境)でのメイン処理
‘ ==========================================================================
WScript.Echo “[INFO] Running in verified execution context. Proceeding to main logic…”
‘ メイン処理の呼び出し
Call ExecuteCoreBusinessLogic()
‘ クリーンアップ
Set objEnv = Nothing
Set objShell = Nothing
Set fso = Nothing
End Sub
‘ ——————————————————————————
‘ Function: CheckIs64BitOS
‘ 真のOSアーキテクチャが64bitであるかを判定する
‘ ——————————————————————————
Function CheckIs64BitOS(ByRef objShell)
Dim arch
On Error Resume Next
‘ PROCESSOR_ARCHITECTURE 環境変数はWOW64下ではAMD64を返すことがあるため、
‘ PROCESSOR_W6432632 の存在有無で厳密に判定する
arch = objShell.ExpandEnvironmentStrings(“%PROCESSOR_W6432%”)
If arch <> “%PROCESSOR_W6432%” And arch <> “” Then
CheckIs64BitOS = True
Else
‘ 代替手段として環境変数を確認
If InStr(UCase(objShell.ExpandEnvironmentStrings(“%PROCESSOR_ARCHITECTURE%”)), “64”) > 0 Then
CheckIs64BitOS = True
Else
CheckIs64BitOS = False
End If
End If
On Error GoTo 0
End Function
‘ ——————————————————————————
‘ Function: CheckIs32BitProcess
‘ 現在実行中のWSHホストが32bit版(SysWOW64経由など)であるかを判定する
‘ ——————————————————————————
Function CheckIs32BitProcess(ByRef fso)
Dim hostPath, systemFolder
hostPath = LCase(WScript.FullName)
systemFolder = LCase(fso.GetSpecialFolder(1)) ‘ 通常は System32(リダイレクト後は SysWOW64 になる)
‘ 実行パスに “syswow64” が含まれているか、
‘ または GetSpecialFolder(1) が SysWOW64 を指しているかで判定
If InStr(hostPath, “syswow64”) > 0 Or InStr(systemFolder, “syswow64”) > 0 Then
CheckIs32BitProcess = True
Else
CheckIs32BitProcess = False
End If
End Function
‘ ——————————————————————————
‘ Sub: ExecuteCoreBusinessLogic
‘ 業務ロジックの本体
‘ ——————————————————————————
Sub ExecuteCoreBusinessLogic()
‘ ここに本来の自動化スクリプトを記述する
WScript.Echo “Business logic is running securely.”
End Sub
—
4. コードの深層解説:プロが押さえるべき実装の急所
① マジックフォルダ `sysnative` の活用
32bitプロセスから真の64bit版 `System32` にアクセスするための鍵が、ファイルシステムのリダイレータが特別に用意した仮想フォルダ `sysnative` である。
通常、32bitの `cscript.exe` から `C:\Windows\System32\cscript.exe` を叩こうとすると、リダイレクトにより `SysWOW64` のものが実行されてしまう。しかし、`C:\Windows\sysnative\cscript.exe` を指定することで、OSは強制的に64bitネイティブのディレクトリへとルーティングを行ってくれる。これこそが、アーキテクチャの壁を突破する最大の秘訣である。
② 無限ループ(デス・ループ)の断ち切り
スクリプトが自己再起動する際、もしネイティブ環境への移行に失敗した場合(あるいは既にネイティブ環境であるにもかかわらず誤判定した場合)、無限にプロセスが生成され続け、最終的にリソース枯渇を引き起こす。
これを防ぐため、再起動時には必ず固有のコマンドライン引数(`/RERUN_NATIVE`)を付与し、二重起動を検知した時点で再起動をブロックする安全弁(Guard)を設けている。
③ オブジェクトの明示的解放とメモリ管理
VBScriptのガベージコレクションは参照カウント方式(COMの `IUnknown::Release`)に依存している。スコープを抜ければ自動解放されるとはいえ、長大なスクリプトや常駐型のWSHプロセスにおいて、不要になった `WScript.Shell` や `FileSystemObject` を `Set obj = Nothing` で明示的に解放する作法は、メモリフラグメンテーションを防ぐ上で極めて重要である。
—
5. チーフアーキテクトからの提言
レガシー技術と呼ばれるVBScriptであっても、OSの内部構造(WOW64サブシステム、プロセスの分離、リダイレクションのメカニズム)を深く理解していれば、モダンな環境においても一切の矛盾なく、堅牢に稼働させることが可能だ。
「動けばいい」という妥協を捨て、環境の揺らぎをコード自身が検知し、自らを補正する「自己治癒能力」を持ったスクリプト設計。この思想こそが、現場のトラブルを未然に防ぎ、真の自動化エンジニアとしての価値を証明する盾となる。
