How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
我希望批处理文件只在提升后运行。如果没有提升,请为用户提供一个选项,以提升方式重新启动批处理。
我正在编写一个批处理文件来设置一个系统变量,将两个文件复制到一个程序文件位置,然后启动一个驱动程序安装程序。如果Windows 7/Windows Vista用户(启用UAC,即使他们是本地管理员)在没有右键单击并选择"以管理员身份运行"的情况下运行它,他们将获得"拒绝访问"复制两个文件并写入系统变量。
如果用户实际上是管理员,我希望使用命令自动重新启动批处理。否则,如果他们不是管理员,我想告诉他们需要管理员权限来运行批处理文件。我使用xcopy复制文件,使用reg add编写系统变量。我使用这些命令来处理可能的Windows XP机器。我在这个主题上发现了类似的问题,但是没有涉及到将批处理文件重新启动为提升的问题。
有一种简单的方法,无需使用外部工具-它与Windows 7、8、8.1和10一起运行良好,并且向后兼容(Windows XP没有任何UAC,因此不需要提升-在这种情况下,脚本只需继续运行)。好的。
查看此代码(我是受到Nironwolf在线程批处理文件中发布的代码的启发,在Windows7上"拒绝访问"?,但我已经改进了它-在我的版本中,没有创建和删除任何目录来检查管理员权限):好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | :::::::::::::::::::::::::::::::::::::::::::: :: Elevate.cmd - Version 4 :: Automatically check & get admin rights :: see"https://stackoverflow.com/a/12264592/1016343" for description :::::::::::::::::::::::::::::::::::::::::::: @echo off CLS ECHO. ECHO ============================= ECHO Running Admin shell ECHO ============================= :init setlocal DisableDelayedExpansion set cmdInvoke=1 set winSysFolder=System32 set"batchPath=%~0" for %%k in (%0) do set batchName=%%~nk set"vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs" setlocal EnableDelayedExpansion :checkPrivileges NET FILE 1>NUL 2>NUL if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges ) :getPrivileges if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges) ECHO. ECHO ************************************** ECHO Invoking UAC for Privilege Escalation ECHO ************************************** ECHO Set UAC = CreateObject^("Shell.Application"^) >"%vbsGetPrivileges%" ECHO args ="ELEV">>"%vbsGetPrivileges%" ECHO For Each strArg in WScript.Arguments >>"%vbsGetPrivileges%" ECHO args = args ^& strArg ^&"" >>"%vbsGetPrivileges%" ECHO Next >>"%vbsGetPrivileges%" if '%cmdInvoke%'=='1' goto InvokeCmd ECHO UAC.ShellExecute"!batchPath!", args,"","runas", 1 >>"%vbsGetPrivileges%" goto ExecElevation :InvokeCmd ECHO args ="/c""" +"!batchPath!" +"""" + args >>"%vbsGetPrivileges%" ECHO UAC.ShellExecute"%SystemRoot%\%winSysFolder%\cmd.exe", args,"","runas", 1 >>"%vbsGetPrivileges%" :ExecElevation "%SystemRoot%\%winSysFolder%\WScript.exe""%vbsGetPrivileges%" %* exit /B :gotPrivileges setlocal & cd /d %~dp0 if '%1'=='ELEV' (del"%vbsGetPrivileges%" 1>nul 2>nul & shift /1) :::::::::::::::::::::::::::: ::START :::::::::::::::::::::::::::: REM Run shell as admin (example) - put here code as you like ECHO %batchName% Arguments: P1=%1 P2=%2 P3=%3 P4=%4 P5=%5 P6=%6 P7=%7 P8=%8 P9=%9 cmd /k |
该脚本利用了这样一个事实:
我已经用Windows 7、8、8.1、10和Windows XP测试过它——它对所有人都很好。优点是,在开始点之后,您可以放置任何需要系统管理员权限的内容,例如,如果您打算为了调试目的重新安装和重新运行Windows服务(假定mypackage.msi是服务安装程序包):好的。
1 2 3 | msiexec /passive /x mypackage.msi msiexec /passive /i mypackage.msi net start myservice |
如果没有这个提升权限的脚本,UAC将向您询问三次管理员用户和密码—现在开始时只向您询问一次,并且仅在需要时才询问。好的。
如果您的脚本只需要显示一条错误消息,并在没有任何管理员特权而不是自动提升的情况下退出,则更简单:您可以通过在脚本开头添加以下内容来实现此目的:好的。
1 2 3 4 5 | @ECHO OFF & CLS & ECHO. NET FILE 1>NUL 2>NUL & IF ERRORLEVEL 1 (ECHO You must right-click and select & ECHO"RUN AS ADMINISTRATOR" to run this batch. Exiting... & ECHO. & PAUSE & EXIT /D) REM ... proceed here with admin rights ... |
这样,用户必须右键单击并选择"以管理员身份运行"。如果脚本检测到管理员权限,它将在
在一些机器上,我遇到了一些问题,这些问题已经在上面的新版本中解决了。一个是由于不同的双引号处理,另一个问题是由于在Windows 7计算机上禁用了UAC(设置为最低级别),因此脚本会一次又一次地调用自身。好的。
我现在通过去掉路径中的引号并稍后重新添加来解决这个问题,并且添加了一个额外的参数,该参数在脚本以提升的权限重新启动时添加。好的。
双引号由以下内容删除(详细信息如下所示):好的。
1 2 3 | setlocal DisableDelayedExpansion set"batchPath=%~0" setlocal EnableDelayedExpansion |
然后,您可以使用
线好的。字母名称(P)Checks if the script has already been called by the VBSCRT script to promote rights,hence avoiding endless returnions.你用0音标移除了参数好的,好的。(P)Update:好的,好的。
- (P)To avoid having to register the EDOCX1 theographic 1 original extension in windows 10,I have replaced the line
。字母名称按字母顺序排列的字母名称字母名称
In the script above;also added EDOCX1 commercial 4 as suggested by Stephen(separate answer)and by Tom?Zato(comment)to set script directory as default.好的,好的。 - (P)Now the script honor command line parameters being passed to it.Thanks to JXMallet,Tanisdlj and Peter Mortensen for Observations and灵感.好的,好的。
- (P)According to artjom B.'s hint,I analyzed it and have replaced EDOCX1 welcox0 by EDOCX1 proposal 6,which preserves the file name for the EDOCX1 singinal 7 parameter好的,好的。
- (P)Added EDOCX1 8 commercial to the EDOCX1 plus 9 commercial section to clean up(as MLT suggested).Added EDOCX1 English 10 to avoid impact if you run different batches in parallel.Note that you need to use EDOCX1 discuss 11 niplication to be able to take advantage of the advanced string functions,such as EDOCX1 universal 12,which extracts just the filename.好的,好的。
- (P)Optimized script structure,improvements(added variable EDOCX1 penographic 13 nabel)——which is now referenced everyywhere allowing to change the path or name of the file easily,only delete EDOCX1 penographic 1 if batch needed to be elevated好的,好的。
- (P)在一些案件中,一个不同的群体被要求提高地位。If the script does not work,check the following parameters:字母名称字母名称Either change the 1st parameter to EDOCX1 plography 17 common and check if that already fixes the issue.It will add EDOCX1 plograph 18 to the script performing the high.他是耶稣。Or try to change the 2nd parameter to EDOCX1 individual 19,this might help(but is in most cases not required)on 64 bit systems.(Adbailey has reported this.)Sysnative"is only required for launching 64-bit applications from a 32-bit script host(e.g.a visual studio build process,or script invitation from another 32-bit application).好的,好的。
- (P)To make it more clear how the parameters are interpreted,I am displaying it now like EDOCX1 original 20.如果你需要将两个阵营中的类似阵营包围起来,E.G.EDOCX1就特别有用。好的,好的。
(P)用户链接:好的,好的。
- Meaning of special characters in batch file:
quotes(""),bang(?),Caret(,ampersand(&;),other special characters
好吧。
正如jcoder和matt提到的,PowerShell使它变得简单,甚至可以在不创建新脚本的情况下嵌入到批处理脚本中。
我修改了马特的剧本:
1 2 3 4 5 | :checkPrivileges NET FILE 1>NUL 2>NUL if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( powershell"saps -filepath %0 -verb runas">nul 2>&1) exit /b |
不需要使用
我使用的是Matt的最佳答案,但在运行提升的脚本时,我发现我的Windows 7和Windows 8系统之间存在差异。
在Windows 8上提升脚本后,当前目录将设置为
1 | cd /d %~dp0 |
注意:使用
要测试这一点,可以将以下内容复制到脚本中。在任何一个版本上正常运行,以查看相同的结果。以管理员身份运行,并查看Windows 8的不同之处:
1 2 3 4 5 6 | @echo off echo Current path is %cd% echo Changing directory to the path of the current script cd %~dp0 echo Current path is %cd% pause |
我这样做:
1 2 3 4 5 6 7 8 9 10 11 12 | NET SESSION IF %ERRORLEVEL% NEQ 0 GOTO ELEVATE GOTO ADMINTASKS :ELEVATE CD /d %~dp0 MSHTA"javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 1);close();" EXIT :ADMINTASKS (Do whatever you need to do here) EXIT |
这样做很简单,只使用Windows默认命令。如果需要重新分配批处理文件,那就太好了。
这篇文章的回复太多了,我甚至不知道我的回复是否会被看到。
不管怎样,我发现这种方法比其他答案上提出的其他解决方案简单,我希望它能帮助一些人。
马特有一个很好的答案,但是它去掉了传递给脚本的任何参数。这是我的修改,保持论点。我还在Windows8中加入了Stephen对工作目录问题的修复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | @ECHO OFF setlocal EnableDelayedExpansion NET FILE 1>NUL 2>NUL if '%errorlevel%' == '0' ( goto START ) else ( goto getPrivileges ) :getPrivileges if '%1'=='ELEV' ( goto START ) set"batchPath=%~f0" set"batchArgs=ELEV" ::Add quotes to the batch path, if needed set"script=%0" set script=%script:"=% IF '%0'=='!script!' ( GOTO PathQuotesDone ) set"batchPath=""%batchPath%""" :PathQuotesDone ::Add quotes to the arguments, if needed. :ArgLoop IF '%1'=='' ( GOTO EndArgLoop ) else ( GOTO AddArg ) :AddArg set"arg=%1" set arg=%arg:"=% IF '%1'=='!arg!' ( GOTO NoQuotes ) set"batchArgs=%batchArgs%"%1"" GOTO QuotesDone :NoQuotes set"batchArgs=%batchArgs% %1" :QuotesDone shift GOTO ArgLoop :EndArgLoop ::Create and run the vb script to elevate the batch file ECHO Set UAC = CreateObject^("Shell.Application"^) >"%temp%\OEgetPrivileges.vbs" ECHO UAC.ShellExecute"cmd","/c""!batchPath! !batchArgs!""","","runas", 1 >>"%temp%\OEgetPrivileges.vbs" "%temp%\OEgetPrivileges.vbs" exit /B :START ::Remove the elevation tag and set the correct working directory IF '%1'=='ELEV' ( shift /1 ) cd /d %~dp0 ::Do your adminy thing here... |
您可以使用psexec的
我不知道你会如何检测它是否已经以提升的状态运行…可能只有在出现拒绝访问错误时才重新尝试使用提升的烫发?
或者,您可以简单地让
如果没有,我使用PowerShell重新启动提升的脚本。把这些行放在脚本的最上面。
1 2 3 4 | net file 1>nul 2>nul && goto :run || powershell -ex unrestricted -Command"Start-Process -Verb RunAs -FilePath '%comspec%' -ArgumentList '/c %~fnx0 %*'" goto :eof :run :: TODO: Put code here that needs elevation |
我从@matt的答案中复制了"net name"方法。他的答案有更好的文档记录,并有错误消息等。这一功能的优点是,PowerShell已经安装并在Windows 7及更高版本上可用。没有临时vbscript(*.vbs)文件,您不必下载工具。
只要您的PowerShell执行权限未被锁定,此方法应在没有任何配置或设置的情况下工作。
对于某些程序,将超级机密
1 2 | set"__COMPAT_LAYER=RunAsInvoker" start regedit.exe |
尽管如此,不会有UAC提示用户在没有管理权限的情况下继续。
我把这个贴在剧本的开头:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | :: BatchGotAdmin :------------------------------------- REM --> Check for permissions >nul 2>&1"%SYSTEMROOT%\system32\icacls.exe""%SYSTEMROOT%\system32\config\system" REM --> If error flag set, we do not have admin. if '%errorlevel%' NEQ '0' ( echo Requesting administrative privileges... goto UACPrompt ) else ( goto gotAdmin ) :UACPrompt echo Set UAC = CreateObject^("Shell.Application"^) >"%temp%\getadmin.vbs" echo args ="">>"%temp%\getadmin.vbs" echo For Each strArg in WScript.Arguments >>"%temp%\getadmin.vbs" echo args = args ^& strArg ^&"" >>"%temp%\getadmin.vbs" echo Next >>"%temp%\getadmin.vbs" echo UAC.ShellExecute"%~s0", args,"","runas", 1 >>"%temp%\getadmin.vbs" "%temp%\getadmin.vbs" %* exit /B :gotAdmin if exist"%temp%\getadmin.vbs" ( del"%temp%\getadmin.vbs" ) pushd"%CD%" CD /D"%~dp0" :-------------------------------------- |
下面的解决方案是干净的,工作得很好。
从https://www.winability.com/download/elevate.zip下载Elevate zip文件
在zip中,您应该找到两个文件:elevate.exe和elevate64.exe。(后者是本机64位编译,如果需要的话,尽管常规的32位版本elevate.exe在32位和64位版本的Windows中都可以正常工作)
将文件elevate.exe复制到Windows始终可以找到的文件夹中(例如c:/windows)。或者你最好把你的BAT文件放在同一个文件夹里。
要在批处理文件中使用它,只需在要以管理员身份执行的命令前面加上elevate命令,如下所示:
1 elevate net start service ...