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

时间:2011-08-12 18:55:13

标签: windows batch-file windows-10 uac elevated-privileges

我希望我的批处理文件只能运行提升。如果没有提升,请为用户提供一个选项,以便将批次重新启动为高架。

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

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

15 个答案:

答案 0 :(得分:32)

正如jcoder和Matt所提到的,PowerShell使其变得简单,甚至可以嵌入到批处理脚本中而无需创建新脚本。

我修改了马特的剧本:

:checkPrivileges 
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges 
) else ( powershell "saps -filepath %0 -verb runas" >nul 2>&1)
exit /b 

不需要:getPrivileges标签。

答案 1 :(得分:27)

我正在使用Matt的优秀答案,但在运行提升的脚本时,我发现Windows 7和Windows 8系统之间存在差异。

在Windows 8上提升脚本后,当前目录将设置为C:\Windows\system32。幸运的是,通过将当前目录更改为当前脚本的路径,可以轻松解决此问题:

cd /d %~dp0

注意:使用cd /d确保驱动器号也已更改。

要对此进行测试,您可以将以下内容复制到脚本中。在任一版本上正常运行以查看相同的结果。以管理员身份运行,并在Windows 8中查看差异:

@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

答案 2 :(得分:24)

我是这样做的:

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默认命令。 如果您需要重新分发批处理文件,那就太棒了。

CD /d %~dp0将当前目录设置为文件的当前目录(如果不是,无论文件所在的驱动器是什么,都可以使用/d选项)。

%~nx0返回带扩展名的当前文件名(如果你不包含扩展名,并且文件夹中有一个同名的exe,它将调用exe)。

这篇帖子上有很多回复,我甚至不知道我的回复是否会被看到。

无论如何,我觉得这比其他答案中提出的其他解决方案更简单,我希望它对某人有所帮助。

答案 3 :(得分:22)

马特有一个很好的答案,但它剥夺了传递给脚本的任何参数。这是我的修改,保持参数。我还整合了Stephen对Windows 8中工作目录问题的修复。

@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...

答案 4 :(得分:19)

您可以让脚本调用自身psexec-h选项来提升。

我不确定你是如何检测它是否已经以高架运行的方式运行......只有在存在拒绝访问错误的情况下才可以重新尝试升级的烫发?

或者,您可以简单地让xcopyreg.exe的命令始终与psexec -h一起运行,但如果最终用户需要输入他们的话,那将会很烦人每次密码(如果在脚本中包含密码,则不安全)......

答案 5 :(得分:17)

如果不是,我使用PowerShell重新启动提升的脚本。将这些行放在脚本的最顶层。

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的回答中复制了'网名'方法。他的答案记录得更好,并有错误信息等。这个有一个优点,PowerShell已经安装并可在Windows 7及更高版本上使用。没有临时的VBScript(* .vbs)文件,您也不必下载工具。

只要未锁定PowerShell执行权限,此方法就可以在没有任何配置或设置的情况下运行。

答案 6 :(得分:13)

对于某些程序,将超级秘密RunAsInvoker环境变量设置为set "__COMPAT_LAYER=RunAsInvoker" start regedit.exe will work。请检查:

require

虽然像这样但没有UAC提示用户将在没有管理员权限的情况下继续。

答案 7 :(得分:5)

我在剧本的开头贴了这个:

:: 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"
:--------------------------------------

答案 8 :(得分:5)

我最近需要一种用户友好的方法,我根据此处和 elsewhere 贡献者的宝贵见解提出了这个方法。只需将此行放在 .bat 脚本的顶部。欢迎反馈。

@pushd %~dp0 & fltmc | find "." && (powershell start '%~f0' ' %*' -verb runas 2>nul && exit /b)

解释:

  • @pushd %~dp0 确保相对于该批处理文件的工作目录一致;支持UNC路径
  • fltmc 一个原生的 Windows 命令,如果不提升运行会输出错误
  • | find "." 使错误更漂亮,并且在提升时不会导致任何输出
  • && ( 如果我们成功遇到错误,因为我们没有提升,请执行此操作...
  • powershell start 调用 PowerShell 并调用 Start-Process cmdlet(start 是别名)
  • '%~f0' 传入此 .bat 文件的完整路径和名称。单引号允许路径/文件名中有空格
  • ' %*' 向此 .bat 文件传递​​任何和所有参数。时髦的引用和转义序列可能不起作用,但简单的引用字符串应该。如果没有参数存在,则需要前导空格以防止破坏事物
  • -verb runas 不要只是开始这个​​过程...以管理员身份运行!
  • 2>nul 如果 UAC 提示被取消/忽略,则丢弃 PowerShell 难看的错误输出。
  • && 如果我们成功使用 PowerShell 调用了我们自己,那么...
    • 注意:如果我们没有获得提升(用户取消 UAC),那么 && 允许 .bat 在没有提升的情况下继续运行,这样任何需要它的命令会失败,但其他人会工作得很好。如果您希望脚本简单地退出而不是在未提升的情况下运行,请将其设为单个 & 符号:&
  • exit /b) 退出初始 .bat 处理,因为我们不再需要它;我们有一个新的提升进程,目前正在运行 .bat。如果 .bat 是从命令行启动的,则添加 /b 允许 cmd.exe 保持打开状态...如果双击 .bat 则无效

答案 9 :(得分:3)

现在是2020年,为什么Windows还没有sudo工具?

因此,我写了gsudo,这是Windows的sudo :它在当前控制台中升高(没有上下文切换到新窗口) ),凭据缓存(减少了UAC弹出窗口),还提升了 PowerShell命令

如果需要,它可以提升需要管理员权限的命令或整个批处理命令。

只需将gsudo放在需要提升的任何内容之前。

提升自身的示例批处理文件:

@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

查看gsudo的运行情况: gsudo demo

安装:

答案 10 :(得分:3)

如果您不需要传递参数,则可以使用紧凑的UAC提示脚本,该脚本只有一行。这样做与最高投票答案中的海拔脚本类似,但不会传递参数,因为没有万无一失的方法可以处理毒药字符的所有可能组合。

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)

将其放置在批处理脚本中@echo off行的下方。

说明

net sess>nul 2>&1部分是检查海拔高度的部分。 net sess只是net session的简写,该命令在脚本没有提升的权限时返回错误代码。我是从this SO answer得到这个想法的。这里的大多数答案使用net file代替,尽管它们的工作原理相同。

然后使用||运算符检查错误级别。如果检查成功,则它将创建并执行WScript,该脚本将重新运行原始批处理文件,但具有较高的权限,然后再将其删除。


WScript文件是快速可靠的最佳方法,尽管它使用的是临时文件。这是其他一些变化及其缺点。

PowerShell

net sess>nul 2>&1||(powershell saps '%0'-Verb RunAs&exit)

优点:

  • 很短。
  • 没有临时文件。

缺点:

  • 慢。 PowerShell的启动速度可能很慢。
  • 当用户拒绝UAC提示时,会显示红色文本。可以将PowerShell命令包装在try..catch中以防止这种情况。

Mshta WSH脚本

net sess>nul 2>&1||(start mshta.exe vbscript:code(close(Execute("CreateObject(""Shell.Application"").ShellExecute""%~0"",,,""RunAs"",1"^)^)^)&exit)

优点:

  • 快。
  • 没有临时文件。

缺点:

  • 不可靠。某些Windows 10计算机会阻止脚本运行,因为Windows Defender会将其拦截为潜在的特洛伊木马。

答案 11 :(得分:0)

尽管它不直接适用于此问题,因为它想为用户提供一些信息,但是当我想运行从任务计划程序提升的.bat文件时,谷歌将我带到了这里。

最简单的方法是创建.bat文件的快捷方式,因为对于快捷方式,您可以直接从高级属性中设置Run as administrator

从任务计划程序运行快捷方式,运行提升的.bat文件。

答案 12 :(得分:0)

使用powershell。

如果cmd文件很长,我将使用第一个文件进行提升,然后调用该文件进行实际工作。

如果脚本是简单命令,则所有内容都可以放在一个cmd文件中。不要忘记在脚本文件中包含路径。

模板:

@echo off
powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c " comands or another script.cmd go here "'"

示例1:

@echo off
powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\BIN\x.ps1"'"

示例2:

@echo off
powershell -Command "Start-Process 'cmd' -Verb RunAs -ArgumentList '/c "c:\bin\myScript.cmd"'"

答案 13 :(得分:0)

尝试一下:

@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

如果您需要有关该批处理文件的信息,请运行HTML / JS / CSS代码段:

document.getElementsByTagName("data")[0].innerHTML="ElevateBatch, version 4, release<br>Required Commands:<ul><li>CLS</li><li>SETLOCAL</li><li>SET</li><li>FOR</li><li>NET</li><li>IF</li><li>ECHO</li><li>GOTO</li><li>EXIT</li><li>DEL</li></ul>It auto-elevates the system and if the user presses No, it just doesn't do anything.<br>This CANNOT be used to create an Elevated Explorer.";
data{font-family:arial;text-decoration:none}
<data></data>

答案 14 :(得分:-3)

以下解决方案干净而且可以正常工作。

  1. https://www.winability.com/download/Elevate.zip

  2. 下载Elevate zip文件
  3. 在zip内部,您应该找到两个文件:Elevate.exe和Elevate64.exe。 (如果需要,后者是本机64位编译,尽管常规的32位版本Elevate.exe在Windows的32位和64位版本上都可以正常工作)

  4. 将文件Elevate.exe复制到Windows可以始终在其中找到的文件夹(例如C:/ Windows)。或者,最好将其复制到计划保留bat文件的文件夹中。

  5. 要在批处理文件中使用它,只需在您要以管理员身份执行的命令前加上elevate命令,如下所示:

 elevate net start service ...