UAC自動昇格
システムの設定変更やサービスの操作など、管理者権限が必要な処理をバッチファイルで行おうとしたとき、「アクセスが拒否されました」というエラーに遭遇したことはありませんか?通常はバッチファイルを右クリックして「管理者として実行」を選ぶ必要があります。しかし、ユーザーにその操作を毎回求めるのは手間がかかります。
この記事では、バッチファイル自身が管理者権限で実行されているかどうかを自動的に確認し、権限が不足している場合は UAC(ユーザーアカウント制御)ダイアログを表示して自動的に昇格する方法を解説します。
管理者権限で実行されているか確認する
自動昇格を実装するには、まず「現在のプロセスが管理者権限で動いているか」を判定する必要があります。これには net session コマンドを利用するのが一般的な方法です。
net session は、管理者権限がなければアクセスが拒否されるコマンドです。出力を捨てつつ実行し、ERRORLEVEL で結果を判断します。
net session >nul 2>&1
| 状況 | ERRORLEVEL |
|---|---|
| 管理者権限あり | 0 |
| 管理者権限なし | 0 以外(通常は 2) |
net session >nul 2>&1
if %errorlevel% equ 0 (
echo 管理者権限で実行されています。
) else (
echo 管理者権限がありません。
)
net session はネットワークセッション情報を表示するコマンドですが、管理者権限がないと実行できないという特性を権限チェックに利用しています。シンプルで広く使われている手法です。
net session は Server サービス(LanmanServer)に依存します。このサービスが停止していると、管理者権限があってもエラーになり、権限なしと誤判定されます。その場合は fltmc >nul 2>&1 で代用できます。fltmc も管理者権限がないとエラーになり、Server サービスには依存しません。
PowerShell を使った UAC 自動昇格
管理者権限がないと判定された場合、PowerShell の Start-Process コマンドレットを使ってバッチファイル自身を管理者権限で再起動させます。
基本パターン
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
powershell -Command "Start-Process '%~f0' -Verb RunAs"
exit /b
)
rem ここから管理者権限で実行される処理
cd /d "%~dp0"
echo 管理者権限で実行中です。
pause
各部分の役割を整理します。
| 記述 | 説明 |
|---|---|
net session >nul 2>&1 | 管理者権限の有無を確認する |
if %errorlevel% neq 0 | 権限がない場合に昇格処理を実行 |
Start-Process '%~f0' | このバッチファイル自身をフルパスで起動する |
-Verb RunAs | 管理者として実行(UAC ダイアログを表示) |
exit /b | 元の(権限なし)プロセスを終了する |
cd /d "%~dp0" | カレントディレクトリをバッチファイルの場所に戻す |
%~f0 は「このバッチファイル自身のフルパス」を意味する特殊変数です。バッチファイルが C:\tools\setup.cmd に置かれていれば C:\tools\setup.cmd に展開されます。これにより、ファイルがどこに置かれていても自分自身を正しく再起動できます。
動作フローをまとめます。
net sessionで管理者権限を確認する- 権限がなければ PowerShell 経由で自身を管理者として起動する
- UAC ダイアログが表示され、ユーザーが「はい」を押すと新しいウィンドウが開く
- 元のウィンドウは
exit /bで閉じる - 新しいウィンドウは管理者権限を持つため、以降の処理が実行される
昇格後のプロセスは、元の場所ではなく C:\Windows\System32 をカレントディレクトリとして起動するのが一般的です。バッチファイルと同じフォルダのファイルを相対パスで参照する場合は、昇格後に cd /d "%~dp0" で移動してください(%~dp0 はバッチファイルのあるフォルダです)。
引数を保持して昇格する
バッチファイルに引数を渡して使う場合、そのまま昇格すると引数が失われます。-ArgumentList オプションで元の引数を引き継ぎましょう。
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
powershell -Command "Start-Process '%~f0' -ArgumentList '%*' -Verb RunAs"
exit /b
)
rem 引数を使った処理
cd /d "%~dp0"
echo 管理者権限で実行中です。
echo 引数: %*
pause
%* はバッチファイルに渡されたすべての引数を展開します。たとえば setup.cmd install verbose と実行した場合、%* は install verbose になります。
-ArgumentList '%*' は、引数を入力されたままの 1 つの文字列として渡します。そのため、引数にシングルクォート(')が含まれていると PowerShell 側の構文が壊れます。ダブルクォート(")や & | ^ が含まれる場合は、外側の powershell -Command "..." が cmd の段階で壊れます。%~f0 のパスにこれらが含まれる場合も同様です。また、引数なしで実行すると -ArgumentList が空文字になり、Start-Process がエラーになることがあります。こうした入力を扱う場合は、PowerShell スクリプトへの移行を検討してください。
実践例:サービスの起動タイプを変更する
Windows サービスの設定変更には管理者権限が必要です。自動昇格の仕組みと組み合わせた実践的な例を示します。
@echo off
setlocal
rem UAC 自動昇格チェック
net session >nul 2>&1
if %errorlevel% neq 0 (
echo 管理者権限が必要です。UAC ダイアログを表示します...
timeout /t 2 >nul
powershell -Command "Start-Process '%~f0' -ArgumentList '%*' -Verb RunAs"
exit /b
)
rem ここから管理者権限で実行される処理
cd /d "%~dp0"
set SERVICE_NAME=%1
if "%SERVICE_NAME%"=="" set SERVICE_NAME=wuauserv
echo ================================
echo サービス管理ツール(管理者)
echo ================================
echo 対象サービス: %SERVICE_NAME%
echo.
sc query %SERVICE_NAME% | findstr /i "STATE"
echo.
echo サービスを手動起動に変更します...
sc config %SERVICE_NAME% start= demand
if %errorlevel% equ 0 (
echo 設定を変更しました。
) else (
echo エラーが発生しました。サービス名を確認してください。
)
echo.
pause
endlocal
timeout /t 2 >nul を昇格前に挟むことで、「管理者権限が必要です」というメッセージをユーザーが読む時間を確保できます。UAC ダイアログが突然表示されると驚かれることがあるため、一言添えるのが親切です。
注意点
UAC の昇格ダイアログは必ずユーザーの確認(「はい」ボタンのクリック)が必要です。スクリプトから自動的にダイアログをスキップすることはできません。ユーザーが「いいえ」を押した場合、昇格は行われず処理は終了します。
グループポリシーによって UAC が無効化されていたり、昇格の挙動が制御されていたりする環境では、このスクリプトが意図どおりに動作しないことがあります。また、UAC が無効な環境では、管理者グループのユーザーは常に昇格済みの状態で実行されるため、昇格ダイアログは表示されません(net session も成功します)。
管理者権限で実行されるバッチファイルは、システムの重要な設定やファイルを変更できます。信頼できない配布元から入手したバッチファイルに自動昇格の仕組みが組み込まれている場合は、実行前に内容を十分確認してください。
まとめ
| 項目 | 内容 |
|---|---|
| 管理者権限の確認 | net session >nul 2>&1 |
| 昇格の判定 | if %errorlevel% neq 0 |
| UAC 昇格の実行 | powershell -Command "Start-Process '%~f0' -Verb RunAs" |
| 引数の引き継ぎ | -ArgumentList '%*' を追加する |
| 元プロセスの終了 | exit /b で昇格後に元のウィンドウを閉じる |