Problems elevating permissions while running a batch (CMD) file

2

2

I’ve put together a batch (CMD) file that we use to check various things on select servers. What is posted below is almost everything (minus sensitive info). If launched with the proper command line, the batch file will proceed to check the day and time that it is launched. This way we can put it in the STARTUP folder on our servers and when we log in, it runs and if the user logs in on a business day between 06:45 AM – 07:30 AM, certain checks are done (i.e., external apps are launched, etc.). Selectively, the proper app is run based on environment variables like COMPUTERNAME, USERNAME (which has been removed in the code below), etc.

One of the processes that we need to run requires elevation of rights (IISRESET). To accomplish this within a batch file, I used the example shown by Matt (thank you) found at https://stackoverflow.com/questions/7044985/how-can-i-auto-elevate-my-batch-file-so-that-it-requests-from-uac-admin-rights. I didn’t want to post on that thread because this is a new topic. In the batch file I provided below, it works properly as is (no guarantees or warranties implied however). But if I remove the “comment” characters (the double colons) by changing:

    :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

...(into)...

    :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

…then the batch file doesn’t run properly. When I remove the comments from the two lines, the batch file no longer properly evaluates variables (whether run manually or as part of the STARTUP process). Even though the batch file states:

    If %COMPUTERNAME%==SERVER1
    If %COMPUTERNAME%==SERVER2

…the command associated with SERVER1 runs properly but SERVER2 runs the commands associated with both SERVER1 and SERVER2. Then, the batch file stops and never executes any of the commands in the COMMON section:

    :COMMON
    explorer.exe /e,
    Start services.msc

…etc…

I've tested a number of scenarios and I know that I am overlooking something simple right in front of my face. Can anyone see what is wrong with the batch file below?

Thank you

-------------------------------------------------------------

Complete batch file:

    @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

STGdb

Posted 2013-11-21T18:50:18.753

Reputation: 483

I couldn't post this over at SO (it kept telling me that my post wasn't formatted properly), so I had to post it here... – STGdb – 2013-11-21T18:56:25.290

Its clear by the failure that the problem is in CHECKPRIVILEGE, going to guess its the OEgetPrivileges.vbs thats failing. I would by trial and error figure out which line causes the elevation of the permissions to fail at. The working lines do not call it. – Ramhound – 2013-11-21T19:01:38.977

Try to write all labels at the same case. Following your first described problem, this seems odd at first. If '%errorlevel%' == '0' ( Goto gotPrivileges ) else ( Goto getPrivileges ) I'm not sure if CMD is able to differentiate or ignore caps. – Doktoro Reichard – 2013-11-21T19:02:31.303

@STGdb - We have the same rules. So you must have missed some formatting. Its likely to be moved since this isn't really topic – Ramhound – 2013-11-21T19:02:37.073

I’m probably overlooking something, but -- you have Goto CHECKPRIVILEGES, but GETPRIVILEGES ends with Exit /B and GOTPRIVILEGES ends with Goto :EOF. Don’t you want to be CALLing CHECKPRIVILEGES? – Scott – 2013-11-21T19:44:33.997

Answers

0

Thank you all very much for your input and advise. Yes, I normally follow standards in any of my code (either always using all lower case or always all UPPER case for labels). Thanks for grabbing that.

So I figured out what my problem was. First, what is happening in my batch file is that it tests whether elevation is needed and if so, it runs a script to obtain elevated access. I was so focused on the elevation part that I wasn't even thinking about the rest of the batch file (and how it evaluates via a command line variable). Because it evaluates using a command line variables, this was causing the rest of the batch file execution to fail. So I took the portion that elevates privileges and rewrote it. I've posted the updated code below so that anyone who may need it can use it also. The code below elevates (if needed) and runs IISRESET elevated. Just added/update as needed.

The "not returning" to the labels portion that I was speaking of in my original post, that was because I was using Goto and not Call. Guess I've been starting into the screen for too long...

Thank you again!!

: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

STGdb

Posted 2013-11-21T18:50:18.753

Reputation: 483