我的電腦有個第三方常駐程式存在 Bug,Windows 睡眠喚醒後偶爾會失常,常駐程式沒提供關閉選單,只能用工作管理員砍掉再重啟。大家都知道我很受不了重複滑滑鼠敲鍵盤,每次遇到都千方百計想把它自動化。於是我寫了一個只有兩行的小批次檔 (.bat) 放在桌面,取代「開工作管理員選程式、按 DEL 或用選單刪除、重跑程式」的一長串動作:

taskkill /im some_agent.exe /f
%appdata%\..\Local\SomeService\some_agent.exe

如此,每次常駐程式當掉,我只要在桌面點兩下就能重啟桯式。

但後來遇到一個狀況,taskkill 砍 some_agent.exe 時有時會遇到存取被拒,必須改用管理者權限執行。

從點兩下變成按滑鼠右鍵、移動游標、點選單,基本上沒增加太多負擔,但我就是不爽(謎:到底是多沒耐性啦),想找出強制用管理者權限啟動批次檔或命令列工具的方法。

我知道 EXE 程式可以透過 Manifest 註記 <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> 強制用管理者權限開啟,但這招對 .bat 或現成 .exe 無效。

研究了一下,要強制以管理者權限執行命令列程式大多得依賴第三方軟體,不下載軟體用 Windows 內建功能的選擇只有 PowerShell Start-Process 指令

Start-Process 有個 -Verb 參數,傳入 -Verb RunAs 即可指定 Windows 使用管理者權限執行,故只要將 taskkill 改用 PowerShell Start-Process -Verb RunAs 執行,就不需要右鍵選單也能自動切換到管理者權限。

實測遇到另一個問題:原本批次檔的邏輯是砍掉舊常駐程式再重新執行常駐程式,但由於 Start-Process 預設為非同步,啟動 taskkill.exe 等待 UAC 同意權限的同時,第二行已啟動另一份 some_agent.exe,之後 taskkill.exe 執行會把新舊 some_agent.exe 通通砍掉。要解決這個問題不難,Start-Process 有個 -Wait 參數,可改為同步執行,等待程序結束後再繼續下一行。

這是我最終的修改版本:

powershell -Command "Start-Process -FilePath 'taskkill.exe' -ArgumentList '/im some_agent.exe /f' -Verb RunAs -Wait"
%appdata%\..\Local\SomeService\some_agent.exe

就醬,我把「滑鼠右鍵、移動游標、點選」再度簡化為「點兩下」,還學到 PowerShell Start-Process 的進階應用,開心。

2021-12-29 補充

  • 經大家提醒,發現我漏提了 RunAs。最開始就是想用 RunAs,但它需要輸入要切換身分的密碼,操作更複雜。如果你的目的是換不同帳號執行,RunAs 就非常合適。
  • 感謝讀者 黃君傑、Ike Wang 分享一招不用寫程式的捷徑做法 - 為 .bat 建立捷徑,由於捷徑可指定「以管理者身分執行」,使用時改點捷徑即可。

Tips of using PowerShell Start-Process to forcely lanuch .bat or .exe as adminstrator.


Comments

# by Eddie

可以請問黑大 你有開UAC嗎?

# by Anderson

一般command line也有一個 C:\Windows\System32\runas.exe 不知道合不合用

# by Cheng

runas 可以用 /savecred

# by Jeffrey

to Cheng, 我以為 /savecred 是第一次輸入密碼時記錄下來,同帳號以後免輸入,是否我認知有誤?

# by wtf

剛查到,在批次檔最前面加上" %1 Mshta vbscript:CreateObject("Shell.Application").ShellExecute("Cmd.exe","/C ""%~0"" ::","","runas",1)(window.close)&&exit " 後面接內容就能直接取得管理者權限,繼續執行

Post a comment