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

スポンサーリンク

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

開発プロジェクトの現場において、VBScriptによる自動化スクリプトが「権限不足」で突如として沈黙するインシデントほど、エンジニアの頭痛の種はない。レジストリの書き換え、サービス制御、システムフォルダへのファイル配置――これらはすべて、昇格されていない通常のプロセスから実行すれば容赦なく弾かれる。

「あらかじめ右クリックして『管理者として実行』してください」
――そんなマニュアル運用をユーザーに強いる設計は、エンジニアの怠慢でしかない。プロフェッショナルな自動化ツールとは、スクリプト自身が自らの実行権限をコンマ数秒で正確に判定し、不足していれば自動的に管理者権限で自分自身を再起動(スワップ)するものでなければならない。

今回は、WMI(Windows Management Instrumentation)の深部と、環境に依存しない `whoami` コマンドの出力を組み合わせた、「すり抜けゼロ」の完全権限判定・自動昇格アーキテクチャを伝授する。

1. なぜ「簡易的な判定」では実務で破綻するのか?

多くの初学者がやりがちな間違いが、`WScript.Network` オブジェクトを使ったユーザー名のチェックや、特定のフォルダへの書き込みテスト(`On Error Resume Next` で誤魔化す手法)だ。

  • ユーザー名チェックの限界: 「Administrator」というアカウント名であっても、UAC(ユーザーアカウント制御)のコンテキスト下では、標準権限でトークンが生成されている場合がある。
  • ファイル書き込みテストの脆弱性: アンチウイルスソフトやグループポリシーの権限継承の揺らぎによって、テスト書き込みが偽陽性・偽陰性を引き起こし、正確な特権の有無を判定できない。

我々が求めるべきは、OSのセキュリティサブシステムが現在行っているプロセスに対して「管理者特権トークン(Administrator Access Token)を割り当てているか」の厳密な確認である。

2. アーキテクチャ設計:WMIとシェル制御の融合

堅牢な判定と再起動を実現するため、以下の2つのアプローチを論理的に統合する。

1. WMI (`Win32_Process`) によるプロセス所有者・整合性チェック:
現在のプロセスがどのようなセキュリティコンテキストで稼働しているかを抽出し、特権昇格されているかを判定する。
2. `Shell.Application` による `runas` 再起動:
権限不足が判別された瞬間、WSHの `WScript.Shell` ではなく、COMのシェルオブジェクトを利用して `runas` 動詞(Verb)で自プロセス(`WScript.ScriptFullName`)を再実行し、旧プロセスを潔く自滅(`WScript.Quit`)させる。

3. プロダクションコード:完全権限チェック&自動昇格スクリプト

以下のコードは、エラーハンドリングを徹底し、二重起動の無限ループを防ぐガード句を組み込んだ、そのまま現場で使えるプロダクション品質のVBScriptである。

‘ ==============================================================================
‘ Script Name : AdminGuardRunner.vbs
‘ Description : 管理者権限の完全判定と、不足時の自動昇格再起動を行うテンプレート
‘ Architecture: WMI Process & Shell.Application Integration
‘ ==============================================================================
Option Explicit

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

Sub Main()
‘ 1. 管理者権限の有無を厳密に判定
If Not IsUserAnAdmin() Then
MsgBox “このスクリプトを実行するには「管理者権限」が必要です。” & vbCrLf & _
“OKをクリックすると、自動的に管理者として再起動します。”, _
vbExclamation + vbOKOnly, “権限昇格の要求”

‘ 2. 管理者権限で自分自身を再起動し、現在のプロセスを終了
Call ElevateAndRestart()
Exit Sub
End If

‘ ==============================================================================
‘ 【ここから下は安全に管理者権限が保証されたメイン処理】
‘ ==============================================================================

MsgBox “管理者権限での実行を確認しました。” & vbCrLf & _
“業務自動化のコアロジックを実行します。”, _
vbInformation, “実行中 (Elevated)”

‘ 例:レジストリ操作やシステムサービスの制御など
‘ Call ExecuteBusinessLogic()

End Sub

‘ ——————————————————————————
‘ 関数名 : IsUserAnAdmin
‘ 概要 : WMIを使用して現在のプロセスが管理者権限で実行されているかを厳密に判定
‘ 戻り値 : Boolean (True = 管理者権限あり / False = 権限不足)
‘ ——————————————————————————
Function IsUserAnAdmin()
Dim objWMIService, colProcesses, objProcess
Dim strWQL, intProcessID

IsUserAnAdmin = False
On Error Resume Next

‘ 現在のプロセスのPIDを取得
‘ 注: WScriptのプロセス自体(cscript.exe または wscript.exe)のPIDを特定する
intProcessID = GetCurrentProcessID()

If intProcessID = 0 Then
‘ 万が一PIDが取得できない場合は安全側に倒してFalse
Exit Function
End If

‘ WMI接続
Set objWMIService = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2”)
strWQL = “SELECT FROM Win32_Process WHERE ProcessId = ” & intProcessID
Set colProcesses = objWMIService.ExecQuery(strWQL)

For Each objProcess in colProcesses
‘ GetOwnerExメソッドにより、プロセスの実行アカウントとSIDを取得
Dim strNameOfUser, strNameOfDomain, intReturn
intReturn = objProcess.GetOwnerEx(strNameOfUser, strNameOfDomain)

If intReturn = 0 Then
‘ ここでビルトインAdministrator、またはAdministratorsグループ所属の判定を行う
‘ さらに堅牢にするため、whoami /groups の結果を解析するアプローチも併用可能
IsUserAnAdmin = CheckTokenMembership(strNameOfUser)
End If
Next

If Err.Number <> 0 Then
‘ WMIクエリ失敗時は安全のためFalseを維持
IsUserAnAdmin = False
End If
On Error GoTo 0
End Function

‘ ——————————————————————————
‘ 補助関数 : CheckTokenMembership (簡易的な管理者グループ・ユーザー名検証)
‘ ——————————————————————————
Function CheckTokenMembership(ByVal userName)
‘ 簡易的かつ実用的なフォールバックとして、whoamiコマンドの出力を利用する
Dim shell, exec, output
Set shell = CreateObject(“WScript.Shell”)

‘ whoami /priv コマンドは管理者特権がある場合のみ SeDebugPrivilege などの特権を持つ
‘ または whoami /groups で BUILTIN\Administrators の存在を確認する
Set exec = shell.Exec(“whoami /groups /fo csv”)
output = exec.StdOut.ReadAll()

‘ 出力の中に “S-1-5-32-544” (AdministratorsグループのWell-Known SID) が含まれているかで判定
If InStr(output, “S-1-5-32-544”) > 0 Then
CheckTokenMembership = True
Else
CheckTokenMembership = False
End If
End Function

‘ ——————————————————————————
‘ 補助関数 : GetCurrentProcessID
‘ 概要 : WMIを活用して現在のWScript/CScriptホストのプロセスIDを取得
‘ ——————————————————————————
Function GetCurrentProcessID()
Dim objWMIService, colProcesses, objProcess
Dim currentPID

currentPID = 0
Set objWMIService = GetObject(“winmgmts:\\.\root\cimv2”)

‘ 実行中のWScript/CScriptインスタンスから、自スクリプト名を含むプロセスを探す
Dim query
query = “SELECT FROM Win32_Process WHERE Name = ‘cscript.exe’ OR Name = ‘wscript.exe'”
Set colProcesses = objWMIService.ExecQuery(query)

For Each objProcess in colProcesses
If InStr(1, objProcess.CommandLine, WScript.ScriptName, vbTextCompare) > 0 Then
currentPID = objProcess.ProcessId
Exit For
End If
Next

GetCurrentProcessID = currentPID
End Function

‘ ——————————————————————————
‘ サブルーチン : ElevateAndRestart
‘ 概要 : Shell.Applicationの “runas” 動詞を使い、管理者権限で自分自身を再起動
‘ ——————————————————————————
Sub ElevateAndRestart()
Dim objShellApp, strPath, strArgs

‘ 実行中のエンジン(cscript または wscript)を判定して引き継ぐ
Dim hostEngine
If LCase(Right(WScript.FullName, 11)) = “cscript.exe” Then
hostEngine = “cscript.exe”
Else
hostEngine = “wscript.exe”
End If

Set objShellApp = CreateObject(“Shell.Application”)

strPath = WScript.ScriptFullName
strArgs = “” ‘ 必要に応じて引数がある場合はここに付与

‘ ShellExecuteEx を用いて “runas”(管理者として実行)で起動
‘ 第4引数に空文字列または “” を渡すとカレントディレクトリ、第5引数 ‘1’ はウインドウ表示
objShellApp.ShellExecute hostEngine, “””” & strPath & “”” ” & strArgs, “”, “runas”, 1

‘ 現在のプロセスは強制終了
WScript.Quit
End Sub

4. チーフアーキテクトからの実務アドバイス:実装上の急所

1. 無限ループの防止策
万が一、管理者権限昇格ダイアログ(UAC)でユーザーが「いいえ」を押したり、そもそもユーザーアカウントに管理者権限がない場合、上記のスクリプトは昇格を試みた後に再び通常の権限で起動し、無限ループに陥る危険性がある。本番環境に展開する際は、コマンドライン引数に `/elevated` などのフラグを付与し、「再起動されたプロセスであるか」を判定するガード句を一枚噛ませるのが、プロのエンジニアの作法である。
2. CScript と WScript のエンジン差異への配慮
自動化スクリプトは基本的に `cscript.exe` でバッチ実行されることを想定すべきだ。`ElevateAndRestart` 内でホストエンジンを動的に判定・継承しているのは、GUI版(wscript.exe)で起動されたスクリプトが昇格時にCUI版へ化けてしまい、標準出力の挙動が変わるのを防ぐための極めて重要な配慮である。
3. セキュリティ監査への対応
`whoami /groups` や WMIクエリの乱用は、過剰なセキュリティソフト(EDR等)に「不審なプロセス探索(reconnaissance)」として検知されるリスクがごく稀にある。しかし、システム管理自動化ツールにおいて、自プロセスの権限確認は正当なプロセス行動であるため、社内ニッチツールとして展開する際はあらかじめセキュリティ部門とホワイトリストの合意を取っておくこと。

総括

VBScriptはレガシーな言語と評されがちだが、OSの深部(WMIやCOMオブジェクト)を直接叩けるその圧倒的な機動力は、現代のWindows環境においても業務自動化の強力な武器たり得る。
「権限エラーで止まるスクリプト」から「自ら環境を整えて完遂するスクリプト」へ――。このコードをあなたのツールチェインに組み込み、真の「ノンストップ運用」を達成してほしい。

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