65.9K
CodeProject 正在变化。 阅读更多。
Home

批处理 - 自动提高管理员权限(以管理员身份运行)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2015年6月2日

CPOL

10分钟阅读

viewsIcon

16767

downloadIcon

415

批处理以管理员身份运行 - 在 BAT 和 CMD 等批处理脚本中自动提高管理员权限 - 通用工具 Batch_Admin

引言

它主要面向Windows系统管理员,因此适用于工作站和服务器。

作为管理员工作时,你是否有时会因为需要记住批处理脚本需要以“以管理员身份运行”而感到烦恼?你是否总是记得在批处理选项中设置快捷方式以管理员身份运行脚本?你是否会因为双击文件后出现一些错误,然后才想到“哦,是的,我忘了”而感到恼火?

如果你只是忘记了,在没有提升权限的情况下启动命令提示符,输入命令运行你的脚本,甚至可能带有一些参数,但在执行过程中却出现错误,那该怎么办?嗯,是的,我知道,我知道。然后,又是“哦,是的,我忘了”。你再次以管理员身份运行命令提示符,然后又费力地输入你的命令,或者从之前的窗口粘贴过来。这还不算太糟,你还能挺过去,但是...

如果你之前忘记以管理员身份运行命令提示符,或者只是点击你的脚本来运行它,结果发现其中的命令序列已经执行了一部分,现在却因为某些原因,直到在Windows中发现需要提升管理员权限,从而导致所有后续操作都失败了。有些事情已经做完了,而另一些事情却出了问题。也许删除了不该删除的东西,没有任何命令应该这样被执行。现在你需要清理这些,进行“撤销”,然后...重新开始,或者这次以管理员身份运行我们的脚本。哎。

这就是为什么我写了这个脚本,它是一个批处理自定义工具,可以轻松地处理这些事情。其理念是使其调用简单、通用、能够抵抗一些奇怪的调用,并在不同的Windows系统上以相同的方式工作。

(请原谅我的英语不好)

使用代码

该工具确保在标准环境、使用标准工具并在不同的Windows系统上以相同的方式工作。它使用了几个标准的内置Windows命令。不使用任何其他外部脚本。它可用于以管理员身份调用任何程序,而不仅仅是批处理脚本。只需创建一个小脚本,然后调用需要管理员权限的程序即可。将其放置在任何搜索 PATH 文件夹中(来自 %PATH%)。

这类似于“以...运行”,但在这里我们不更改用户帐户,只是将管理员组的权限提升到与管理员用户相同的最高权限。

要使用它,你只需将其父批处理脚本中插入以下行(完全按此),该脚本将以管理员身份运行。最好在我们的父脚本顶部执行此操作,并且最好是第一个通过 CALL 进一步调用子脚本的脚本(参见下面的详细说明)。

net session >nul 2>nul&if errorlevel 1  Batch_Admin "%~0" %*

这可以插入到任何通过 CALL 语法调用的子脚本中。

要在仍未拥有管理员权限时显示消息,例如,在调用 Batch_Admin 之前 5 秒将变量 ShowAdminInfo 设置为秒数

SET ShowAdminInfo=5
net session >nul 2>nul&if errorlevel 1  Batch_Admin "%~0" %*

那么它是如何工作的呢?

  • 通过 VBScript 调用 UAC.ShellExecute 以获取用户权限
  • 批处理运行脚本,无论是 BAT 还是 CMD
  • 调用脚本可以在引号中包含很长的名称空间
  • 将所有参数回传给从命令行传递的主脚本,就好像没有调用传输和从头开始一样,也包括特殊字符,如感叹号(!)和百分号(%),以及括号 ()
  • 如果调用发生在主脚本所在的目录中,则保持主脚本的位置
  • 如果我们在自己之前设置了变量 ShowAdminInfo,例如 5 秒,则辅助显示消息,这可以防止立即传递管理员权限,从而提供额外信息并做出明智的决定。需要设置的示例:SET ShowAdminInfo=5 默认情况下,由于未定义此变量,因此不显示。
  • 脚本也在系统搜索路径 %PATH% 和网络资源中调用,例如:\\Computer\share\test.bat
  • 防止在脚本同时调用多个 Batch_Admin 时,写入必要的辅助文件时产生误解。它使用 1 到 100 之间的随机数。
  • 但是,最好在父脚本中使用它。过渡到管理员权限总是要求您在新的窗口、新的环境中完全重新运行脚本,而不能引用之前在我们的脚本中设置的变量,这些变量的值也不会传递给以管理员身份的调用。脚本将再次执行。

关注点

- 设置一个附加变量,供脚本稍后使用,当它在当前目录中时。另请参阅下面的注释。PATH_BAT - 脚本位置的相同路径,例如:C:\UTILS 注意:但是,如果从另一个从属批处理脚本调用 CALL 函数,则需要这些变量的正确值,您必须自己添加两行(当在父脚本中切换到管理员时是必需的,因为那样包括子脚本,如我们上面提到的,我们的 Batch_Admin 不再调用并且不能正确设置这些变量,可能仍然是旧的,适合父脚本,而不是从属脚本)- 这两行对于切换到此目录是可选的,并且可以在第一行的末尾用 & 符号组合

SET "PATH_BAT=%~dp0"&SET "BatchFullName=%~dpf0"
CD /D "%~dp0"

现在说最好的,Batch_Admin新版本中添加的东西,它需要对操作变更进行进一步的描述

为什么要改变?

如果你调用另一个脚本命令 CALL 子脚本,并且只有在子脚本中才会调用旧的 Batch_Admin,那么提升的管理员权限将不会从父脚本传输任何变量。什么都没有,什么都没有。是的,我到处都把 Batch_Admin 放在第一位,主脚本,而且在顶部。好的,但是如果操作脚本时忘记了它,或者如果他把 Batch_Admin 的调用放在了子脚本中,而上层脚本我们自己至少用 SET 命令设置了一个变量呢...?结果是,在后面的子脚本中,通过切换到管理员——它将一无所知关于这个变量的设置。

因此,现在 Batch_Admin 默认情况下会提供帮助。现在设置(切换到管理员后)所有环境变量和系统,使其与用户和脚本主机在切换到管理员之前的环境相同,这在某种程度上将其恢复到切换到管理员之前的状态。唯一的例外是变量 TEMP,它默认保持不变。

但不用担心 - 这些更改仅涉及脚本的当前运行,不涉及 Windows 系统设置或用户配置文件上的常规设置。它们之间没有关联。Windows 每次都会创建环境设置。但是,切换到管理员通常会复制管理员设置,而在此之前我们有自己的以及用户修改后的副本。我们说“复制变量以获取管理员权限”而不是“复制变量管理员”,因为在提升权限后,我们仍然在变量 USERNAME 中请求用户名,例如约翰,而不是管理员。

默认操作

  • 恢复 SET 命令设置的变量,这些权限在切换到管理员之前已设置,但 TEMP 除外。


优点

  • 将之前所有通过 SET 命令设置的变量集合,无论是手动从命令行输入,还是在任何其父批处理脚本中设置的变量,都进行后续设置。这可以测试通过第二个 CALL 命令以及任何进一步设置 Batch_Admin 的脚本按顺序调用。
  • 变量搜索路径 PATH 现在与切换到管理员之前相同,或者如果主脚本对其进行了修改,则此修改将得以保留
  • 例外是变量 TEMP,Batch_Admin 不会干预,也就是说,它像往常一样由系统自己更改(因为当我们切换到管理员时它会更改)
  • 我们重新获得对通常在提升管理员权限后消失的两个变量的访问权
    • CLIENTNAME   - 远程计算机的名称,例如。调用终端会话的工作站名称,例如:  COMPUTER-JOHN
    • SESSIONNAME  - 远程会话的名称,例如。终端会话号,例如:   RDP-Tcp#0
  • 其他系统变量是相同的,因为当你获取管理员权限时它们也不会改变,例如。

              用户名
              USERPROFILE
              HOMEPATH
              APPDATA

缺点

  • 如果有人在父脚本中更改了典型的系统变量,例如 PATH,那么它现在将不会有“干净”的变量集,这可能是预期的(在使用下面描述的参数时)


取消和更改选项

在调用 Batch_Admin 之前,将以下变量设置为任何值(只要有值即可),默认情况下为空)

  • $Admin_SET     - 明确阻止恢复 SET 用户变量,这些变量将是新的、干净的管理员环境变量
  • $Admin_Temp  - 在恢复变量时,它也会恢复变量 TEMP,然后它与调用之前相同(默认不恢复)



更改后调用子批处理脚本CALL命令的一般原则和方法

注意:  通常,切换到管理员权限总是要求在新的窗口、新的环境中从头开始运行脚本,而不能引用预设变量和这些变量的值,这些变量的值也不会传递给以管理员身份的调用。但是...新版本的 Batch_Admin 会这样做,并将这些变量及其值传输到以管理员身份的调用(参见上面的描述)。相反,子脚本中设置的变量仍然不会移动到父脚本。因此,强烈建议仍然在第一个脚本中调用 Batch_Admin,并且在父脚本的开头,特别是当 CALL 命令调用后续脚本时。在每个连续的子脚本中粘贴调用 Batch_Admin 的行是不会出错的,因为它们实际上不会调用 Batch_Admin,或者将无事可做,因为它已经是管理员。

因此,让我们看看在修复后,什么时候工作不正常,什么时候工作正常
   
让我们从一个错误的调用开始。在这里所示的第二个脚本“2.bat”中,会得到消息
(有效,因为这是 Batch_Admin 的新版本,传输了主变量设置)

[2] Variable_1 - 是的,我知道这个变量

而第一个脚本 1.bat 将一无所知关于第二个脚本中 Variable_2 的设置,即

[1] Variable_2 - 我对这个变量一无所知

修复:  只需将第一个脚本单独以管理员身份运行,或者也在其中,即在“1.bat”的顶部插入 Batch_Admin 的调用,就像在第二个脚本“2.bat”中一样。

net session >nul 2>nul&if errorlevel 1  Batch_Admin "%~0" %*

注意:     如果第二个脚本“2.bat”删除行首的冒号
                      :: SET $Admin_SET=Whatever
               那么我们可以测试,如果这是一个旧的 Batch_Admin,也就是没有从父脚本恢复变量的情况下,我们得到什么消息。

 

父脚本,我们称之为 1.BAT

     @echo off
     echo [1] I'm beginning ...&echo.

     SET Variable_1=abc

     CALL 2.BAT

     if     defined Variable_1   echo [1] Variable_1 - Yes, I know this variable
     if not defined Variable_1   echo [1] Variable_1 - I know nothing of this variable
     if     defined Variable_2   echo [1] Variable_2 - Yes, I know this variable
     if not defined Variable_2   echo [1] Variable_2 - I know nothing of this variable
     pause

子脚本,我们称之为 2.BAT

     @echo off
     REM *** A D M I N I S T R A T O R  ***
     :: SET $Admin_SET=Whatever
     net session >nul 2>nul&if errorlevel 1  Batch_Admin "%~0" %*

     SET Variable_2=xyz

     if     defined Variable_1   echo [2] Variable_1 - Yes, I know this variable
     if not defined Variable_1   echo [2] Variable_1 - I know nothing of this variable
     if     defined Variable_2   echo [2] Variable_2 - Yes, I know this variable
     if not defined Variable_2   echo [2] Variable_2 - I know nothing of this variable
     pause

此工具的完整源代码

将以下文本复制到记事本中,并将其保存到磁盘为:  Batch_Admin.bat

或从文章附件下载(附件脚本 本身也包含 其自身的 完整操作说明)

@echo off
(if '%1'=='' SET $Help$=Yes)&(if '%1'=='?' SET $Help$=Yes)&(if '%1'=='/?' SET $Help$=Yes)&(if /I '%1'=='/HELP' SET $Help$=Yes)&(if /I '%1'=='-HELP' SET $Help$=Yes)&(if /I '%1'=='/INFO' SET $Help$=Yes)
if .%$Help$%==.Yes (SET $Help$=&echo *** Batch_Admin ***&echo.&echo Automatically get admin rights for another Batch. See info inside.&TIMEOUT /T 10>nul&(if exist Batch_Admin.bat MORE /C /E +80 Batch_Admin.bat)&pause&goto:eof)

::  A D M I N I S T R A T O R   - Automatically get admin rights for script batch. Paste this on top:    net session >nul 2>nul&if errorlevel 1  Batch_Admin "%~0" %*
::                                Also keep Batch directory localisation and then set variable:   PATH_BAT
::                                if earlier variable "ShowAdminInfo" is empty (not defined) then no info, else showing info with number of seconds
::
::                                Elaboration:  Artur Zgadzaj    Addition informations:  www.widzenia.com/info   (login: info  password: computer)
setlocal
setlocal EnableExtensions
setlocal DisableDelayedExpansion

MD %TEMP% 2> nul
SET /A $Admin_Number=%RANDOM% * 100 / 32768 + 1
SET > "%TEMP%\$Batch_Admin_%$Admin_Number%__SET.TXT"

SET "PATH_BAT=%~dp1"&if not exist "%~1" if not exist "%~1.*" SET "PATH_BAT="

 SET $Parameters=%*
setlocal EnableDelayedExpansion
 SET $Parameters=!$Parameters:%%=%%%%!
setlocal DisableDelayedExpansion

net session >nul 2>nul&if not errorlevel 1  goto Administrator_OK

SET "$Script=%PATH_BAT%%~nx1"
SET "$Script=%$Script:(=^(%"
SET "$Script=%$Script:)=^)%"

if defined ShowAdminInfo   (
   echo.
   echo Script = %$Script%
   echo.
   echo ******************************************************************************
   echo ***   R U N N I N G    A S    A D M I N I S T R A T O R    F O R   Y O U   ***
   echo ******************************************************************************
   echo.
   echo Call up just as the Administrator. You can make a shortcut to the script and set
   echo.
   echo          shortcut ^> Advanced ^> Running as Administrator
   echo.
   echo     Alternatively run once "As Administrator"
   echo     or in the Schedule tasks with highest privileges
   echo.
   echo Cancel Ctrl-C or wait for launch  %ShowAdminInfo%  seconds ...
   TIMEOUT /T %ShowAdminInfo% > nul
   )

SET "Admin_Name=$Batch_Admin_%$Admin_Number%"

SET "Inverted_Commas="
del "%TEMP%\%Admin_Name%_Start.bat" 2>nul
echo %$Parameters% > "%TEMP%\%Admin_Name%_Start.bat"
if not exist "%TEMP%\%Admin_Name%_Start.bat"  SET Inverted_Commas=^"

echo @echo off > "%TEMP%\%Admin_Name%_Start.bat"
echo setlocal DisableDelayedExpansion >> "%TEMP%\%Admin_Name%_Start.bat"
if not defined $Admin_Temp  echo SET TEMP^>^>"%TEMP%\%Admin_Name%__SET.TXT">> "%TEMP%\%Admin_Name%_Start.bat"
if not defined $Admin_SET   echo FOR /F ^"delims=^" %%%%A IN ^(%TEMP%\%Admin_Name%__SET.TXT^) DO SET %%%%A>> "%TEMP%\%Admin_Name%_Start.bat"
echo SET TMP=%%TEMP%%^&SET $Admin_Number=^&SET "PATH_BAT=%PATH_BAT%">> "%TEMP%\%Admin_Name%_Start.bat"
echo del "%TEMP%\%Admin_Name%__*.*" 2^>nul >> "%TEMP%\%Admin_Name%_Start.bat" 
echo CD /D "%CD%" >> "%TEMP%\%Admin_Name%_Start.bat"
echo %$Parameters% %Inverted_Commas% >> "%TEMP%\%Admin_Name%_Start.bat"

echo SET UAC = CreateObject^("Shell.Application"^)                         > "%TEMP%\%Admin_Name%__getPrivileges.vbs"
echo UAC.ShellExecute "%TEMP%\%Admin_Name%_Start.bat", "", "", "runas", 1 >> "%TEMP%\%Admin_Name%__getPrivileges.vbs"
"%TEMP%\%Admin_Name%__getPrivileges.vbs"
endlocal
exit /B

:Administrator_OK
%$Parameters%
goto:eof
REM *** A D M I N I S T R A T O R  - Automatically get admin rights  (The End)  ***

历史

这是第二个版本。 以前,切换到管理员权限后不会恢复用户设置的父脚本变量。

© . All rights reserved.