概要
Powershellあるあるですが、「管理者として実行」するのが手間なので、スクリプト側で勝手に管理者起動しちゃうようにしました。
(確認ダイアログは出ます)
本文
1. コード
# 管理者権限でない場合、現在のスクリプトを管理者権限で実行して自分は終了
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
$commandPath = $PSCommandPath
echo ("not admin. restart as admin:" + $commandPath)
# 引数を、管理者権限実行用に作り直す
# 引数が、クォートされた空白を含む文字列である場合を想定。
# そこまで考えないでいいなら、Start-Process の $argsToAdminProcess の代わりに$Argsを入れても問題ない。
$argsToAdminProcess = ""
$Args.ForEach{
echo ("not admin: args: " + $PSItem)
$argsToAdminProcess += " `"$PSItem`""
}
# 実行
Start-Process powershell.exe "-File `"$commandPath`" $argsToAdminProcess" -Verb RunAs
# デバッグ用に、閉じる前に止める。
Pause
exit
}
echo "admin."
# 管理権限実行に渡ってきた引数を確認する
$Args.ForEach{
echo ("admin: args: " + $PSItem)
}
# デバッグ用に、閉じる前に止める。
Pause
2. コマンドと実行結果
PS C:\dev\src\tmp> .\main.ps1 aaa "bbb ccc" ddd
not admin. restart as admin:C:\dev\src\tmp\main.ps1
not admin: args: aaa
not admin: args: bbb ccc
not admin: args: ddd
続行するには、Enter キーを押してください...:
admin.
admin: args: aaa
admin: args: bbb ccc
admin: args: ddd
続行するには、Enter キーを押してください...:
$Args.ForEach{...
で引数を組みなおさなかった場合、引数は aaa
bbb
ccc
ddd
の4つになります。
3. はまったところ
# 実行
Start-Process powershell.exe "-File `"$commandPath`" $argsToAdminProcess" -Verb RunAs
Start-Processの引数
と powershell.exeの引数
が混ざってると気づくまでは意味が分からなかったです。
Start-Processの引数
は powersshell.exe
と -Verb RunAs
、
powershell.exeの引数
は "-File `"$commandPath`" $argsToAdminProcess"
です。
そしてここがだめだと、Start-Processで起動したウィンドウが即消滅するので、何が悪いのか手がかりがつかめず辛かった。。。
おかげで [Security.Principal.WindowsPrincipal]
[Security.Principal.WindowsIdentity]
の中身とかまでのぞき込むはめになったものの収穫なしという。
4. 短くした版
デバッグ用のechoとか削った版です。
コメント入れて8行なので、管理権限が必要なスクリプトの頭に一律コピーしても、そんな邪魔でもないんじゃないかなと思います。
# 管理者権限でない場合、現在のスクリプトを管理者権限で実行して自分は終了
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
$argsToAdminProcess = ""
$Args.ForEach{ $argsToAdminProcess += " `"$PSItem`"" }
Start-Process powershell.exe "-File `"$PSCommandPath`" $argsToAdminProcess" -Verb RunAs
exit
}
echo "admin."
# 管理権限実行に渡ってきた引数を確認する
$Args.ForEach{
echo ("admin: args: " + $PSItem)
}
参考にさせていただいたページ
Powershellスクリプトを管理者権限で再実行する方法
かなり汎用的に書かれています。
【PowerShell】PowerShellを管理者権限で実行したい!ソースの先頭に埋め込むだけで自動で管理者権限に昇格するスクリプト! - これくとろぐ
ワンライナーで書かれてます。引数は考慮されてませんが、引数文字列内の空白考慮なしでいいなら、$Argsを忍び込ませればいけます。
あとがきという落ち
引数を反映させようとしてがんばったわけですが、引数を使う時点で高確率でpowershellを起動させているので、引数対応の必要性は低い気がしました
ouch...