有一种无需使用外部工具的简单方法 - 它在Windows 7、8、8.1、10 和 11上运行良好,并且也向后兼容(Windows XP 没有任何 UAC,因此不需要提升 -在这种情况下,脚本将继续执行)。
查看这段代码(我的灵感来自 NIronwolf 在线程Batch File - “Access Denied” On Windows 7?中发布的代码? ),但我已经改进了它 - 在我的版本中,没有创建和删除任何目录检查管理员权限):
::::::::::::::::::::::::::::::::::::::::::::
:: 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 会向您询问 3 次管理员用户名和密码 - 现在您在开始时只被询问一次,并且仅在需要时询问您。
如果您的脚本只需要显示一条错误消息并在没有任何管理员权限而不是自动提升的情况下退出,则更简单:您可以通过在脚本开头添加以下内容来实现此目的:
@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)
必须在同一行。它在这里以多行显示,以提高可读性!
在一些机器上,我遇到了问题,这些问题已经在上面的新版本中解决了。一个是由于不同的双引号处理,另一个问题是由于 UAC 在 Windows 7 机器上被禁用(设置为最低级别),因此脚本一次又一次地调用自己。
我现在通过删除路径中的引号并稍后重新添加它们来解决此问题,并且我添加了一个额外的参数,该参数在脚本以提升的权限重新启动时添加。
双引号被以下内容删除(详细信息在这里):
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
然后,您可以使用 访问路径!batchPath!
。它不包含任何双引号,因此"!batchPath!"
稍后在脚本中说是安全的。
线
if '%1'=='ELEV' (shift & goto gotPrivileges)
检查脚本是否已被VBScript脚本调用以提升权限,从而避免无休止的递归。它使用删除参数shift
。
更新:
为了避免在Windows 10.vbs
中注册扩展,我在上面的脚本中替换了该行;还按照 Stephen(单独的答案)和 Tomáš Zato(评论)的建议添加以将脚本目录设置为默认值。
"%temp%\OEgetPrivileges.vbs"
"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
cd /d %~dp0
现在脚本尊重传递给它的命令行参数。感谢 jxmallet、TanisDLJ 和 Peter Mortensen 的观察和启发。
根据 Artjom B. 的提示,我对其进行了分析并替换SHIFT
为SHIFT /1
,它保留了%0
参数的文件名
添加del "%temp%\OEgetPrivileges_%batchName%.vbs"
到:gotPrivileges
清理部分(如mlt建议的那样)。如果您并行运行不同的批次,添加%batchName%
以避免影响。请注意,您需要使用for
才能利用高级字符串函数,例如%%~nk
,它仅提取文件名。
优化脚本结构,改进(添加的变量vbsGetPrivileges
现在随处引用,允许轻松更改文件的路径或名称,只有.vbs
在需要提升批处理时才删除文件)
在某些情况下,提升需要不同的调用语法。如果脚本不起作用,请检查以下参数:
set cmdInvoke=0
set winSysFolder=System32
将第一个参数更改为set cmdInvoke=1
并检查是否已经解决了问题。它将添加cmd.exe
到执行提升的脚本中。
或者尝试将第二个参数更改为winSysFolder=Sysnative
,这在 64 位系统上可能会有所帮助(但在大多数情况下不是必需的)。(ADBailey 已经报道了这一点)。“Sysnative”仅在从 32 位脚本宿主启动 64 位应用程序时需要(例如,Visual Studio 构建过程,或从另一个 32 位应用程序调用脚本)。
为了更清楚地解释参数的解释方式,我现在将其显示为P1=value1 P2=value2 ... P9=value9
. 如果您需要用双引号将路径等参数括起来,这尤其有用,例如"C:\Program Files"
.
如果您想调试 VBS 脚本,您可以将//X
参数添加到 WScript.exe 作为第一个参数,如此处所建议的(它针对 CScript.exe 进行了描述,但也适用于 WScript.exe)。
@MiguelAngelo 提供的错误修复: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="%~0", b="%~dpnx0"
pause
有用的链接: