有一种简单的方法,无需使用外部工具 - 它运行良好Windows 7、8、8.1、10 和 11并且也向后兼容(Windows XP 没有任何 UAC,因此不需要提升 - 在这种情况下,脚本将继续执行)。
Check out this code (I was inspired by the code by NIronwolf posted in the thread Batch File - "Access Denied" On Windows 7? 1), but I've improved it - in my version there isn't any directory created and removed to check for administrator privileges):
::::::::::::::::::::::::::::::::::::::::::::
:: 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=%~dpnx0"
rem this works also from cmd shell, other than %~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
该脚本利用了以下事实:NET FILE
需要管理员权限并返回errorlevel 1
如果你没有它。提升是通过创建一个重新启动批处理文件以获取权限的脚本来实现的。这会导致 Windows 显示 UAC 对话框并要求您输入管理员帐户和密码。
我已经在 Windows 7、8、8.1、10、11 和 Windows XP 上对其进行了测试 - 它对所有系统都适用。
优点是,在启动点之后,您可以放置任何需要系统管理员权限的内容,例如,如果您打算重新安装并重新运行 Windows 服务以进行调试(假设 mypackage.msi 是服务安装程序包) :
msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice
如果没有此权限提升脚本,UAC 会询问您三次管理员用户名和密码 - 现在只在开始时询问一次,并且仅在需要时询问。
如果您的脚本只需要显示错误消息并在没有任何管理员权限的情况下退出代替自动提升,这甚至更简单:您可以通过在脚本开头添加以下内容来实现此目的:
@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 ...
这样,用户必须右键单击并选择“以管理员身份运行”。该脚本将在REM
如果检测到管理员权限则声明,否则退出并出错。如果您不需要PAUSE
,只需将其删除即可。重要的: NET FILE [...] EXIT /D)
必须在同一条线上。为了更好的可读性,它在这里以多行显示!
在某些机器上,我遇到了问题,这些问题已经在上面的新版本中解决了。一个是由于不同的双引号处理,另一个问题是由于 Windows 7 计算机上的 UAC 被禁用(设置为最低级别),因此脚本一次又一次地调用自身。
我现在已经通过删除路径中的引号并稍后重新添加它们来解决此问题,并且我添加了一个额外的参数,该参数是在脚本以提升的权限重新启动时添加的。
双引号被以下删除(详细信息是here):
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
然后您可以使用以下方式访问该路径!batchPath!
。它不包含任何双引号,所以可以肯定地说"!batchPath!"
稍后在脚本中。
The line
if '%1'=='ELEV' (shift & goto gotPrivileges)
检查脚本是否已被调用VBScript脚本来提升权限,从而避免无休止的递归。它使用删除参数shift
.
Update:
-
为了避免必须注册.vbs
延伸于Windows 10,我已经更换了线
"%temp%\OEgetPrivileges.vbs"
by
"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
在上面的脚本中;还添加了cd /d %~dp0
按照 Stephen(单独答案)和 Tomáš Zato(评论)的建议,将脚本目录设置为默认值。
-
现在,该脚本支持传递给它的命令行参数。感谢 jxmallet、TanisDLJ 和 Peter Mortensen 的观察和启发。
-
根据Artjom B.的提示,我分析了它并替换了SHIFT
by SHIFT /1
,它保留了文件名%0
范围
-
Added del "%temp%\OEgetPrivileges_%batchName%.vbs"
to the :gotPrivileges
要清理的部分(如mlt建议)。添加%batchName%
以避免并行运行不同批次时产生影响。请注意,您需要使用for
能够利用高级字符串函数,例如%%~nk
,它仅提取文件名。
-
优化脚本结构,改进(添加变量vbsGetPrivileges
现在到处都可以引用它,可以轻松更改文件的路径或名称,只需删除.vbs
文件(如果需要提升批次)
-
在某些情况下,提升需要不同的调用语法。如果脚本不起作用,请检查以下参数:
set cmdInvoke=0
set winSysFolder=System32
将第一个参数更改为set cmdInvoke=1
并检查是否已经解决了问题。它将添加cmd.exe
到执行提升的脚本。
或者尝试将第二个参数更改为winSysFolder=Sysnative
,这可能对 64 位系统有帮助(但在大多数情况下不是必需的)。 (ADBailey 已对此进行了报道)。仅当从 32 位脚本主机启动 64 位应用程序时才需要“Sysnative”(例如 Visual Studio 构建过程或从另一个 32 位应用程序调用脚本)。
-
为了更清楚如何解释参数,我现在将其显示为P1=value1 P2=value2 ... P9=value9
。如果您需要将路径等参数括在双引号中,例如"C:\Program Files"
.
-
如果要调试VBS脚本,可以添加//X
按照建议,将 WScript.exe 参数作为第一个参数here(它是针对 CScript.exe 进行描述的,但也适用于 WScript.exe)。
-
错误修正由提供米格尔·安吉洛:batchPath 现在可以在 cmd shell 上正确返回。这个小脚本test.cmd
显示了差异,对于那些对细节感兴趣的人(在 cmd.exe 中运行它,然后通过 Windows 资源管理器双击运行它):
@echo off
setlocal
set a="%~0"
set b="%~dpnx0"
if %a% EQU %b% echo running shell execute
if not %a% EQU %b% echo running cmd shell
echo a=%a%, b=%b%
pause
有用的链接:
- 批处理文件中特殊字符的含义:
引号 (”), Bang (!), 插入符号 (^), , 其他特殊字符
1) Note that this link no longer exists, it is now showing a 404 error.