こんにちは!普段の業務の中で「この処理、自動化できたら楽なのに…」と思うことはありませんか?
VBScript(Visual Basic Scripting Edition)は、Windows環境さえあれば特別な準備なしで動く、極めて強力な自動化ツールです。しかし、本格的なシステム設定の変更や、`C:\Program Files` 配下へのファイル出力、レジストリの書き換えなどを行おうとすると、必ず大きな壁にぶつかります。
それが、UAC(ユーザーアカウント制御)による権限の壁です。
普通にダブルクリックして起動したスクリプトは「一般ユーザー権限」で動くため、管理者権限が必要な処理に差し掛かった瞬間にエラーで強制終了してしまいます。
「使う人に『右クリックして管理者として実行してね』と毎回お願いするのはスマートじゃないな…」
そう思ったあなたへ。今回は、スクリプト自身が「自分の権限」を自動で判別し、足りなければ自ら管理者権限への昇格プロンプト(UAC)を呼び出して再起動する、極上の「ブートストラップ(自己昇格)コード」をプレゼントします。
一見難しそうに見えますが、OSの仕組みを紐解きながら一歩ずつ丁寧に解説していきます。「ここをクリアすれば、VBScriptの基本とWindowsの権限モデルはバッチリマスターできますよ!」という心強い道標として、ぜひ最後まで楽しんでいってくださいね。
—
1. なぜ「自動昇格」が必要なのか?(UACの壁)
Windows Vista以降に導入された UAC(User Account Control) は、悪意のあるプログラムが勝手にシステムを破壊しないようにするための重要なセキュリティの盾です。
私たちが管理者アカウントでWindowsにサインインしていても、普段起動するプログラムはすべて「一般ユーザー権限(標準トークン)」という制限された状態で動いています。システムに変更を加えようとした時だけ、「本当に許可しますか?」というあの画面(昇格プロンプト)が出て、一時的に「管理者権限(特権トークン)」に切り替わる仕組みです。
VBScriptをダブルクリックしたときも、標準では「一般ユーザー権限」で起動します。
そのため、管理者権限が必要な処理を行うには、スクリプト自身が「今の私はどっちの権限で動いている?」「足りないなら、昇格してやり直そう!」と自律的に判断する仕組み(ブートストラップ)が必要不可欠なのです。
—
2. 権限昇格を実現する「2大COMオブジェクト」の正体
VBScriptでシステムを操作するとき、よく使われるオブジェクトが2つあります。ここを正しく理解することが、脱・初心者への第一歩です。
① `WScript.Shell` オブジェクト
主にプログラムの起動(`Run` メソッド)や、キー入力の送信、環境変数の取得などに使います。非常に便利ですが、このオブジェクトからは「管理者権限で実行する(RunAs)」という命令を下すことができません。
② `Shell.Application` オブジェクト
Windowsのシェル(エクスプローラーやデスクトップなどの基盤)を操作するためのオブジェクトです。このオブジェクトが持つ `ShellExecute` メソッドこそが、「管理者として実行(runas)」という魔法の呪文を解き放つ唯一の手段になります。
今回は、この2つのオブジェクトを適材適所で組み合わせることで、エレガントな自動昇格を実現します。
—
3. 【コピペOK】極限の自動昇格ブートストラップ・テンプレート
まずは、あなたのスクリプトの「先頭」にそのまま貼り付けるだけで使える、極めて堅牢で実用的なテンプレートコードを紹介します。
実務でそのまま使えるよう、「引数の引き継ぎ」や「カレントディレクトリの自動修復」といった、プロの現場で必須となるエラー回避ロジックをすべて組み込んであります。
‘ ==============================================================================
‘ UAC自動昇格ブートストラップ・テンプレート
‘ ※このスクリプトは、一般権限で起動された場合に自動的に管理者権限へ昇格します。
‘ ==============================================================================
Option Explicit
‘ 1. 権限チェックと自動昇格の実行
AdjustPrivilege()
‘ ==============================================================================
‘ 【メイン処理】ここから下に、管理者権限で行いたい処理を記述します
‘ ==============================================================================
Dim wshShell
Set wshShell = CreateObject(“WScript.Shell”)
‘ 動作確認用のメッセージ(管理者権限で動いていることを証明します)
MsgBox “おめでとうございます!” & vbCrLf & _
“現在のスクリプトは【管理者権限】で実行されています。” & vbCrLf & vbCrLf & _
“現在の作業フォルダ: ” & wshShell.CurrentDirectory, _
vbInformation + vbOKOnly, “権限昇格 成功”
‘ (例)管理者権限がないと書き込めない領域にテストファイルを書き出してみる
Dim fso, testFile
Set fso = CreateObject(“Scripting.FileSystemObject”)
On Error Resume Next
Set testFile = fso.CreateTextFile(“C:\Windows\System32\uac_test_success.txt”, True)
If Err.Number = 0 Then
testFile.WriteLine “管理者権限での書き込みに成功しました。作成日時: ” & Now()
testFile.Close
fso.DeleteFile “C:\Windows\System32\uac_test_success.txt”
MsgBox “System32フォルダへの書き込みテストに成功しました!”, vbInformation, “検証完了”
Else
MsgBox “書き込みに失敗しました。エラー: ” & Err.Description, vbCritical, “検証失敗”
End If
On Error GoTo 0
‘ ==============================================================================
‘ 【サブルーチン・関数群】(処理の心臓部)
‘ ==============================================================================
Sub AdjustPrivilege()
‘ 現在の実行権限が「管理者」かどうかを判定します
If IsAdmin() Then
‘ すでに管理者権限であれば、UAC昇格後のカレントディレクトリの歪みを補正して処理を続行
RestoreCurrentDirectory()
Exit Sub
End If
‘ — これ以降は、一般ユーザー権限で起動された場合の「昇格・再実行」処理 —
Dim shellApp, args, arg, argsString
Set shellApp = CreateObject(“Shell.Application”)
‘ 起動時に渡された引数を正しく再構築する(スペースが含まれる引数にも対応)
argsString = “”
For Each arg In WScript.Arguments
‘ 引数にスペースが含まれる場合は、ダブルクォーテーションで囲み直す
If InStr(arg, ” “) > 0 Then
argsString = argsString & ” “”” & arg & “”””
Else
argsString = argsString & ” ” & arg
End If
Next
‘ 自身(VBScript)を「runas(管理者として実行)」の動詞を添えて再起動
‘ 引数1: 起動する実行ファイル(wscript.exe または cscript.exe)
‘ 引数2: 渡すパラメータ(自身のスクリプトフルパス + 引き継ぐ引数)
‘ 引数3: 作業ディレクトリ(空でOK)
‘ 引数4: 動詞(”runas” を指定することでUACプロンプトをトリガーします)
‘ 引数5: ウィンドウの表示状態(1 = 通常表示)
On Error Resume Next
shellApp.ShellExecute WScript.FullName, “””” & WScript.ScriptFullName & “””” & argsString, “”, “runas”, 1
‘ UACで「いいえ」を押された、またはエラーが発生した場合のハンドリング
If Err.Number <> 0 Then
MsgBox “管理者権限への昇格が拒否されました。プログラムを終了します。” & vbCrLf & _
“エラー内容: ” & Err.Description, vbExclamation, “警告”
WScript.Quit
End If
On Error GoTo 0
‘ 昇格後の「子プロセス」に処理を託したため、現在の「親プロセス(一般権限)」は静かに終了します
WScript.Quit
End Sub
‘ ——————————————————————————
‘ 関数: IsAdmin
‘ 目的: 現在のプロセスが管理者権限(昇格済み)で動作しているかを判定する
‘ 原理: 一般ユーザーではアクセスできないレジストリ領域の読み込み成否で超高速判定
‘ ——————————————————————————
Function IsAdmin()
Dim wshShell, regValue
Set wshShell = CreateObject(“WScript.Shell”)
On Error Resume Next
‘ 「HKU\S-1-5-19」(LocalServiceアカウントのハイブ)は管理者権限がないと読み書きできません
wshShell.RegRead “HKEY_USERS\S-1-5-19\Environment\TEMP”
If Err.Number = 0 Then
IsAdmin = True
Else
IsAdmin = False
End If
On Error GoTo 0
End Function
‘ ——————————————————————————
‘ サブルーチン: RestoreCurrentDirectory
‘ 目的: UAC昇格によって「C:\Windows\System32」に強制変更された作業フォルダを、
‘ スクリプト自身の保存場所へと正常に復元する
‘ ——————————————————————————
Sub RestoreCurrentDirectory()
Dim fso, wshShell, scriptFolder
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set wshShell = CreateObject(“WScript.Shell”)
‘ スクリプト自身の親フォルダのパスを取得
scriptFolder = fso.GetParentFolderName(WScript.ScriptFullName)
‘ 作業フォルダを元に戻す
wshShell.CurrentDirectory = scriptFolder
End Sub
—
4. コードの徹底解剖!先輩エンジニアのワンポイント解説
このコードには、ただ「動く」だけではなく、実務の運用に耐えうるための「3つの高度な工夫」が施されています。一つずつ噛み砕いて見ていきましょう。
① 超高速・超軽量な「権限判定」の裏技 (`IsAdmin`関数)
よくあるサンプルコードでは、現在管理者かどうかを調べるために `whoami` という外部コマンドを呼び出したり、WMI(Windows Management Instrumentation)という重いサービスに問い合わせたりしています。
しかし、これらはプロセスの生成コストが高く、スクリプトの起動が一瞬もたつきます。
そこでこのコードでは、「管理者しか触れないレジストリ領域(`HKEY_USERS\S-1-5-19`)を試しに1行だけ読み込んでみる」というアプローチを取っています。
OSのAPIレベルで瞬時に判定が終わるため、CPUに優しく、ミリ秒単位で処理が完了するプロの極意です。
② 無限ループを防ぐ「プロセスのバトンタッチ」
自動昇格のロジックで最も恐ろしいのは、「管理者権限への昇格に失敗したのに、何度も昇格プロンプトを出し続けてしまう無限ループ」です。
shellApp.ShellExecute WScript.FullName, … , “runas”, 1
WScript.Quit ‘ ← ここが超重要!
このコードでは、`ShellExecute` で管理者権限の「新しい自分(子プロセス)」を起動した直後、元の「一般ユーザー権限の自分(親プロセス)」を `WScript.Quit` で即座に完全消滅させています。これにより、メモリ上に不要なプロセスが残ることもなく、綺麗にバトンタッチが行われます。
③ UAC昇格の罠「作業フォルダがSystem32に化ける問題」の克服
実務で最も多くのエンジニアが頭を抱えるのが、「昇格した瞬間、スクリプトの置いてあるフォルダではなく `C:\Windows\System32` がカレントディレクトリ(作業フォルダ)になってしまう」というWindowsの仕様(罠)です。
これに気づかないと、スクリプトと同じフォルダにあるファイルを「相対パス」で読み書きしようとした際、ファイルが見つからずにエラーで自滅してしまいます。
このコードでは、昇格後にすかさず `RestoreCurrentDirectory` サブルーチンを呼び出し、「私の居場所はここじゃない、元のフォルダに戻るよ」と作業フォルダを強制的に修復しています。地味ですが、現場でバグを出さないための極めて重要な防衛策です。
—
5. 陥りやすいエラーとトラブルシューティング
実際にこのコードを使って開発を進める中で、もし動かない場合は以下のポイントをチェックしてみてくださいね。
Q1. UACのプロンプトで「いいえ」を選んだらどうなる?
A1. 安全に終了します。
コード内の `On Error Resume Next` から始まるエラーハンドリング部分が、ユーザーの「キャンセル」を検知し、おかしなエラーを出すことなく「管理者権限への昇格が拒否されました」と親切なメッセージを出して終了するよう設計されています。
Q2. 引数(パラメータ)を渡して起動したのに、昇格後に消えてしまう
A2. `argsString` の再構築処理がその問題を完全に解決しています。
VBScriptは、再起動(昇格)する際に引数を自動で引き継いでくれません。そのため、コード内の `For Each arg In WScript.Arguments` の部分で、バラバラになった引数を一つの文字列に繋ぎ直し、スペースが含まれる場合はダブルクォーテーションで囲み直す(エスケープ処理)という丁寧な処理を行っています。
—
まとめ:この知識を手に入れたあなたへ
お疲れ様でした!
今回ご紹介したブートストラップコードは、VBScriptにおけるひとつの「到達点」とも言える、非常に高度なWindows OSとの対話ロジックです。
このコードの意味を理解し、使いこなせるようになったあなたは、単に「マクロの記録」を使うだけの段階を完全に脱却し、「Windowsのシステム仕様を理解して、安全かつ確実に自動化を設計できるITエンジニア」への大きな一歩を踏み出しました。
このテンプレートをベースに、普段の面倒なファイル整理やシステム設定、ネットワークの設定変更などをどんどん自動化してみてください。あなたの頼もしい相棒として、このスクリプトが活躍してくれることを願っています。
「ここをもっと詳しく知りたい!」「この処理と組み合わせるにはどうすればいい?」といった疑問があれば、いつでも聞いてくださいね。一歩ずつ、一緒にマスターしていきましょう!
