![运行批处理(CMD)文件时提升权限的问题](https://linux22.com/image/1386957/%E8%BF%90%E8%A1%8C%E6%89%B9%E5%A4%84%E7%90%86%EF%BC%88CMD%EF%BC%89%E6%96%87%E4%BB%B6%E6%97%B6%E6%8F%90%E5%8D%87%E6%9D%83%E9%99%90%E7%9A%84%E9%97%AE%E9%A2%98.png)
我整理了一个批处理 (CMD) 文件,我们用它来检查选定服务器上的各种内容。下面发布的内容几乎是所有内容(敏感信息除外)。如果使用正确的命令行启动,批处理文件将继续检查启动的日期和时间。这样,我们可以将其放在服务器上的 STARTUP 文件夹中,当我们登录时,它会运行,如果用户在工作日上午 06:45 至 07:30 之间登录,则会进行某些检查(即启动外部应用程序等)。根据环境变量(如 COMPUTERNAME、USERNAME(已在下面的代码中删除)等)有选择地运行适当的应用程序。
我们需要运行的进程之一需要提升权限 (IISRESET)。为了在批处理文件中完成此操作,我使用了 Matt(谢谢)提供的示例,该示例位于https://stackoverflow.com/questions/7044985/how-can-i-auto-elevate-my-batch-file-so-that-it-requests-from-uac-admin-rights。我不想在该主题上发帖,因为这是一个新主题。在下面提供的批处理文件中,它可以正常工作(但不提供任何保证或担保)。但如果我通过更改以下内容删除“注释”字符(双冒号):
:BEGIN
If %COMPUTERNAME%==SERVER1 explorer.exe "c:\queue"
:: If %COMPUTERNAME%==SERVER1 Goto CHECKPRIVILEGES
If %COMPUTERNAME%==SERVER2 explorer.exe "c:\queue"
:: If %COMPUTERNAME%==SERVER2 Goto CHECKPRIVILEGES
:COMMON
...(进入)...
:BEGIN
If %COMPUTERNAME%==SERVER1 explorer.exe "c:\queue"
If %COMPUTERNAME%==SERVER1 Goto CHECKPRIVILEGES
If %COMPUTERNAME%==SERVER2 explorer.exe "c:\queue"
If %COMPUTERNAME%==SERVER2 Goto CHECKPRIVILEGES
:COMMON
…那么批处理文件就无法正常运行。当我从这两行中删除注释时,批处理文件不再正确评估变量(无论是手动运行还是作为 STARTUP 过程的一部分运行)。即使批处理文件声明:
If %COMPUTERNAME%==SERVER1
If %COMPUTERNAME%==SERVER2
...与 SERVER1 关联的命令正常运行,但 SERVER2 运行与 SERVER1 和 SERVER2 关联的命令。然后,批处理文件停止并且从不执行 COMMON 部分中的任何命令:
:COMMON
explorer.exe /e,
Start services.msc
…ETC…
我已经测试了许多场景,我知道我忽略了眼前的一些简单的事情。有人能看出下面的批处理文件有什么问题吗?
谢谢
-------------------------------------------------------------
完整批处理文件:
@Echo Off
:: ***** If not started using "-Login" with the cmd line then we won't even check the day or time *****
:: ***** We won't even consider what day or time it is if we run this CMD file manually *****
Set LaunchString=%1%
If [%LaunchString%] equ [] Goto BEGIN Rem ***** No parameters given *****
Call :UPCASE LaunchString
If not %LaunchString% equ -LOGIN Goto BEGIN
:: ***** See if we're running on a normal business weekday *****
:: ***** That way we can put this in server startup to run automatically at login during certain times *****
For /F "tokens=1 delims= " %%A IN ('Date /t') DO @(Set DayName=%%A)
If %DayName:~0,3% equ Mon Goto CONTINUE
If %DayName:~0,3% equ Tue Goto CONTINUE
If %DayName:~0,3% equ Wed Goto CONTINUE
If %DayName:~0,3% equ Thu Goto CONTINUE
If %DayName:~0,3% equ Fri Goto CONTINUE
Goto FINISH Rem ***** Not a business day so exit *****
:CONTINUE
:: Check if the time is between 06:45 and 07:30 and if not then exit otherwise continue processing
Setlocal enableextensions enabledelayedexpansion
Set tm=%time%
Set hh=!tm:~0,2!
Set mm=!tm:~3,2!
If !hh! equ 6 ( :: Hour is 6 (i.e., 06:xx AM)
If not !mm! gtr 44 ( :: - Since hour is 6, are minutes greater than 44 (i.e., after 06:45)?
Goto FINISH
)
) else If !hh! equ 7 ( :: Hour is 7 (i.e., 07:xx AM)
If not !mm! lss 30 ( :: - Since hour is 7, are minutes less than 31 (i.e., before 07:30)?
Goto FINISH
)
) else Goto FINISH
Endlocal
:: If manually launched without command line argument then we start here (no day or time check)
:BEGIN
If %COMPUTERNAME%==SERVER1 explorer.exe "c:\queue"
:: If %COMPUTERNAME%==SERVER1 Goto CHECKPRIVILEGES
If %COMPUTERNAME%==SERVER2 explorer.exe "c:\queue"
:: If %COMPUTERNAME%==SERVER2 Goto CHECKPRIVILEGES
:COMMON
explorer.exe /e,
Start services.msc
:: ***** Check if test file exists *****
If Exist "c:\test.log" Start c:\programA.exe
If Exist "d:\test.log" Start c:\programB.exe
:FINISH
Exit /B
Goto:EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Subroutine - Convert a variable VALUE to all UPPER CASE.
:UPCASE
For %%i IN ("a=A" "b=B" "c=C" "d=D" "e=E" "f=F" "g=G" "h=H" "i=I" "j=J" "k=K" "l=L" "m=M" "n=N" "o=O" "p=P" "q=Q" "r=R" "s=S" "t=T" "u=U" "v=V" "w=W" "x=X" "y=Y" "z=Z") DO Call Set "%1=%%%1:%%~i%%"
Goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Subroutine - Elevate permissions to run IISRESET
:CHECKPRIVILEGES
Net FILE 1>NUL 2>NUL
If '%errorlevel%' == '0' ( Goto gotPrivileges ) else ( Goto getPrivileges )
:GETPRIVILEGES
If '%1'=='ELEV' (shift & goto gotPrivileges)
Setlocal DisableDelayedExpansion
Set "batchPath=%~0"
Setlocal EnableDelayedExpansion
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
"%temp%\OEgetPrivileges.vbs"
:: Del "%temp%\OEgetPrivileges.vbs"
Exit /B
:GOTPRIVILEGES
Setlocal & pushd .
CMD /k iisreset
Goto :EOF
答案1
非常感谢大家的意见和建议。是的,我通常会在我的任何代码中遵循标准(标签要么始终使用全部小写,要么始终使用全部大写)。谢谢您的理解。
所以我弄清楚了我的问题是什么。首先,批处理文件中发生的事情是,它测试是否需要提升权限,如果需要,它会运行脚本来获取提升的访问权限。我太专注于提升权限部分,以至于我甚至没有考虑批处理文件的其余部分(以及它如何通过命令行变量进行评估)。由于它使用命令行变量进行评估,这导致批处理文件的其余部分执行失败。所以我把提升权限的部分拿来重写了。我已将更新后的代码发布在下面,以便任何可能需要它的人也可以使用它。下面的代码提升权限(如果需要)并运行提升的 IISRESET。只需根据需要添加/更新即可。
我在原帖中提到的“不返回”标签部分,是因为我使用的是 Goto 而不是 Call。我想我已经进入屏幕太久了……
再次感谢你!!
:CHECKPRIVILEGES
Setlocal
Set PrivLaunchCmd=%temp%\Cmd2Run.CMD
ECHO "%SystemRoot%\System32\iisreset.exe" > "%PrivLaunchCmd%"
Net FILE 1>NUL 2>NUL
If '%errorlevel%' == '0' Goto GOTPRIVILEGES
:GETPRIVILEGES
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "%PrivLaunchCmd%", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
Call "%temp%\OEgetPrivileges.vbs"
Del "%temp%\OEgetPrivileges.vbs"
Del "%PrivLaunchCmd%"
Endlocal
Goto :EOF
:GOTPRIVILEGES
Call "%PrivLaunchCmd%"
Del "%PrivLaunchCmd%"
Endlocal
Goto :EOF