script - Problems elevating permissions while running a batch (CMD) file

06
2014-04
  • STGdb

    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 http://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
    
  • Answers
  • STGdb

    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
    

  • Related Question

    windows - Using Command Prompt arguments to run a file (with arguments) as an administrator?
  • Vercas

    I am making the menu items called Lock for Microsoft's BitLocker. I've got it all right up to one point: locking HDD partitions requires administrator privileges.
    How do I use process paths or CMD or something similar to start an application elevated, with arguments?


  • Related Answers
  • surfasb

    You need the Elevation Powertoy for Vista. It also works on Windows 7. http://blogs.technet.com/b/deploymentguys/archive/2009/01/21/the-elevation-powertoys-and-windows-7.aspx

  • Dennis Williamson

    Use the RUNAS command and put your application name and its arguments within double quotes.

    RUNAS /user:machinename\administrator "app arg1 arg2 \"filename with spaces\""