<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>UAC on 卡螺絲</title><link>https://caloskao.org/tags/uac/</link><description>Recent content in UAC on 卡螺絲</description><generator>Hugo -- gohugo.io</generator><language>zh-Hant</language><lastBuildDate>Wed, 06 May 2026 16:35:15 +0800</lastBuildDate><atom:link href="https://caloskao.org/tags/uac/index.xml" rel="self" type="application/rss+xml"/><item><title>Windows Batch 批次檔自動要求系統管理員權限</title><link>https://caloskao.org/windows-batch-run-as-administrator/</link><pubDate>Wed, 06 May 2026 00:00:00 +0800</pubDate><guid>https://caloskao.org/windows-batch-run-as-administrator/</guid><description>&lt;p&gt;有些批次檔需要管理員權限才能正常執行，例如修改系統設定、操作受保護的資料夾、或是安裝服務。&lt;/p&gt;
&lt;p&gt;相較於要求使用者以滑鼠右鍵「以系統管理員身份執行」，比較合理的做法是讓批次檔自己偵測權限，不足就直接觸發 UAC 提示重新啟動，因為最常發生的狀況就是直接啟動了腳本就被提示權限不足，使用體驗大打折扣。&lt;/p&gt;
&lt;h2 id="做法"&gt;做法
&lt;/h2&gt;&lt;p&gt;把以下程式碼貼在批次檔的最前面，Your codes 之後再接原本的邏輯：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bat" data-lang="bat"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;: BatchGotAdmin (Run as Admin code starts)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;REM --&amp;gt; Check for permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;nul &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%SYSTEMROOT%&lt;/span&gt;&lt;span class="s2"&gt;\system32\cacls.exe&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%SYSTEMROOT%&lt;/span&gt;&lt;span class="s2"&gt;\system32\config\system&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;REM --&amp;gt; If error flag set, we do not have admin.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &amp;#39;&lt;span class="nv"&gt;%errorlevel%&lt;/span&gt;&amp;#39; &lt;span class="ow"&gt;NEQ&lt;/span&gt; &amp;#39;0&amp;#39; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;echo&lt;/span&gt; Requesting administrative privileges...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="nl"&gt;UACPrompt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="nl"&gt;gotAdmin&lt;/span&gt;&lt;span class="c1"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;UACPrompt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;echo&lt;/span&gt; Set UAC = CreateObject&lt;span class="se"&gt;^(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Shell.Application&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;^)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%temp%&lt;/span&gt;&lt;span class="s2"&gt;\getadmin.vbs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;echo&lt;/span&gt; UAC.ShellExecute &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%~s0&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;runas&amp;#34;&lt;/span&gt;, 1 &lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%temp%&lt;/span&gt;&lt;span class="s2"&gt;\getadmin.vbs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%temp%&lt;/span&gt;&lt;span class="s2"&gt;\getadmin.vbs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;exit&lt;/span&gt; /B
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;gotAdmin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;exist&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%temp%&lt;/span&gt;&lt;span class="s2"&gt;\getadmin.vbs&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%temp%&lt;/span&gt;&lt;span class="s2"&gt;\getadmin.vbs&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;pushd&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%CD%&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CD&lt;/span&gt; /D &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%~dp0&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;: BatchGotAdmin (Run as Admin code ends)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;: Your codes should start from the following line&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="運作原理"&gt;運作原理
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;偵測權限&lt;/strong&gt;：用 &lt;code&gt;cacls.exe&lt;/code&gt; 嘗試讀取 &lt;code&gt;%SYSTEMROOT%\system32\config\system&lt;/code&gt;，這個檔案只有管理員才能存取。如果 &lt;code&gt;errorlevel&lt;/code&gt; 不是 &lt;code&gt;0&lt;/code&gt;，代表目前沒有管理員權限。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;觸發 UAC&lt;/strong&gt;：在 &lt;code&gt;%temp%&lt;/code&gt; 建立一個暫時的 VBScript，內容是呼叫 &lt;code&gt;Shell.Application&lt;/code&gt; 的 &lt;code&gt;ShellExecute&lt;/code&gt; 並指定 &lt;code&gt;runas&lt;/code&gt; 動詞——這就是彈出 UAC 視窗的標準方式。VBScript 執行後，原本的 batch 程序直接 &lt;code&gt;exit /B&lt;/code&gt; 結束，由新的提升後的 process 接手。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;清理並繼續&lt;/strong&gt;：取得權限後，刪除剛才建立的暫時 VBScript，然後 &lt;code&gt;pushd&lt;/code&gt; 確保工作目錄正確，讓後續指令可以用相對路徑正常執行。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="用在-powershell-腳本的啟動器"&gt;用在 PowerShell 腳本的啟動器
&lt;/h2&gt;&lt;p&gt;現在寫自動化腳本大多傾向用 PowerShell，&lt;code&gt;.bat&lt;/code&gt; 檔案很常見的用途是當 &lt;code&gt;.ps1&lt;/code&gt; 的啟動器——由 batch 負責提權、設定執行政策，再呼叫 PowerShell 腳本本體：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bat" data-lang="bat"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;: BatchGotAdmin (略，同上)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;powershell.exe -ExecutionPolicy Bypass -File &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;%~dp0&lt;/span&gt;&lt;span class="s2"&gt;your-script.ps1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;為什麼不直接在 &lt;code&gt;.ps1&lt;/code&gt; 裡觸發 UAC？其實 PowerShell &lt;strong&gt;可以&lt;/strong&gt;自我提權，寫法大概長這樣：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-NOT&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="no"&gt;Security.Principal.WindowsPrincipal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Security.Principal.WindowsIdentity&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;GetCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;IsInRole&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="no"&gt;Security.Principal.WindowsBuiltInRole&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Administrator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;Start-Process&lt;/span&gt; &lt;span class="n"&gt;powershell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;exe&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;-NoProfile -ExecutionPolicy Bypass -File &lt;/span&gt;&lt;span class="se"&gt;`&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$PSCommandPath&lt;/span&gt;&lt;span class="se"&gt;`&amp;#34;&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;-Verb&lt;/span&gt; &lt;span class="n"&gt;RunAs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但問題不在提權本身，主要有兩個獨立的阻礙：&lt;/p&gt;
&lt;h3 id="第一execution-policy主因"&gt;第一：Execution Policy（主因）
&lt;/h3&gt;&lt;p&gt;Windows 客戶端預設的執行政策是 &lt;code&gt;Restricted&lt;/code&gt;，直接禁止所有 &lt;code&gt;.ps1&lt;/code&gt; 執行，不管是雙擊還是在命令列輸入路徑都一樣擋。企業環境還常透過 Group Policy 強制鎖定這個設定。&lt;code&gt;.bat&lt;/code&gt; 啟動器可以在呼叫時帶入 &lt;code&gt;-ExecutionPolicy Bypass&lt;/code&gt; 直接繞過，這是最主要的實際原因。&lt;/p&gt;
&lt;h3 id="第二雙擊不執行獨立的安全設計"&gt;第二：雙擊不執行（獨立的安全設計）
&lt;/h3&gt;&lt;p&gt;即使 Execution Policy 已放寬，&lt;code&gt;.ps1&lt;/code&gt; 雙擊預設也不會執行——Windows 把副檔名關聯設成用 PowerShell ISE（或其他關聯的 editor）開啟，而不是直接跑。Microsoft 文件明確指出這是刻意設計，與 Execution Policy 是兩件獨立的事。&lt;code&gt;.bat&lt;/code&gt; 就沒有這個問題，雙擊直接執行。&lt;/p&gt;
&lt;p&gt;兩個問題疊在一起，讓 &lt;code&gt;.bat&lt;/code&gt; 作啟動器成為最省事的做法。&lt;/p&gt;
&lt;h2 id="注意事項"&gt;注意事項
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;UAC 提示會跳出一個獨立視窗，所以原本的 console 視窗會關掉、再開一個新的。如果有 console 輸出需要保留，注意這個行為。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%~s0&lt;/code&gt; 是批次檔自身的短路徑（8.3 格式），避免路徑含空白時 VBScript 解析出錯。&lt;/li&gt;
&lt;li&gt;Windows 11 / 10 都適用，不需要額外安裝任何工具。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies" target="_blank" rel="noopener"
&gt;about_Execution_Policies - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts" target="_blank" rel="noopener"
&gt;about_Scripts - PowerShell | Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://technet.microsoft.com/en-us/library/bb613481.aspx" target="_blank" rel="noopener"
&gt;Running Scripts | Microsoft TechNet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</description></item></channel></rss>