Windows 我如何自动提升批处理文件,以便它在需要时请求UAC管理员权限?

Windows 我如何自动提升批处理文件,以便它在需要时请求UAC管理员权限?,windows,batch-file,windows-10,uac,elevated-privileges,Windows,Batch File,Windows 10,Uac,Elevated Privileges,我希望我的批处理文件只运行提升。如果未提升,则为用户提供一个选项,以在提升时重新启动批处理 我正在编写一个批处理文件来设置一个系统变量,将两个文件复制到一个程序文件位置,然后启动一个驱动程序安装程序。如果Windows7/WindowsVista用户(已启用,即使他们是本地管理员)在没有右键单击并选择“以管理员身份运行”的情况下运行它,他们将获得“拒绝访问”的权限,即复制两个文件并写入系统变量 如果用户实际上是管理员,我想使用命令自动重新启动提升的批处理。否则,如果他们不是管理员,我想告诉他们运

我希望我的批处理文件只运行提升。如果未提升,则为用户提供一个选项,以在提升时重新启动批处理

我正在编写一个批处理文件来设置一个系统变量,将两个文件复制到一个程序文件位置,然后启动一个驱动程序安装程序。如果Windows7/WindowsVista用户(已启用,即使他们是本地管理员)在没有右键单击并选择“以管理员身份运行”的情况下运行它,他们将获得“拒绝访问”的权限,即复制两个文件并写入系统变量


如果用户实际上是管理员,我想使用命令自动重新启动提升的批处理。否则,如果他们不是管理员,我想告诉他们运行批处理文件需要管理员权限。我正在使用xcopy复制文件,并使用REG ADD写入系统变量。我正在使用这些命令来处理可能的WindowsXP机器。我在这个主题上发现了类似的问题,但是没有任何问题涉及将批处理文件重新启动为提升状态。

您可以让脚本使用的
-h
选项调用自身以运行提升状态

我不知道你会如何检测到它是否已经被提升了。。。可能只有在出现访问被拒绝错误时才重新尝试提升的烫发


或者,您可以简单地让
xcopy
reg.exe
的命令始终与
psexec-h
一起运行,但如果最终用户每次都需要输入密码,这会让他们感到恼火(如果您在脚本中包含密码,则会使其不安全)…

有一种不需要使用外部工具的简单方法-它可以与Windows7、8、8.1和10运行良好,并且向后兼容(WindowsXP没有任何UAC,因此不需要升级-在这种情况下,脚本只需继续)

请查看此代码(我是受NIronwolf在线程中发布的代码启发的),但我对其进行了改进-在我的版本中,没有创建和删除任何目录来检查管理员权限):

:
::Elevate.cmd-版本4
::自动检查并获取管理员权限
::见“https://stackoverflow.com/a/12264592/1016343“为了描述
::::::::::::::::::::::::::::::::::::::::::::
@回音
CLS
回声。
回音=============================
运行管理shell的ECHO
回音=============================
:init
setlocal DisableDelayedExpansion
设置cmdInvoke=1
设置winSysFolder=System32
设置“batchPath=%~0”
对于(%0)中的%%k,请设置batchName=%%~nk
设置“vbsGetPrivileges=%temp%\OEgetPriv\uu0%batchName%.vbs”
setlocal EnableDelayedExpansion
:检查权限
NET文件1>NUL 2>NUL
如果“%errorlevel%”==“0”(转到转到特权)其他(转到特权)
:getPrivileges
如果“%1”==“ELEV”(回显ELEV&shift/1&goto goto权限)
回声。
回音**************************************
ECHO调用UAC进行权限提升
回音**************************************
ECHO Set UAC=CreateObject^(“Shell.Application”^)>%vbsGetPrivileges%
ECHO args=“ELEV”>>%vbsGetPrivileges%
回送WScript中的每个strArg。参数>>%vbsGetPrivileges%
ECHO args=args^&strArg^&“”>%vbsGetPrivileges%
回显下一步>>%vbsGetPrivileges%
如果“%cmdInvoke%”==“1”转到InvokeCmd
ECHO UAC.ShellExecute“!batchPath!”,args“,“runas”,1>>%vbsGetPrivileges%
转到行政长官
:InvokeCmd
ECHO args=“/c”“”+”!batchPath!”+“”“+args>>”%vbsGetPrivileges%
ECHO UAC.ShellExecute“%SystemRoot%\%winSysFolder%\cmd.exe”,args,“,“runas”,1>>“%vbsGetPrivileges%”
:ExecElevation
%SystemRoot%\%winSysFolder%\WScript.exe“%vbsGetPrivileges%”*
退出/B
:获得特权
设置本地和cd/d%~dp0
如果“%1”==“ELEV”(删除“%vbsGetPrivileges%”1>nul 2>nul&shift/1)
::::::::::::::::::::::::::::
::开始
::::::::::::::::::::::::::::
REM以管理员的身份运行shell(示例)-在这里输入您喜欢的代码
回显%batchName%参数:P1=%1 P2=%2 P3=%3 P4=%4 P5=%5 P6 P7=%7 P8=%8 P9=%9
cmd/k
该脚本利用了
网络文件
需要管理员权限这一事实,如果您没有权限,则返回
errorlevel1
。提升是通过创建一个脚本来实现的,该脚本重新启动批处理文件以获得权限。这会导致Windows显示UAC对话框,并要求您输入管理员帐户和密码

我已经用Windows7、8、8.1、10和WindowsXP对它进行了测试——它对所有人都很好。 优点是,在启动点之后,您可以放置任何需要系统管理员权限的内容,例如,如果您打算重新安装并重新运行Windows服务以进行调试(假定mypackage.msi是服务安装程序包):

msiexec/passive/x mypackage.msi
msiexec/passive/i mypackage.msi
net启动myservice
如果没有这个提升权限的脚本,UAC会向您询问三次管理员用户和密码-现在您在开始时只被询问一次,而且只有在需要时才被询问


如果您的脚本只需要显示一条错误消息,并且在没有任何管理员权限时退出,而不是自动提升,这就更简单了:您可以通过在脚本开头添加以下内容来实现:

@ECHO关闭&CLS&ECHO。
NET FILE 1>NUL 2>NUL&IF ERRORLEVEL 1(ECHO)必须右键单击并选择&
ECHO“以管理员身份运行”以运行此批处理。正在退出…&ECHO&
暂停和退出(D)
雷姆。。。继续这里与管理员权限。。。
这样,用户必须右键单击并选择“以管理员身份运行”
。如果检测到管理员权限,脚本将在
REM
语句之后继续,否则将以错误退出。如果不需要暂停
,只需将其删除即可。 重要提示:cd /d %~dp0
@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
:: 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"
:--------------------------------------
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
@ECHO OFF
setlocal EnableDelayedExpansion

::net file to test privileges, 1>NUL redirects output, 2>NUL redirects errors
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...
set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe
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
 elevate net start service ...
net session >nul 2>nul & net session >nul 2>nul || gsudo "%~f0" && exit /b || exit /b
:: This will run as admin ::
@echo off
  rem Test if current context is already elevated:
  whoami /groups | findstr /b BUILTIN\Administrators | findstr /c:"Enabled group" 1> nul 2>nul && goto :isadministrator
  echo You are not admin. (yet)
  :: Use gsudo to launch this batch file elevated.
  gsudo "%~f0"
  goto end
:isadministrator
  echo You are admin.
  echo (Do admin stuff now).
:end
@echo off
powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c " comands or another script.cmd go here "'"
@echo off
powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\BIN\x.ps1"'"
@echo off
powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c "c:\bin\myScript.cmd"'"
@echo off
CLS
: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 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)
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 sess>nul 2>&1||(echo(CreateObject("Shell.Application"^).ShellExecute"%~0",,,"RunAs",1:CreateObject("Scripting.FileSystemObject"^).DeleteFile(wsh.ScriptFullName^)>"%temp%\%~nx0.vbs"&start wscript.exe "%temp%\%~nx0.vbs"&exit)
net sess>nul 2>&1||(powershell saps '%0'-Verb RunAs&exit)
net sess>nul 2>&1||(start mshta.exe vbscript:code(close(Execute("CreateObject(""Shell.Application"").ShellExecute""%~0"",,,""RunAs"",1"^)^)^)&exit)
@pushd %~dp0 & fltmc | find "." && (powershell start '%~f0' ' %*' -verb runas 2>nul && exit /b)