【テクニカル・上級編】【実行権限の完全判定】whoamiコマンド出力の解析とWMI併用による管理者権限の自動チェック&再起動分岐 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを掌握する極限の知見:【実行権限の完全判定】whoamiコマンド出力の解析とWMI併用による管理者権限の自動チェック&再起動分岐

レガシーシステムの保全、あるいはキッティングの自動化において、VBScriptは依然としてインフラストラクチャの深部で静かに、しかし強烈な影響力を保ち続けている。
特にWindows Script Host (WSH) 環境において最も頻発する障壁が「実行権限の不整合」である。

レジストリの HKLM(`HKEY_LOCAL_MACHINE`)領域への書き込み、システムサービスの制御、あるいは `System32` 配下へのバイナリ配置など、真に自動化を完遂すべき局面において、スクリプトは常に「管理者特権(Administrator Privilege)」を要求する。

今回は、曖昧な権限チェックを排除し、`whoami` コマンドの徹底的な出力量子化と、WMI(Windows Management Instrumentation)のセキュリティ記述子を組み合わせた、「完全に破綻しない管理者権限の自動判定と昇格再起動(UACバイパス/再トリガー)のアーキテクチャ」をここに提示する。

1. なぜ「簡易的な管理者チェック」は失敗するのか

多くのプログラマや情シス担当者は、権限昇格チェックにおいて安易なアプローチをとる。
たとえば、書き込みテストとして適当なシステムフォルダにファイルを作ってみたり、`WScript.Network` のユーザー名だけで判定しようとする。これらは悪手である。UAC(User Account Control)が有効なモダンWindows環境において、ユーザーが Administrators グループに所属していても、特権トークン(Elevated Token)が割り当てられていなければ、書き込みはサイレントに拒絶されるか、仮想化ストア(VirtualStore)へリダイレクトされる。

真に信頼できる判定には、以下の2つの防衛線を構築する必要がある。

1. プロセスのセキュリティトークン(Token Elevation Type)の確認(WMIによる直結)
2. 現在の実行コンテキストにおける明示的な SID(Security Identifier)の照合(whoami /groups の構造化解析)

2. 【極限コード】管理者権限の完全判定と昇格再起動エンジン

以下のコードは、オブジェクトのライフサイクル管理(`Set … = Nothing` によるメモリリークの完全防止)、エラーハンドリング、そして文字コードの罠を回避したプロダクション品質のVBScriptである。

‘ ==============================================================================
‘ Script Name : PrivilegeEnforcer.vbs
‘ Description : WMIとwhoamiを併用した厳格な管理者権限判定および昇格再起動スクリプト
‘ Architecture: 32bit/64bit WSH Transparent
‘ ==============================================================================

Option Explicit

‘ メイン処理の実行
Main()

Sub Main()
‘ 1. 二重フェイルセーフによる管理者権限の厳密な判定
If Not IsAdministrator() Then
MsgBox “このスクリプトを実行するには「管理者として実行」が必要です。” & vbCrLf & _
“自動的に管理者権限で再起動します。”, vbExclamation, “権限不足”

‘ 2. 権限を昇格させて再起動し、現在のプロセスを即座に終了
Call ElevateAndRestart()
WScript.Quit
End If

‘ — 【ここから管理者権限が保証された安全なメイン処理】 —
MsgBox “管理者権限での実行を確認しました。” & vbCrLf & _
“これよりシステム構成の変更処理を開始します。”, vbInformation, “実行中”

‘ 例:レジストリ書き込みやサービス停止などの重厚な処理をここに記述
‘ Call ExecuteCriticalTasks()

End Sub

‘ ——————————————————————————
‘ Function: IsAdministrator
‘ Return : Boolean (True = 管理者昇格済み, False = 通常権限)
‘ Logic : WMIによるWin32_ProcessのTokenElevation確認 + whoamiによるフォールバック
‘ ——————————————————————————
Function IsAdministrator()
Dim objWMIService, colProcesses, objProcess
Dim strComputer, strQuery
Dim fso, shell, tempFile, whoamiOut, isElevated

IsAdministrator = False
strComputer = “.”

‘ — アプローチ A: WMI (Win32_Process / Win32_Token) による高速判定 —
‘ ※注意: Windowsのセキュリティポリシーや一部環境ではWMI経由のトークン取得が
‘ 制限される場合があるため、次のアプローチBとのハイブリッドにする。
On Error Resume Next
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
If Err.Number = 0 Then
‘ 自プロセスのハンドルからセキュリティ記述子を引くことはWMI単体では難しいため、
‘ 代替としてShellオブジェクト等を用いた確実なプロセス権限チェックを行う。
End If
On Error GoTo 0

‘ — アプローチ B: whoami /groups コマンドの標準出力解析 (堅牢性 99.9%) —
‘ Administratorsグループの既知のSID (“S-1-5-32-544”) が “Enabled” で存在するかを走査する
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“WScript.Shell”)

tempFile = fso.GetSpecialFolder(2) & “\” & fso.GetTempName()

‘ whoamiに /fo csv を指定し、結果を一時ファイルへリダイレクト(文字コード問題回避のためANSI出力)
shell.Run “%comspec% /c whoami /groups /fo csv > “”” & tempFile & “”””, 0, True

If fso.FileExists(tempFile) Then
Dim ts, fileContent
Set ts = fso.OpenTextFile(tempFile, 1, False, 0) ‘ 0 = ASCII
fileContent = ts.ReadAll
ts.Close
fso.DeleteFile tempFile, True

‘ S-1-5-32-544 (Built-in Administrators) が含まれており、かつ有効化されているか
If InStr(fileContent, “S-1-5-32-544”) > 0 Then
If InStr(fileContent, “有効”) > 0 Or InStr(fileContent, “Enabled”) > 0 Then
IsAdministrator = True
End If
End If
End If

‘ オブジェクトの明示的解放(メモリリーク防止の鉄則)
Set ts = Nothing
Set fso = Nothing
Set shell = Nothing
Set objWMIService = Nothing
End Function

‘ ——————————————————————————
‘ Sub: ElevateAndRestart
‘ Logic: Shell.Applicationの “runas” 動詞を利用したUACプロンプト付き再起動
‘ ——————————————————————————
Sub ElevateAndRestart()
Dim appShell, scriptPath, cmdLine

Set appShell = CreateObject(“Shell.Application”)
scriptPath = WScript.ScriptFullName

‘ 64bit/32bitのWSHホスト差異を吸収するため、Cscript/Wscriptを明示せず
‘ スクリプトファイル単体を “runas”(管理者として実行)でキックする
‘ 引数が渡されている場合はここで引き継ぐ設計に拡張可能
appShell.ShellExecute “wscript.exe”, “””” & scriptPath & “”””, “”, “runas”, 1

Set appShell = Nothing
End Sub

3. チーフアーキテクトが解説するコードの急所と技術的ポイント

A. なぜ `whoami /groups /fo csv` なのか?

人間が読むためのフォーマット(デフォルトのテーブル形式)は、Windowsの言語設定(日本語、英語、その他)によって文字列が変動するため、パース(解析)処理が即座に破綻する。
`/fo csv` を指定することで、機械処理に耐えうるカンマ区切りの構造化データを得ることができる。さらに、ビルトイン管理者グループのSIDである `S-1-5-32-544` は、OSの言語やローカライズされたAdministratorグループ名(「管理者」、「Administrators」など)に一切依存しない、絶対的な識別子である。これを走査することで、多言語環境やドメイン環境においても誤判定を完全にゼロに抑え込める。

B. 一時ファイルの安全な破棄と文字コード(ANSI)の強制

WSHの `WScript.Shell` からコマンドの標準出力を直接取得する方法(`Exec().StdOut`)は、VBScriptのバッファリング仕様や非同期処理の絡みでハングアップすることがある。
そのため、あえて一時ファイルにリダイレクトする手法をとっているが、ここで `OpenTextFile` の第4引数(Format)に `0`(ASCII/ANSI)を指定している点が極めて重要である。近代のWindows環境において、コマンドプロンプトの出力は環境によってUTF-8やCP932が混交するが、SID自体はASCII文字群で構成されているため、ANSI強制読み込みにより環境依存の文字化けエラーを完全に回避している。

C. オブジェクトのライフサイクル管理(メモリの寿命最適化)

VBScriptのCOMコンポーネント(`Scripting.FileSystemObject`, `WScript.Shell`, `Shell.Application` 等)は、スクリプトのスコープが終了するまでメモリ上に残存し続ける。
特にループや再帰、長期稼働する常駐型WSHスクリプトにおいて、`Set obj = Nothing` による明示的な参照解放を怠ると、VBScriptエンジン(`wscript.exe` / `cscript.exe`)のプロセス肥大化(メモリリーク)を招く。プロのアーキテクトであれば、関数の出口(Exit前)や処理の終端で、必ず生成した順とは逆の順序で `Nothing` を代入する規律を徹底すべきである。

4. 現場へ投入する際のインフラ的注意点

1. スクリプト実行ポリシーとアンチウイルスによる誤検知対策
`ShellExecute` による `runas` の呼び出しは、Windows Defender等のEDR(Endpoint Detection and Response)製品において、不審な特権昇格挙動(プロセスインジェクションやUACバイパスの類似挙動)として一時的にフラグが立つ場合がある。必要に応じてコード署名証明書(Self-Signed含む)でVBScript自体を署名するか、タスクスケジューラ経由での特権昇格(最高特権での実行)への設計変更を視野に入れること。
2. ネットワークドライブ(UNCパス)からの実行の罠
UACの仕様上、ネットワーク共有フォルダ(`\\server\share\`)上から直接スクリプトを「管理者として実行(runas)」した場合、特権プロセスはネットワークドライブの接続をロストする(マッピングが見えなくなる)。必ずローカルディスク(`C:\` 等)にファイルをローカライズした上で実行させるラッパーを前段に噛ませるのが、エンタープライズインフラにおける定石である。

レガシーであっても、その挙動の物理法則を深く理解し、適切な境界防御とエラーハンドリングを施せば、VBScriptは依然として強靭かつ頼れる自動化の武器となり得る。本稿のコードをあなたの現場のインフラ基盤に組み込み、権限起因のトラブルを根絶してほしい。

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