バッチを自動で管理者権限で実行する方法

バッチを利用していて、
毎回管理者権限で実行させるのが面倒くさいと思ったことはないでしょうか。
本記事ではバッチを通常実行するだけで自動で管理者権限で実行するための方法を記載します。

# バッチのコード
以下コードをバッチの先頭に記載するだけです。
```bat
rem バッチの先頭に記載する
whoami /priv | find "SeDebugPrivilege" > nul
if %errorlevel% neq 0 (
 @powershell start-process %~0 -verb runas
 exit
)
```

:::note info
先頭と書きましたが、通常バッチではコマンドを表示させないために、
先頭に **@&#x200b;echo off** を記載することが殆どだと思いますので、
その際は **@&#x200b;echo off** の後に記載してください。
:::


# 解説

* whoami /priv
このコマンドはセキュリティ特権の一覧を表示しますが、
非管理者権限、管理者権限でそれぞれ実行したときに表示される内容が異なります。

```txt:非管理者権限
PRIVILEGES INFORMATION
----------------------

特権名                        説明                                            状態
============================= =============================================== ====
SeLockMemoryPrivilege         メモリ内のページのロック                        無効
SeShutdownPrivilege           システムのシャットダウン                        無効
SeChangeNotifyPrivilege       走査チェックのバイパス                          有効
SeUndockPrivilege             ドッキング ステーションからコンピューターを削除 無効
SeIncreaseWorkingSetPrivilege プロセス ワーキング セットの増加                無効
SeTimeZonePrivilege           タイム ゾーンの変更                             無効
```

```txt:管理者権限
PRIVILEGES INFORMATION
----------------------

特権名                                    説明                                                   状態
========================================= ====================================================== ====
SeLockMemoryPrivilege                     メモリ内のページのロック                               無効
SeIncreaseQuotaPrivilege                  プロセスのメモリ クォータの増加                        無効
SeSecurityPrivilege                       監査とセキュリティ ログの管理                          無効
SeTakeOwnershipPrivilege                  ファイルとその他のオブジェクトの所有権の取得           無効
SeLoadDriverPrivilege                     デバイス ドライバーのロードとアンロード                無効
SeSystemProfilePrivilege                  システム パフォーマンスのプロファイル                  無効
SeSystemtimePrivilege                     システム時刻の変更                                     無効
SeProfileSingleProcessPrivilege           単一プロセスのプロファイル                             無効
SeIncreaseBasePriorityPrivilege           スケジューリング優先順位の繰り上げ                     無効
SeCreatePagefilePrivilege                 ページ ファイルの作成                                  無効
SeBackupPrivilege                         ファイルとディレクトリのバックアップ                   無効
SeRestorePrivilege                        ファイルとディレクトリの復元                           無効
SeShutdownPrivilege                       システムのシャットダウン                               無効
SeDebugPrivilege                          プログラムのデバッグ                                   無効
SeSystemEnvironmentPrivilege              ファームウェア環境値の修正                             無効
SeChangeNotifyPrivilege                   走査チェックのバイパス                                 有効
SeRemoteShutdownPrivilege                 リモート コンピューターからの強制シャットダウン        無効
SeUndockPrivilege                         ドッキング ステーションからコンピューターを削除        無効
SeManageVolumePrivilege                   ボリュームの保守タスクを実行                           無効
SeImpersonatePrivilege                    認証後にクライアントを偽装                             有効
SeCreateGlobalPrivilege                   グローバル オブジェクトの作成                          有効
SeIncreaseWorkingSetPrivilege             プロセス ワーキング セットの増加                       無効
SeTimeZonePrivilege                       タイム ゾーンの変更                                    無効
SeCreateSymbolicLinkPrivilege             シンボリック リンクの作成                              無効
SeDelegateSessionUserImpersonatePrivilege 同じセッションで別のユーザーの偽装トークンを取得します 無効
```

見てわかるように、管理者権限の方が表示される数が多いことがわかります。
これを利用して、現在バッチが非管理者権限、管理者権限のどちらで動作しているかを調べることができます。


* | find "SeDebugPrivilege" > nul
パイプラインを使って、
find "SeDebugPrivilege"
とすることで、管理者権限にしか表示されない"SeDebugPrivilege"を検索させています。

:::note info
今回は"SeDebugPrivilege"としましたが、他の管理者権限にしかないものであればここはなんでもOKです。
:::

実行結果を表示させないために、> nulでリダイレクトさせています。

* if %errorlevel% neq 0
ヒットした場合は
%errorlevel%
が0になりますので、管理者権限で実行、0以外の場合は非管理者権限で実行ということがわかります。



* @&#x200b;powershell start-process %~0 -verb runas
管理者権限で実行させるコマンドです。

以下で詳しく見ていきます。

* @&#x200b;
画面にpowershell start-process %~0 -verb runasを表示させない
* powershell
powershellを実行する
* start-process
プロセスを実行する
* %~0
バッチで自分自身を示す
* -verb runas
管理者権限で実行する

これにより、
非管理者権限で実行の場合は管理者権限として再度実行することができます。
※当然、非管理者権限ユーザーで実行した場合は、管理者権限のアカウント、パスワードが要求されます。

* exit
これを書くことにより、管理者権限で実行したらそこで終了するようにしています。
exit
が無かったら、管理者権限での実行終了後、非管理者権限でバッチが実行されてしまい、
思わぬ結果になってしまう可能性があります。

これによってバッチを実行するだけで管理者権限で実行できるようになりました。
管理者権限での実行し忘れ等防止に役立つかと思います。


# 追記
管理者権限判定の個所ですが、
[別の判定方法](https://qiita.com/Marukaziler/items/1ee0844f63d6dbd5fc2b)がありました。
こちらを用いると

```bat
net session >NUL 2>nul
if %errorlevel% neq 0 (
 @powershell start-process %~0 -verb runas
 exit
)
```

となります。

:::note info
なんかこっちの方がスッキリしますね。
:::