我希望我的批处理文件只运行提升。如果没有提升,为用户提供一个选项,以提升的方式重新启动批处理。

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

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


当前回答

对于某些程序,将超级秘密的__COMPAT_LAYER环境变量设置为RunAsInvoker可以工作。看看这个:

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

尽管这样,将没有UAC提示用户将继续没有管理权限。

其他回答

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

在Windows 8上提升脚本后,当前目录将被设置为c:\Windows\system32。幸运的是,有一个简单的解决方法,将当前目录更改为当前脚本的路径:

cd /d %~dp0

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

要测试这一点,可以将以下内容复制到脚本中。在两个版本上正常运行可以看到相同的结果。以Admin身份运行,看看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

我把这个粘贴在脚本的开头:

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

正如jcoder和Matt提到的,PowerShell使它变得很容易,甚至可以在不创建新脚本的情况下嵌入到批处理脚本中。

我修改了马特的剧本:

:: Check privileges 
net file 1>NUL 2>NUL
if not '%errorlevel%' == '0' (
    powershell Start-Process -FilePath "%0" -ArgumentList "%cd%" -verb runas >NUL 2>&1
    exit /b
)

:: Change directory with passed argument. Processes started with
:: "runas" start with forced C:\Windows\System32 workdir
cd /d %1

:: Actual work

对于某些程序,将超级秘密的__COMPAT_LAYER环境变量设置为RunAsInvoker可以工作。看看这个:

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

尽管这样,将没有UAC提示用户将继续没有管理权限。

我是这样做的:

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选项)。

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

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

无论如何,我发现这种方法比其他答案上提出的其他解决方案更简单,我希望它能帮助到一些人。