我正在尝试为我的用户编写一个批处理文件,以便使用 UAC 从他们的 Vista 机器上运行。该文件正在重写其主机文件,因此需要以管理员权限运行。我需要能够向他们发送一封电子邮件,其中包含指向 .bat 文件的链接。期望的行为是,当他们右键单击文件并说“打开”时,他们将获得其中一个使屏幕变暗的 UAC 对话框,并迫使他们回答是否要授予应用程序以管理员身份运行的权限。相反,他们只是在命令行窗口中看到“拒绝访问”。
这可以做不同的事情吗?
这个脚本可以解决问题!只需将其粘贴到 bat 文件的顶部即可。如果要查看脚本的输出,请在批处理文件的底部添加“暂停”命令。
更新:这个脚本现在稍微编辑以支持命令行参数和 64 位操作系统。
谢谢Eneerge @https://sites.google.com/site/eneerge/scripts/batchgotadmin
@echo off
:: BatchGotAdmin
:-------------------------------------
REM --> Check for permissions
IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64" (
>nul 2>&1 "%SYSTEMROOT%\SysWOW64\cacls.exe" "%SYSTEMROOT%\SysWOW64\config\system"
) ELSE (
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.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"
set params= %*
echo UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params:"=""%", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"
exit /B
:gotAdmin
pushd "%CD%"
CD /D "%~dp0"
:--------------------------------------
<YOUR BATCH SCRIPT HERE>
这是我一直在使用的:
@echo off
if not "%1"=="am_admin" (
powershell -Command "Start-Process -Verb RunAs -FilePath '%0' -ArgumentList 'am_admin'"
exit /b
)
echo main code here
pause
笔记:
Start-Process 的 -Verb RunAs 标志是启用管理提升的原因。
仅在 Windows 7 和 10 上测试过,您可能不得不乱用引用
目前不支持传递参数,但您可以向 -ArgumentList 添加更多内容。请注意,-ArgumentList 接受单个字符串或字符串数组。
am_admin
if not "%1"=="am_admin" (powershell start -verb runas '%0' 'am_admin "%~1" "%~2"' & exit)
之后包含参数来传递参数,这些参数将比它们所在的位置高一个
'am_admin %*'
传递所有内容,但不能很好地使用引号和空格:/ 您可以批量使用 shift
来弹出第一个 arg,从而修复除 %0
之外的所有 args。
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
之后添加 cd /D %~dp0
这是我的代码!它看起来很大,但主要是注释行(以 :: 开头的行)。
特征:
全参数转发
不更改工作文件夹
错误处理
接受带括号的路径(%TEMP% 文件夹除外)
支持 UNC 路径
映射文件夹检查(如果管理员无法访问映射驱动器,请警告您)
可用作外部库(查看我在此主题的帖子:https://stackoverflow.com/a/30417025/4932683)
可以在代码中的任何地方/如果需要时调用
只需将其附加到批处理文件的末尾,或将其保存为库(请在上方查看)
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:RequestAdminElevation FilePath %* || goto:eof
::
:: By: Cyberponk, v1.5 - 10/06/2016 - Changed the admin rights test method from cacls to fltmc
:: v1.4 - 17/05/2016 - Added instructions for arguments with ! char
:: v1.3 - 01/08/2015 - Fixed not returning to original folder after elevation successful
:: v1.2 - 30/07/2015 - Added error message when running from mapped drive
:: v1.1 - 01/06/2015
::
:: Func: opens an admin elevation prompt. If elevated, runs everything after the function call, with elevated rights.
:: Returns: -1 if elevation was requested
:: 0 if elevation was successful
:: 1 if an error occured
::
:: USAGE:
:: If function is copied to a batch file:
:: call :RequestAdminElevation "%~dpf0" %* || goto:eof
::
:: If called as an external library (from a separate batch file):
:: set "_DeleteOnExit=0" on Options
:: (call :RequestAdminElevation "%~dpf0" %* || goto:eof) && CD /D %CD%
::
:: If called from inside another CALL, you must set "_ThisFile=%~dpf0" at the beginning of the file
:: call :RequestAdminElevation "%_ThisFile%" %* || goto:eof
::
:: If you need to use the ! char in the arguments, the calling must be done like this, and afterwards you must use %args% to get the correct arguments:
:: set "args=%* "
:: call :RequestAdminElevation ..... use one of the above but replace the %* with %args:!={a)%
:: set "args=%args:{a)=!%"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEDELAYEDEXPANSION & set "_FilePath=%~1"
if NOT EXIST "!_FilePath!" (echo/Read RequestAdminElevation usage information)
:: UAC.ShellExecute only works with 8.3 filename, so use %~s1
set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)
:: Remove parenthesis from the temp filename
set _FN=%_FN:(=%
set _vbspath="%temp:~%\%_FN:)=%.vbs" & set "_batpath=%temp:~%\%_FN:)=%.bat"
:: Test if we gave admin rights
fltmc >nul 2>&1 || goto :_getElevation
:: Elevation successful
(if exist %_vbspath% ( del %_vbspath% )) & (if exist %_batpath% ( del %_batpath% ))
:: Set ERRORLEVEL 0, set original folder and exit
endlocal & CD /D "%~dp1" & ver >nul & goto:eof
:_getElevation
echo/Requesting elevation...
:: Try to create %_vbspath% file. If failed, exit with ERRORLEVEL 1
echo/Set UAC = CreateObject^("Shell.Application"^) > %_vbspath% || (echo/&echo/Unable to create %_vbspath% & endlocal &md; 2>nul &goto:eof)
echo/UAC.ShellExecute "%_batpath%", "", "", "runas", 1 >> %_vbspath% & echo/wscript.Quit(1)>> %_vbspath%
:: Try to create %_batpath% file. If failed, exit with ERRORLEVEL 1
echo/@%* > "%_batpath%" || (echo/&echo/Unable to create %_batpath% & endlocal &md; 2>nul &goto:eof)
echo/@if %%errorlevel%%==9009 (echo/^&echo/Admin user could not read the batch file. If running from a mapped drive or UNC path, check if Admin user can read it.)^&echo/^& @if %%errorlevel%% NEQ 0 pause >> "%_batpath%"
:: Run %_vbspath%, that calls %_batpath%, that calls the original file
%_vbspath% && (echo/&echo/Failed to run VBscript %_vbspath% &endlocal &md; 2>nul & goto:eof)
:: Vbscript has been run, exit with ERRORLEVEL -1
echo/&echo/Elevation was requested on a new CMD window &endlocal &fc;: 2>nul & goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
如何使用它的示例
:EXAMPLE
@echo off
:: Run this script with elevation
call :RequestAdminElevation "%~dpfs0" %* || goto:eof
echo/I now have Admin rights!
echo/
echo/Arguments using %%args%%: %args%
echo/Arguments using %%*: %*
echo/%%1= %~1
echo/%%2= %~2
echo/%%3= %~3
echo/
echo/Current Directory: %CD%
echo/
echo/This file: %0
echo/
pause &goto:eof
[here you paste the RequestAdminElevation function code]
set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)
中的 &fc;: 2>nul
将错误级别设置为 1。我删除了该位,它运行良好。我正在使用 Windows 10 家庭版。
fc;:
,因为它紧随其后 :eof ?我不确定为什么这一点也导致了这个问题,因为它应该被执行。
echo/%TEMP%| findstr /C:"(" >nul
测试您的 %temp%
环境变量中是否有 (
字符,如果是肯定的,则应该只运行 &&
之后的部分。奇怪的是为什么您的 (
测试返回阳性。
另一种方法是
在本地创建快捷方式并将其设置为调用管理员权限(属性、高级、以管理员身份运行)
接着
向您的用户发送快捷方式(或快捷方式的链接,而不是批处理文件本身的链接)。
Ben Gripka 的解决方案会导致无限循环。他的批处理是这样的(伪代码):
IF "no admin privileges?"
"write a VBS that calls this batch with admin privileges"
ELSE
"execute actual commands that require admin privileges"
如您所见,如果 VBS 请求管理员权限失败,这会导致无限循环。
但是,尽管已成功请求管理员权限,但仍可能发生无限循环。
Ben Gripka 的批处理文件中的检查很容易出错。我玩弄了批处理并观察到尽管检查失败,但管理员权限仍然可用。有趣的是,如果我从 Windows 资源管理器启动批处理文件,检查会按预期工作,但是当我从 IDE 启动它时却没有。
所以我建议使用两个单独的批处理文件。第一个生成调用第二个批处理文件的 VBS:
@echo off
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
set params = %*:"=""
echo UAC.ShellExecute "cmd.exe", "/c ""%~dp0\my_commands.bat"" %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"
第二个名为“my_commands.bat”,位于与第一个相同的目录中,包含您的实际命令:
pushd "%CD%"
CD /D "%~dp0"
REM Your commands which require admin privileges here
这不会导致无限循环,并且还删除了容易出错的管理员权限检查。
另一个 PowerShell 解决方案...
这不是关于以管理员身份运行批处理脚本,而是如何从批处理中提升另一个程序...
我有一个 exe 的批处理文件“包装器”。它们具有相同的“根文件名”,但扩展名不同。我能够以管理员身份启动 exe,并将工作目录设置为包含脚本的目录,使用以下一行 powershell 调用:
@powershell "Start-Process -FilePath '%~n0.exe' -WorkingDirectory '%~dp0' -Verb RunAs"
更多信息
您还可以应用大量额外的 Start-Process
选项!签出:https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-6
请注意,我使用 @
前缀。这相当于一行的 @echo off
。我在这里使用 %~n0
来获取批处理脚本的“根名称”,然后连接 .exe
以将其指向相邻的二进制文件。 %~dp0
的使用提供了批处理所在目录的完整路径。当然,-Verb RunAs
参数提供海拔。
我知道这不是 OP 的解决方案,但由于我确信这里还有许多其他用例,所以我想我会分享。
这些答案中的所有代码示例都有问题,但后来我发现:http://www.robotronic.de/runasspcEn.html
它不仅允许您以管理员身份运行,它还检查文件以确保它没有被篡改并安全地存储所需的信息。我承认这不是弄清楚如何使用的最明显的工具,但对于我们这些编写代码的人来说,它应该足够简单。
@echo off
Net session >nul 2>&1 || (PowerShell start -verb runas '%~0' &exit /b)
Echo Administrative privileges have been got. & pause
以上适用于我的 Windows 10 版本 1903
@echo off
和 title
可以出现在此代码之前:
net session>nul 2>&1
if %errorlevel%==0 goto main
echo CreateObject("Shell.Application").ShellExecute "%~f0", "", "", "runas">"%temp%/elevate.vbs"
"%temp%/elevate.vbs"
del "%temp%/elevate.vbs"
exit
:main
<code goes here>
exit
如果您不需要担心以下问题,那么许多其他答案都是多余的:
参数
工作目录(cd %~dp0 将更改为包含批处理文件的目录)
还有来自 this post 的 FSUTIL 查询,它也链接到 ss64.com,具有以下代码:
@Echo Off
Setlocal
:: First check if we are running As Admin/Elevated
FSUTIL dirty query %SystemDrive% >nul
if %errorlevel% EQU 0 goto START
::Create and run a temporary VBScript to elevate this batch file
Set _batchFile=%~f0
Set _Args=%*
:: double up any quotes
Set _batchFile=""%_batchFile:"=%""
Set _Args=%_Args:"=""%
Echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\~ElevateMe.vbs"
Echo UAC.ShellExecute "cmd", "/c ""%_batchFile% %_Args%""", "", "runas", 1 >> "%temp%\~ElevateMe.vbs"
cscript "%temp%\~ElevateMe.vbs"
Exit /B
:START
:: set the current directory to the batch file location
cd /d %~dp0
:: Place the code which requires Admin/elevation below
Echo We are now running as admin [%1] [%2]
pause
只要 FSUTIL 存在,它就是一个可靠的替代方案。
由于此脚本在无限循环中(使用 Win 7 Pro)再次运行时弹出一个新的命令提示符,因此我建议您尝试另一种方法:How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
请注意,您必须在脚本末尾添加它,如编辑中所述,以便在提升权限后返回脚本目录:cd /d %~dp0
根据 toster-cx 的帖子和此页面上的其他有趣帖子,我了解了如何配置和解决我的问题。我有类似的问题,我希望磁盘清理实用程序在周一和周四的午餐时间(比如下午 2 点)每周运行两次。但是,这需要更高的权限。
共享批处理文件,这可能有助于像我这样的其他初学者 -
@echo off
echo Welcome to scheduling 'PC Maintenance Activity'
ping localhost -n 3 >nul
echo -- Step - 1 of 3 : Please give 'Admin' rights on next screen
ping localhost -n 5 >nul
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit)
cls
echo -- Step - 2 of 3 : In next screen, select temp areas for cleaning
during routine scheduled activity
ping localhost -n 3 >nul
C:\Windows\System32\cleanmgr.exe /sageset:112
cls
echo Now scheduling maintenance activity...
SchTasks /Create /SC WEEKLY /D MON,THU /TN PC_Cleanup /TR
"C:\Windows\System32\cleanmgr.exe "/sagerun:112 /ST 14:00
cls
echo -- Thanks for your co-operation --
echo -- Maintenance activity is scheduled for --
echo -- Every Monday and Thursday at 2 pm --
ping localhost -n 10 >nul
非常感谢这个论坛和 Rems 在这里发帖 [https://www.petri.com/forums/forum/windows-scripting/general-scripting/32313-schtasks-exe-need-to-pass-parameters-to-script][1]
他的帖子有助于在安排任务时配置可选参数。
使用 mshta
提示管理员权限:
@echo off
net session >nul 2>&1 && goto :admintasks
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 1);close();"
exit /b
:admintasks
rem ADMIN TASKS HERE
或者,使用 powershell:
powershell -c Start-Process "%~nx0" -Verb runas
您不能从批处理文件中请求管理员权限,但您可以在 %temp% 中编写一个 Windows 脚本主机脚本并运行它(然后以管理员身份执行您的批处理)您想在 Shell 中调用 ShellExecute 方法。以“runas”为动词的应用对象
我使用了多个示例将这个工作的一个班轮修补在一起。
这会将您的批处理脚本作为 ADMIN + Maximized Window
打开
只需将以下代码之一添加到批处理脚本的顶部。两种方式都有效,只是编码方式不同。
我相信第一个示例响应最快,因为 /d
开关禁用了我启用的 doskey 命令。
EXAMPLE ONE
@ECHO OFF
IF NOT "%1"=="MAX" (powershell -WindowStyle Hidden -NoProfile -Command {Start-Process CMD -ArgumentList '/D,/C' -Verb RunAs} & START /MAX CMD /D /C %0 MAX & EXIT /B)
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
:: Your original batch code here:
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
EXAMPLE TWO
@ECHO OFF
IF NOT "%1"=="MAX" (powershell -WindowStyle Hidden -NoProfile -Command "Start-Process CMD -ArgumentList '/C' -Verb RunAs" & START /MAX CMD /C "%0" MAX & EXIT /B)
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
:: Your original batch code here:
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
有关使用原始批次代码时的建议,请参见下文
放置原始批号 in it's entirety
仅仅因为最顶部的第一行代码有 @ECHO OFF
并不意味着如果您的原始脚本也有它,您不应该再次包含它。
这确保了当脚本在现在以管理员模式运行的新窗口中重新启动时,您不会丢失预期的脚本参数/属性......例如当前工作目录、本地变量等
您可以从以下命令开始以避免其中一些问题
:: Make sure to use @ECHO OFF if your original code had it
@ECHO OFF
:: Avoid clashing with other active windows variables with SETLOCAL
SETLOCAL
:: Nice color to work with using 0A
COLOR 0A
:: Give your script a name
TITLE NAME IT!
:: Ensure your working directory is set where you want it to be
:: the following code sets the working directory to the script directory folder
PUSHD "%~dp0"
THE REST OF YOUR SCRIPT HERE...
:: Signal the script is finished in the title bar
ECHO.
TITLE Done! NAME IT!
PAUSE
EXIT
使用 runas 命令。但是,我认为您不能轻松地通过电子邮件发送 .bat 文件。
runas
命令不能用于引发提升。
set params= %*
而不是set params=%*
修复了代码,因此保证定义了参数