有一种简便的方法无需使用外部工具-它在Windows 7、8、8.1和10上运行良好,并且也向后兼容(Windows XP没有任何UAC,因此不需要提升-在这种情况下,如果脚本只是继续执行)。
签出此代码(我受NIronwolf的代码启发,该代码发布在线程“ 批处理文件”中-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=%~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和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(将其设置为最低级别),因此脚本会一次又一次地调用自身。
我现在通过删除路径中的引号并在以后重新添加引号来解决此问题,并且添加了一个额外的参数,该脚本在脚本以提升的权限重新启动时会添加。
双引号将被以下内容删除(详细信息在此处):
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
然后,您可以使用来访问路径!batchPath!
。它不包含任何双引号,因此可以"!batchPath!"
在脚本的稍后部分安全地声明。
线
if '%1'=='ELEV' (shift & goto gotPrivileges)
检查该脚本是否已经被VBScript脚本调用以提升权限,从而避免了无限递归。使用删除参数shift
。
更新:
为了避免.vbs
在Windows 10中注册扩展名,我在上面的脚本
"%temp%\OEgetPrivileges.vbs"
中用替换了该行
"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
;还cd /d %~dp0
由Stephen(单独回答)和TomášZato(评论)建议添加,以将脚本目录设置为默认目录。
现在,该脚本支持传递给它的命令行参数。感谢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
将1st参数更改为,set cmdInvoke=1
然后检查是否已解决问题。它将添加cmd.exe
到执行高程的脚本中。
或者尝试将2nd参数更改为winSysFolder=Sysnative
,这在64位系统上可能会有所帮助(但在大多数情况下不是必需的)。(ADBailey对此进行了报道)。仅从32位脚本主机启动64位应用程序时才需要“系统”(例如,Visual Studio生成过程或从另一个32位应用程序中调用脚本)。
为了更清楚地说明参数的解释方式,我现在将其显示为P1=value1 P2=value2 ... P9=value9
。如果您需要将诸如路径之类的参数括在双引号中(例如),此功能特别有用"C:\Program Files"
。
如果要调试VBS脚本,可以//X
按照此处的建议将参数作为第一个参数添加到WScript.exe (针对CScript.exe进行了描述,但也适用于WScript.exe)。
有用的链接: