How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?

339,441

Solution 1

You can have the script call itself with psexec's -h option to run elevated.

I'm not sure how you would detect if it's already running as elevated or not... maybe re-try with elevated perms only if there's an Access Denied error?

Or, you could simply have the commands for the xcopy and reg.exe always be run with psexec -h, but it would be annoying for the end-user if they need to input their password each time (or insecure if you included the password in the script)...

Solution 2

There is an easy way without the need to use an external tool - it runs fine with Windows 7, 8, 8.1, 10 and 11 and is backwards-compatible too (Windows XP doesn't have any UAC, thus elevation is not needed - in that case the script just proceeds).

Check out this code (I was inspired by the code by NIronwolf posted in the thread Batch File - "Access Denied" On Windows 7?), but I've improved it - in my version there isn't any directory created and removed to check for administrator privileges):

::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
:: see "https://stackoverflow.com/a/12264592/1016343" for description
::::::::::::::::::::::::::::::::::::::::::::
 @echo off
 CLS
 ECHO.
 ECHO =============================
 ECHO Running Admin shell
 ECHO =============================

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=1
 set winSysFolder=System32
 set "batchPath=%~dpnx0"
 rem this works also from cmd shell, other than %~0
 for %%k in (%0) do set batchName=%%~nk
 set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
 setlocal EnableDelayedExpansion

:checkPrivileges
  NET FILE 1>NUL 2>NUL
  if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )

:getPrivileges
  if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
  ECHO.
  ECHO **************************************
  ECHO Invoking UAC for Privilege Escalation
  ECHO **************************************

  ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
  ECHO args = "ELEV " >> "%vbsGetPrivileges%"
  ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
  ECHO args = args ^& strArg ^& " "  >> "%vbsGetPrivileges%"
  ECHO Next >> "%vbsGetPrivileges%"
  
  if '%cmdInvoke%'=='1' goto InvokeCmd 

  ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
  goto ExecElevation

:InvokeCmd
  ECHO args = "/c """ + "!batchPath!" + """ " + args >> "%vbsGetPrivileges%"
  ECHO UAC.ShellExecute "%SystemRoot%\%winSysFolder%\cmd.exe", args, "", "runas", 1 >> "%vbsGetPrivileges%"

:ExecElevation
 "%SystemRoot%\%winSysFolder%\WScript.exe" "%vbsGetPrivileges%" %*
 exit /B

:gotPrivileges
 setlocal & cd /d %~dp0
 if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul  &  shift /1)

 ::::::::::::::::::::::::::::
 ::START
 ::::::::::::::::::::::::::::
 REM Run shell as admin (example) - put here code as you like
 ECHO %batchName% Arguments: P1=%1 P2=%2 P3=%3 P4=%4 P5=%5 P6=%6 P7=%7 P8=%8 P9=%9
 cmd /k

The script takes advantage of the fact that NET FILE requires administrator privilege and returns errorlevel 1 if you don't have it. The elevation is achieved by creating a script which re-launches the batch file to obtain privileges. This causes Windows to present the UAC dialog and asks you for the administrator account and password.

I have tested it with Windows 7, 8, 8.1, 10, 11 and with Windows XP - it works fine for all. The advantage is, after the start point you can place anything that requires system administrator privileges, for example, if you intend to re-install and re-run a Windows service for debugging purposes (assumed that mypackage.msi is a service installer package):

msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice

Without this privilege elevating script, UAC would ask you three times for your administrator user and password - now you're asked only once at the beginning, and only if required.


If your script just needs to show an error message and exit if there aren't any administrator privileges instead of auto-elevating, this is even simpler: You can achieve this by adding the following at the beginning of your script:

@ECHO OFF & CLS & ECHO.
NET FILE 1>NUL 2>NUL & IF ERRORLEVEL 1 (ECHO You must right-click and select &
  ECHO "RUN AS ADMINISTRATOR"  to run this batch. Exiting... & ECHO. &
  PAUSE & EXIT /D)
REM ... proceed here with admin rights ...

This way, the user has to right-click and select "Run as administrator". The script will proceed after the REM statement if it detects administrator rights, otherwise exit with an error. If you don't require the PAUSE, just remove it. Important: NET FILE [...] EXIT /D) must be on the same line. It is displayed here in multiple lines for better readability!


On some machines, I've encountered issues, which are solved in the new version above already. One was due to different double quote handling, and the other issue was due to the fact that UAC was disabled (set to lowest level) on a Windows 7 machine, hence the script calls itself again and again.

I have fixed this now by stripping the quotes in the path and re-adding them later, and I've added an extra parameter which is added when the script re-launches with elevated rights.

The double quotes are removed by the following (details are here):

setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion

You can then access the path by using !batchPath!. It doesn't contain any double quotes, so it is safe to say "!batchPath!" later in the script.

The line

if '%1'=='ELEV' (shift & goto gotPrivileges)

checks if the script has already been called by the VBScript script to elevate rights, hence avoiding endless recursions. It removes the parameter using shift.


Update:

  • To avoid having to register the .vbs extension in Windows 10, I have replaced the line
    "%temp%\OEgetPrivileges.vbs"
    by
    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
    in the script above; also added cd /d %~dp0 as suggested by Stephen (separate answer) and by Tomáš Zato (comment) to set script directory as default.

  • Now the script honors command line parameters being passed to it. Thanks to jxmallet, TanisDLJ and Peter Mortensen for observations and inspirations.

  • According to Artjom B.'s hint, I analyzed it and have replaced SHIFT by SHIFT /1, which preserves the file name for the %0 parameter

  • Added del "%temp%\OEgetPrivileges_%batchName%.vbs" to the :gotPrivileges section to clean up (as mlt suggested). Added %batchName% to avoid impact if you run different batches in parallel. Note that you need to use for to be able to take advantage of the advanced string functions, such as %%~nk, which extracts just the filename.

  • Optimized script structure, improvements (added variable vbsGetPrivileges which is now referenced everywhere allowing to change the path or name of the file easily, only delete .vbs file if batch needed to be elevated)

  • In some cases, a different calling syntax was required for elevation. If the script does not work, check the following parameters:
    set cmdInvoke=0
    set winSysFolder=System32
    Either change the 1st parameter to set cmdInvoke=1 and check if that already fixes the issue. It will add cmd.exe to the script performing the elevation.
    Or try to change the 2nd parameter to winSysFolder=Sysnative, this might help (but is in most cases not required) on 64 bit systems. (ADBailey has reported this). "Sysnative" is only required for launching 64-bit applications from a 32-bit script host (e.g. a Visual Studio build process, or script invocation from another 32-bit application).

  • To make it more clear how the parameters are interpreted, I am displaying it now like P1=value1 P2=value2 ... P9=value9. This is especially useful if you need to enclose parameters like paths in double quotes, e.g. "C:\Program Files".

  • If you want to debug the VBS script, you can add the //X parameter to WScript.exe as first parameter, as suggested here (it is described for CScript.exe, but works for WScript.exe too).

  • Bugfix provided by MiguelAngelo: batchPath is now returned correctly on cmd shell. This little script test.cmd shows the difference, for those interested in the details (run it in cmd.exe, then run it via double click from Windows Explorer):

    @echo off
    setlocal
    set a="%~0"
    set b="%~dpnx0"
    if %a% EQU %b% echo running shell execute
    if not %a% EQU %b% echo running cmd shell
    echo a=%a%, b=%b% 
    pause
    

Useful links:

Solution 3

As jcoder and Matt mentioned, PowerShell made it easy, and it could even be embedded in the batch script without creating a new script.

I modified Matt's script:

:: Check privileges 
net file 1>NUL 2>NUL
if not '%errorlevel%' == '0' (
    powershell Start-Process -FilePath "%0" -ArgumentList "%cd%" -verb runas >NUL 2>&1
    exit /b
)

:: Change directory with passed argument. Processes started with
:: "runas" start with forced C:\Windows\System32 workdir
cd /d %1

:: Actual work

Solution 4

I do it this way:

NET SESSION
IF %ERRORLEVEL% NEQ 0 GOTO ELEVATE
GOTO ADMINTASKS

:ELEVATE
CD /d %~dp0
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 1);close();"
EXIT

:ADMINTASKS
(Do whatever you need to do here)
EXIT

This way it's simple and use only windows default commands. It's great if you need to redistribute you batch file.

CD /d %~dp0 Sets the current directory to the file's current directory (if it is not already, regardless of the drive the file is in, thanks to the /d option).

%~nx0 Returns the current filename with extension (If you don't include the extension and there is an exe with the same name on the folder, it will call the exe).

There are so many replies on this post I don't even know if my reply will be seen.

Anyway, I find this way simpler than the other solutions proposed on the other answers, I hope it helps someone.

Solution 5

I am using Matt's excellent answer, but I am seeing a difference between my Windows 7 and Windows 8 systems when running elevated scripts.

Once the script is elevated on Windows 8, the current directory is set to C:\Windows\system32. Fortunately, there is an easy workaround by changing the current directory to the path of the current script:

cd /d %~dp0

Note: Use cd /d to make sure drive letter is also changed.

To test this, you can copy the following to a script. Run normally on either version to see the same result. Run as Admin and see the difference in Windows 8:

@echo off
echo Current path is %cd%
echo Changing directory to the path of the current script
cd %~dp0
echo Current path is %cd%
pause
Share:
339,441

Related videos on Youtube

PDixon724
Author by

PDixon724

Updated on April 21, 2022

Comments

  • PDixon724
    PDixon724 about 2 years

    I want my batch file to only run elevated. If not elevated, provide an option for the user to relaunch batch as elevated.

    I'm writing a batch file to set a system variable, copy two files to a Program Files location, and start a driver installer. If a Windows 7/Windows Vista user (UAC enabled and even if they are a local admin) runs it without right-clicking and selecting "Run as Administrator", they will get 'Access Denied' copying the two files and writing the system variable.

    I would like to use a command to automatically restart the batch as elevated if the user is in fact an administrator. Otherwise, if they are not an administrator, I want to tell them that they need administrator privileges to run the batch file. I'm using xcopy to copy the files and REG ADD to write the system variable. I'm using those commands to deal with possible Windows XP machines. I've found similar questions on this topic, but nothing that deals with relaunching a batch file as elevated.

    • Matt
      Matt over 11 years
      Check out what I've posted - you don't need any external tool, the script automatically checks for admin rights and auto-elevates itself if required.
    • akauppi
      akauppi about 9 years
      Please consider if Matt's answer would be the ticked one? Seems so to me.
    • Jim Fell
      Jim Fell over 8 years
    • Matt
      Matt over 8 years
      Please regard the new Windows 10 hints in the comments section of the batch script I have posted.
    • BrunoLM
      BrunoLM over 8 years
      From cmd: @powershell Start-Process cmd -Verb runas. From Powershell just drop @powershell. This starts cmd with elevated rights.
    • sactiw
      sactiw about 8 years
      Or try pure windows way using schtasks: stackoverflow.com/questions/19098101/…
    • HaxAddict1337
      HaxAddict1337 about 4 years
      The question is not very clear because the term auto-elevate refers to elevating without prompt. In case you were searching for that, see the exploit here.
    • Matt
      Matt about 2 years
      @akauppi - I'm honored to hear that, however, the user PDixon724 who asked this question was last seen 10 years ago. He's the only one who can change the accepted answer.
  • PDixon724
    PDixon724 over 12 years
    Thanks for the response. Unfortunately, I don't think I can use anything outside of stock Windows Vista/7 tools because this will be going out to customers outside of my office. I don't think I can legally distribute PSExec.
  • ewall
    ewall over 12 years
    Yup, I think you are right about that--even though PSExec is now a Microsoft tool (since they bought out the Sysinternals guys!) the EULA does forbid distribution :(
  • PDixon724
    PDixon724 over 12 years
    I think my options are pretty limited. If I knew how to code in VB, I could make it an exe with an admin manifest, but I wouldn't even know where to start. I guess I'll just warn at the beginning of the batch to run as admin if they're running Windows Vista/7. Thanks all.
  • ewall
    ewall over 12 years
    Another 3rd-party tool that might be freely redistributable and easy to integrate and learn is AutoIt; this page demonstrates how the script requests elevated privileges.
  • PDixon724
    PDixon724 over 12 years
    Thanks ewall. It looks like I can redistribute AutoIt. I'll go down that road. Thanks again for the help!
  • jcoder
    jcoder over 11 years
    Great answer, although it amazes me slightly that you have to do all that to do something that is clearly necessary in some cases.
  • Matt
    Matt over 11 years
    Indeed, a command such as ELEVATE is clearly missing in the Windows batch language.
  • jcoder
    jcoder over 11 years
    Perhaps it's easier with powershell which seems to be the approved scripting lanaguge for more complex things, but I never bothered to learn it so far :(
  • Matt
    Matt over 11 years
    The syntax in powershell is completely different (verb-noun syntax), but it allows you to call .NET assemblies easily. But it is a bit more difficult to handle it (signing scripts etc).
  • Matt
    Matt over 10 years
    Good hint, Stephen. So the script should end with cd %~dp0 to retain its current path (I assume this works in Win7 as well, so the same command can be used although only needed for Win8+). +1 for this!
  • Nicolas
    Nicolas about 10 years
    psexec -h doesn't work: 'Couldn't install PSEXESVC service: Access is denied.'. You need to already have the administrator rights to run psexec.
  • Matt
    Matt almost 10 years
    You are right, if PowerShell is installed, you can use it to run the batch file with elevation (thank you for the code snippet!). And yes, the label is is not needed. Thank you for the hints, it's worth a +1 ... :-)
  • Adil Hindistan
    Adil Hindistan over 9 years
    When invoked from cmd Powershell.exe does not have -verb runas option. It does exist if you are already in PowerShell.
  • Matt
    Matt over 9 years
    I haven't tested it with Windows Server 2012 explicitly, but it works with Windows 7 and 8 so I tend to say yes. However, to be sure you should test it before you use it. But on a Server, you are usually running scripts without user interaction and hence you would schedule to run it with proper user rights and would not need/want UAC confirmation because it would stop the execution of your scheduled task until an admin types in the user credentials.
  • Ryan Bemrose
    Ryan Bemrose over 9 years
    My powershell method: stackoverflow.com/a/25756858/821878 Not as nice as an "ELEVATE" command, but it doesn't require a temporary *.vbs.
  • Nicolas Mommaerts
    Nicolas Mommaerts over 9 years
    This counts for all proposed solutions here: doesn't work when the script has spaces in its name and you call it from the command prompt
  • Matt
    Matt over 9 years
    @Nicolas: I don't question why you would like to have spaces in the name - try using underscore (_) instead of spaces or use double quotes (") around path+name of the batch file.
  • Nicolas Mommaerts
    Nicolas Mommaerts over 9 years
    I have already renamed the (legacy) bat file, but thanks for the info anyway
  • Nicolas Mommaerts
    Nicolas Mommaerts over 9 years
    when providing a list whitespace seperated arguments surrounded by quotes to get it treated as one, the /c %~fnx0 %*' part seems to leave every part besides the first. Eg from test.bat "arg1 arg2 arg3" only arg1 is passed forward
  • Nicolas Mommaerts
    Nicolas Mommaerts over 9 years
    It seems that no matter what, the Start-Process removes all double quotes in the argumentlist..
  • ShaunO
    ShaunO about 9 years
    I really like this solution, works great for me. On Windows 8.1 I did require the :gotPrivileges label for it to work.
  • fliedonion
    fliedonion about 9 years
    This is a useful answer. However in ECHO UAC.ShellExecute.... line, "batchArgs!" will not expand variable. Use "!batchArgs!". My edit was rejected, so I comment.
  • jxmallett
    jxmallett about 9 years
    @fliedonion well spotted! I'm not sure why your edit was rejected because it was definitely a typo and your fix works. Made the change myself and tested it on Win 8.1. Now to find all the scripts where I use this code....
  • jxmallett
    jxmallett about 9 years
    The script broke when using quoted arguments, like test.bat "a thing" or "test script.bat" arg1 arg2. All fixed now.
  • Tomáš Zato
    Tomáš Zato almost 9 years
    You might want to add cd %~dp0 before your own code. Otherwise, you'll find out that your working directory is something like C:\Windows\System32. Imagine your script accidentally changes something there...
  • Matt
    Matt almost 9 years
    @Tomáš Zato: Yes, that is correct. Note that Stephen has already suggested it. Take a look at the code snippet he has provided.
  • Ryan Beesley
    Ryan Beesley almost 9 years
    I'm hitting a problem if this batch file is remote on a UNC path.
  • meh-uk
    meh-uk almost 9 years
    Of note this was also required on my system running Windows 7.
  • VitaminYes
    VitaminYes over 8 years
    This does not seem to work with Windows 10. It did its job well inside 7 and 8/8.1, but not 10. It seems to hang somewhere after line 9.
  • Matt
    Matt over 8 years
    @VitaminYes: I have verified it. It works with WIndows 10 as well, but you probably didn't notice that Windows dialog which pops up for the first time saying "How to open this file?" - select "Microsoft Windows Based Script Host", tickmark "Always use this App to open .vbs files" and click OK. Next time (and every subsequent time) the batch works just fine as it did in Win7/8.
  • Matt
    Matt over 8 years
    @VitaminYes: The dialog mentioned before does the same as if you would type ftype VBSFile="%SystemRoot%\System32\WScript.exe" "%1" %* and then assoc .vbs=VBSFile into an admin console window. It registers the .vbs extension to be run with Windows Script Host - apparently Windows 10 doesn't have this association any longer per default so you have to do it once.
  • Matt
    Matt over 8 years
    Another way for Windows 10 users - if you don't want to change the default registration of .vbs extensions as mentioned above - then you can replace the line "%temp%\OEgetPrivileges.vbs" in the script by "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs", which also worked fine for me.
  • VitaminYes
    VitaminYes over 8 years
    The .vbs extension has its correct association. Wow, this is strange. I hit the return key after the ninth line prints and it ran fine. I wonder what I said "yes" to? Maybe it didn't have WSH after all
  • Matt
    Matt over 8 years
    @VitaminYes: Have you tried the updated version of the script I provided yesterday? It should run regardless of the .vbs extension registration.
  • NeplatnyUdaj
    NeplatnyUdaj over 8 years
    Hi! I'm getting the dialog "This file does not have a program associated with it for performing this action" coming from line where OEgetPrivileges.vbs is executed. I haven't modified the script. The vbs is created and it is executed via WScript. Any ideas? Using Windows 7.
  • Matt
    Matt over 8 years
    @NeplatnyUdaj: I have just tested the updated script with Windows 7/64 bit, and on my PC it runs just fine. Check if %SystemRoot%\System32\WScript.exe is on your machine installed, then check my hints I gave earlier to VitaminYes (regarding registration via ftype and assoc). Maybe you have to install/activate Windows Scripting Host, which would be unusual because it comes out of the box in Windows 7 normally.
  • NeplatnyUdaj
    NeplatnyUdaj over 8 years
    I've found out that the message is not from running the vb script, but from running the batch file via UAC from within the vbs script. It comes from this line: UAC.ShellExecute "C:\Users\Me\Documents\script.bat", "ELEV", "", "runas", 1. Also I have some strange Windows apparently, because NET FILE does not give an exception(yes, I've checked I'm not admin. I had to modify the check to use mkdir in forbidden directory instead.
  • Matt
    Matt over 8 years
    The script needs to be saved as .cmd, e.g. elevate.cmd. It can also be that your Windows installation have issues and needs a refresh (new setup) - I have tested the batch on multiple PCs and found no errors as you described. Try it on a colleague's PC to find that out. I cannot give support on your Windows installation.
  • Matt
    Matt over 8 years
    I like the arg processing in your script. But note that cacls is deprecated in Windows 7 and newer windows versions.
  • NeplatnyUdaj
    NeplatnyUdaj over 8 years
    Matt: The problem was with the group policy(or whatever, I'm not a windows expert) on the company machine. Running it on clean windows works.
  • Matt
    Matt over 8 years
    Thank you for letting me know. Yes, it is possible that some functions are blocked via policies on a company PC. A clean PC or VM installation is always a good one idea for comparison. @NeplatnyUdaj
  • Andreas Reiff
    Andreas Reiff over 8 years
    I managed to break it (due to my fault: running script from mapped network drive, since admin and normal user dont have same mapping). Still: is there a way to see the output? For me, I had to find the .vbs and change the /c to a /K and then saw it manually.
  • Artjom B.
    Artjom B. over 8 years
    @Matt Can you check whether there is some truth behind this rejected edit on your answer?
  • Matt
    Matt over 8 years
    @Artjom B.: Yes, there was an issue, but a bit different. Not removing the SHIFT is the solution, but appending a /1 parameter to the SHIFT command (see updated listing). It should work fine now. Thanks for bringing this to my attention!
  • mlt
    mlt almost 8 years
    Is there a way to cleanup %TEMP% and delete OEgetPrivileges.vbs upon termination?
  • Matt
    Matt almost 8 years
    I thought about that too, there are several issues: One is that the file is locked until the batch ends, another is that if you start any second admin batch it will interfere unless you create a unique temp name. Yes it is possible but complicates things. @mlt
  • mlt
    mlt almost 8 years
    Since we already have admin privileges at some point, perhaps, it might worth considering adding a RunOnce registry entry into HKCU hive to delete the script on next logon.
  • Matt
    Matt almost 8 years
    @mlt: I've added a cleanup to the script, it was easier than expected. Thank you for the hint!
  • Princa
    Princa almost 8 years
    is there a way to not have a prompt window to ask for UAC continue or cancel? Plan to run this in uDeploy or shell which needs to run silently without any prompt and interaction requirement.
  • Matt
    Matt almost 8 years
    @Princa: Yes - this "prompt" is coming from Windows directly. In the Windows control panel, type "UAC" in the search field and press enter. Then open "Change User Account Control settings" by double clicking on it and confirming with an admin account. A dialog opens up where you can drag a slider to "Never notify". Confirm with "OK", reboot your PC and the dialog should go away if you're logged in with a privileged (admin) account. But note this is not a recommended setting because it lowers security.
  • Stavm
    Stavm almost 8 years
    cd %~dp0 will not work on Network drives, use pushd %~dp0 instead.
  • Troy
    Troy over 7 years
    Hey, thanks for the scripts, it works very good if I run a bat file(let's say A.bat) with the codes. But when I try to include A.bat in B.bat and run B.bat, then the UAC will prompt but still not get administration right in this case. I am using "call A.bat" to include the scripts.
  • Joe Coder
    Joe Coder over 7 years
    I love the simplicity of this answer. And finally a reason to use Jscript!
  • Matt
    Matt over 7 years
    @Troy: Admin rights exist only within the context of the elevation script. If I understand it right, you need the admin rights in B.bat, but want to use A.bat just to elevate B.bat. If that is the case, call B.bat after the ::Start section of A.bat (i.e. do it the opposite way).
  • Troy
    Troy over 7 years
    @Matt: Thanks for the comments. Yes, I do need the admin right in B.bat and I want user to double click to run B.bat at first. In B.bat, it includes the A.bat which has your codes fully. Here are my codes in B.bat: <code>call A.bat :: then call my custom codes</code> So, just like A.bat is a library and I want B.bat looks simple. But this won't work for me.
  • Matt
    Matt over 7 years
    In this case, the only way I see is to include the elevation script in B.bat, and the code you have written needs to be appended. Or you can place the elevation in B.bat and call the library and your code from there with two calls, i.e. call A.bat and C.bat (just the simple code) from B.bat.
  • Troy
    Troy over 7 years
    @Matt, Thanks Matt! Maybe it is just like you said, it exits only within context of elevation script. I can figure out other workaround for this. Thanks again.
  • Daniele Orlando
    Daniele Orlando over 7 years
    Magic! Thank you very much.
  • Marslo
    Marslo over 7 years
    Works for me! I'm using it for netsh int set int %wifiname% Enable/Disable.
  • quakes
    quakes over 7 years
    I had the same problem as Nicolas Mommaerts above. I don't understand why it works (the best kind of fix), but the following works like it should (note all the extra quotation marks at the end): net file 1>nul 2>nul && goto :run || powershell -ex unrestricted -Command "Start-Process -Verb RunAs -FilePath '%comspec%' -ArgumentList '/c ""%~fnx0""""'"
  • Andreas Brauchle
    Andreas Brauchle over 7 years
    If a parameter contains spaces it gets spitted into variables, so f.e. "te st" will be only accessible by %1 and %2. Any ideas on how to solve this?
  • Andreas Brauchle
    Andreas Brauchle over 7 years
    nevermind, I used stackoverflow.com/a/30590134/3706972 which is working with spaces in parameters.
  • Matt
    Matt over 7 years
    @brauchle_andi: According to my tests, double quotes are passed through, i.e. if you specify Elevate.cmd "1st param" "2nd param" "3rd param" they are passed this way during elevation as %1 ... %3. If you omit the double quotes, then they are interpreted as 1st param 2nd param 3rd param, which is %1 ... %6 instead.
  • ADBailey
    ADBailey over 7 years
    Thanks for this! I had some difficulty using it to launch a 64-bit application from a 32-bit host (part of a build script; Windows was redirecting to "Program Files" to "Program Files (x86)"). To solve, I replaced %SystemRoot%\System32\WScript.exe with %SystemRoot%\Sysnative\WScript.exe to force the use of 64-bit WScript.
  • Matt
    Matt over 7 years
    @ADBailey: You're welcome. However I was wondering about "Sysnative" - on my 64 bit Windows there is only C:\Windows\System32 and C:\Windows\SysWow64, but not C:\Windows\Sysnative. In both paths you can find Wscript.exe.
  • ADBailey
    ADBailey over 7 years
    Ah, SysNative isn't a "real" directory, just a feature of the File System Redirector that Windows uses for 32-bit applications on 64-bit Windows. In such cases, requests to c:\Windows\System32 are redirected to c:\Windows\SysWow64, whilst requesting c:\Windows\Sysnative is a way of saying "yes, I'm a 32-bit application that is aware of the 64-bit OS and I really do want the proper System32". You can try this out by running c:\Windows\SysWow64\cmd.exe (32-bit) and listing the directories.
  • ADBailey
    ADBailey over 7 years
    P.S. a direct swap to Sysnative is only any good if your (Elevate.cmd) script is always being run in a 32-bit host: in a 64-bit host, Sysnative won't be found. If you want it to be flexible to either (as I ended up doing), you need to add a quick "if exists" condition to switch between Sysnative and System32. It's a niche problem and probably too fussy to edit your provided answer with, but I figured the information would be useful if anybody else ran into it.
  • Matt
    Matt over 7 years
    @ADBailey: Thanks for the explanation, very useful! I think the most practical way is to save a 64bit version of the elevate script, like Elevate64.cmd for 64 bit, and Elevate.cmd for 32 bit. The reason is that such a script would have more dependencies to 64 bit code and many IF's would complicate things ...
  • Matt
    Matt over 7 years
    @ADBailey: I have provided a new version of the script, which includes a parameter for System32 ... this should make life easier for you. Also, I noticed that on some system a 2nd change was required, see the Updates section in the answer.
  • ADBailey
    ADBailey over 7 years
    Great work. I personally ended up diverging from your script a bit in the end to suit my specific needs and do, in my case, genuinely need a script that can elevate a new 64-bit application when run from either a 32-bit or 64-bit host, but I'm sure that the extra flexibility will help others out. No obligation, but your answer would provide additional clarity if it stated explicitly that "Sysnative" is only for launching 64-bit applications from a 32-bit script host (e.g. a Visual Studio build process, or script invocation from another 32-bit application).
  • Matt
    Matt over 7 years
    @ADBailey: Thanks, I have added your explanation to the answer.
  • lit
    lit over 7 years
    The Elevate.cmd script ends with cmd /k. Does this create a new shell process and stay there?
  • Matt
    Matt over 7 years
    @lit: Yes, that is the purpose - to show the admin console after elevating (for demonstration). If you don't need an admin console (because you just want to run your script elevated) remove cmd /k.
  • Wolf
    Wolf about 7 years
    Fsutil dirty is even better
  • Wolf
    Wolf about 7 years
    What's the purpose of pushd . this looks not very useful without a corresponding popd. It also has the cd /D on board, as I understand the explanation here: Pushd - change directory/folder | Windows CMD | SS64.com ...and my personal observations
  • Matt
    Matt about 7 years
    @Wolf - cd /d %~dp0 sets the current directory to the script directory. The /d parameter is required to ensure that the drive is also changed if needed, not only the path. The command pushd . can possibly be removed, it was there from the beginning of development. If you (or someone who already removed and tested it) can confirm, I can remove it.
  • Wolf
    Wolf about 7 years
    Yes, I already know the /d option for cd, but since I'm using a combination of pushd (which implicitly does cd /d -- that's in fact the purpose of the parameter) and popd, I don't need the extra cd /d. In your case here, I'd suggest to just remove the pointless & pushd .
  • Wolf
    Wolf about 7 years
    Do you know that the line pushd "%CD%" saves the current working directory and changes to the current working directory?
  • Wolf
    Wolf about 7 years
    Do you know the /d option of the CD command? (BTW: you have a tasty piano picture in you profile)
  • Matt
    Matt about 7 years
    @Wolf - Thanks for the hint, I've optimized the script and removed the pushd.
  • Wolf
    Wolf about 7 years
    You're welcome, but... How exactly did you "optimize" a 0 into a 1? -- I'm a bit confused. (BTW: there was a also typo left from my last edit which I fixed now.)
  • Matt
    Matt about 7 years
    @Wolf: Right :-) , that has nothing to do with that. Read the comments in my answer (about "calling syntax"), there I have explained the parameter. It works better on my machines with the 1 setting, so I changed that parameter as well. Some might use 0 on their PC depending on their enterprise environment.
  • Matheus Rocha
    Matheus Rocha about 7 years
    @Wolf You can find documentation on the CD command here (as well as other commands): technet.microsoft.com/en-us/library/bb490875.aspx The /d command changes the current drive (or entire path) you're working with. It's pretty much the same as not explicitly using /d apparently.
  • Wolf
    Wolf about 7 years
    I already know this, I just want to emphasize Stavm's comment. You have a "current" working directory on each drive: the cd command doesn't change the drive (even if you explicitly include the drive at the beginning of the path), whereas typing the drive letter plus colon does it. The /d option includes this change of the current drive.
  • Matheus Rocha
    Matheus Rocha about 7 years
    @Wolf Oh ok. Is that you mentioned my profile picture, I thought you were asking me haha
  • Wolf
    Wolf about 7 years
    Maybe adding the /d switch would make your answer applicable also to scripts started from memory sticks and all drives other than the system drive. (concerning the profile image: I'm playing the piano and looking at this keyboard is more fun than looking on my computer keyboard.)
  • Matheus Rocha
    Matheus Rocha about 7 years
    @Wolf I typed a huge answer only to realize I mis-understood you... I got what you mean now. I'm gonna edit it to include the /d. Thank you pal :) (P.S.: Pianist here too!)
  • script'n'code
    script'n'code almost 7 years
    Another problem (inconvenience) is that the script pauses (waits for user input) if the server service isn't running (i have it disabled for reasons). I usuallly test for admin perms by trying to write to the HOSTS file location, but it's perhaps better to invoke the powershell command -Verb runas, instead of relying on enabled windows services or attempting file writes.
  • TOOGAM
    TOOGAM almost 7 years
    I tried Stavm's comment, and pushd wasn't helping much. What did is replacing the MSHTA line of the batch file (which I placed between pushd %~dp0% and popd) with these 3 lines: SET DPZERO=%~dp0% and SET NXZERO=%~nx0% and (the rest of this, up through the quotation mark, is one long line) MSHTA "javascript: var oShellApp = new ActiveXObject('Shell.Application'); var oWSH = new ActiveXObject('WScript.Shell'); oShellApp.ShellExecute('CMD', '/C ' + oWSH.Environment("Process")("DPZERO") + oWSH.Environment("Process")("NXZERO"), '', 'runas', 1);close();"
  • TOOGAM
    TOOGAM almost 7 years
    (My prior comment probably only works for paths without spaces. Otherwise, quotation mark escaping is likely needed.)
  • Bob Sammers
    Bob Sammers almost 7 years
    @quakes +1 for your quotes fix. I can't shed any light on why it works either (seems mismatched to me!) but your version knocks off the " %* " from the original. Intentional? This is presumably designed to relaunch the script with the same parameters as the original invocation. For quotes around the script name (so it can contain spaces), the following seems to work: ""%~fnx0"""" %*'". If there are quotes in the other parameters though, they are still stripped.
  • Jaroslav Záruba
    Jaroslav Záruba almost 7 years
    or use pushd %~dp0 instead... why? because popd
  • Nulano
    Nulano over 6 years
    This works great, but it might be a good idea to move the cd command to the start (this insures that the path is also available to the elevated script - otherwise the elevated script just runs from system32). You should also redirect the net command to nul to hide it's output: net session >nul 2>&1
  • Rev
    Rev over 5 years
    Why is "exit /B" required? If I execute the batch from command prompt, it seems that it does not continue to ":gotPrivileges" until I REM that line. When starting the batch from the explorer by simple double-click, it works fine with the "exit /B" enabled.
  • Matt
    Matt over 5 years
    @Rev1.0 - To get elevated privileges, the batch script needs to invoke itself (a subroutine would not be enough for the UAC to be triggered). The command Exit /b ensures that only the called instance exits correctly after the elevation mechanism is invoked.
  • Ola Berntsson
    Ola Berntsson over 5 years
    Funny, but Windows Defender detects this as a trojan and quarantines it on launch...
  • Radon8472
    Radon8472 about 5 years
    That command only opens a dialogwindow what asks the user if this command is allowed to be executed. So you cant use this command in a batchfile what should run WITHOUT user interactions.
  • ceztko
    ceztko over 4 years
    I added change directory on start, simplified the flow and cleaned a bit. Work dir can't be changed through WorkingDirectory parameter in Start-Process because of security reason inrunas processes
  • RockPaperLz- Mask it or Casket
    RockPaperLz- Mask it or Casket about 4 years
    The link to the Microsoft site no longer worked, so I changed it to the content on archive.org. If anyone can find a working link to the content on Microsoft's site, but all means, please update it to that.
  • RockPaperLz- Mask it or Casket
    RockPaperLz- Mask it or Casket about 4 years
    Cool. Thanks. On which versions of Windows does it function?
  • HaxAddict1337
    HaxAddict1337 about 4 years
    it's still in medium integrity not elevated, so you can't edit HKLM in regedit. It just skipped the uac.
  • Gerardo Grignoli
    Gerardo Grignoli about 4 years
    The tests suite runs on Server 2019 and my local dev box is Windows 10 1909. Sorry I haven't tested compatibility with other older OS.
  • RockPaperLz- Mask it or Casket
    RockPaperLz- Mask it or Casket about 4 years
    Thanks Gerardo. If anyone tries it on other versions of Windows, please post your results.
  • Gerardo Grignoli
    Gerardo Grignoli about 4 years
    I've just tested gsudo v0.7 on Windows 8.1 and worked. It's not trivial to install .Net Framework 4.6 there. Luckily choco install dotnet4.6.2 brought some hard-to-get dependencies. Then gsudo config Prompt "$p# " fixed an issue with ConHost showing a wrong prompt (escape sequence chars instead of the red sharp). @RockPaperLizard
  • RockPaperLz- Mask it or Casket
    RockPaperLz- Mask it or Casket about 4 years
    Thanks so much Gerardo. Could it be recompiled to work with any versions of .Net Framework before 4.6, or does it depend on some functionality specific to 4.6?
  • Andrei Belogortseff
    Andrei Belogortseff about 4 years
    If it were possible to elevate WITHOUT user interaction it would be a huge security hole, wouldn't it? Every virus would start using that method to elevate itself without user approval.
  • Gerardo Grignoli
    Gerardo Grignoli almost 4 years
    Does not depend on 4.6 functionality. Could be backported, but the code uses some 'modern' C# syntax sugar that probably wont compile without fixing.
  • yww325
    yww325 almost 4 years
    this line is magical, can you explain the first section net sess>nul 2>&1?
  • Riegardt Steyn
    Riegardt Steyn over 3 years
    Side note: you don't need to proxy through cmd. You can place the executable there and only the arguments at the end, as in - powershell -Command "Start-Process 'docker-compose' -Verb RunAs -ArgumentList '"-f ./build/postgres.yaml up"'"
  • braggPeaks
    braggPeaks over 3 years
    Works like a charm, thank you very much. However, the cd /d %1 line should be inside the above parenthesis, just after the exit /b.
  • RockPaperLz- Mask it or Casket
    RockPaperLz- Mask it or Casket about 3 years
    Nicely done! Glad to see good answers to this question are still flowing in.
  • My1
    My1 about 3 years
    doesnt seem to work with me as is, but I could change the . to a : in the find, because apparently the error message in german didnt have a dot.
  • Abdulhameed
    Abdulhameed almost 3 years
    Nice solution but regarding the first method, when I try to pass any argument to my batch file, it doesn't reach to that batch file.... I tried to play around with ShellExecute"%fullPathArgs%" but didn't work either. It seems that I've to pass the batch file arguments in another parameter.
  • Pyprohly
    Pyprohly almost 3 years
    @Abdulhameed If the arguments are simple you could use ShellExecute"%~0","%~*",,"RunAs" instead of ShellExecute"%~0",,,"RunAs", but complicated arguments involving quoting, escape sequences, or poison characters will break it. Notice that other answers will have similar caveats. Preserving the arguments reliably is not an easy task.
  • sorosh_sabz
    sorosh_sabz almost 3 years
    This is great tools, Thanks very much
  • RockPaperLz- Mask it or Casket
    RockPaperLz- Mask it or Casket over 2 years
    Nice technique! Upvoted. If admin rights aren't granted, will this generate an infinite loop?
  • Michel de Ruiter
    Michel de Ruiter over 2 years
    No, the script will just (give an error and) try without elevation.
  • mshakurov
    mshakurov over 2 years
    @jxmallet - just replace '!arg!' to '%arg%' and you can use double quoted arguments. this work for me...
  • Rabadash8820
    Rabadash8820 over 2 years
    @braggPeaks I think that's incorrect. The point of the powershell Start-Process line is to re-run the current script with elevated privileges, in a new process. That process would not enter the if statement, so if the cd line were in there, it wouldn't be hit like it needs to be.
  • Miguel Angelo
    Miguel Angelo about 2 years
    There was a problem with set "batchPath=%~0"... wscript could not find the file. I replaced that line with set "batchPath=%~dpnx0" to set the batchPath variable with the full path of the script.
  • Matt
    Matt about 2 years
    @MiguelAngelo - What does %~dpnx0 do exactly? According to this there is %~dp0 for drive letter and path only and %~nx0 for file name and extension only. Does it combine both? And could you give an example what is different in the path you're using that breaks the %~0 parameter? I am curious to hear what the issue is because on my machine it works fine so far.
  • Luuk
    Luuk about 2 years
    I would suggest changing ... && exit /b) to ... && popd && exit /b). that way the current directory keeps unchanged after running the script.
  • Miguel Angelo
    Miguel Angelo about 2 years
    @Matt When I ran it here, it didn't find the path, so I debugged and found out the batchPath variable only had the file name of the batch file. So I used dpnx to specify the parts of the path that I wanted to include: d - drive, p - path, n - name and x - extension. The ~ is used to remove enclosing double quotes, if param 0 have these e.g. when it contains spaces, so this is correct. I think any combo of ~, d, p, n and x will work. The parameter 0 is defined by the caller, I think, so if the caller specify a relative path, it will only contain the relative string when the script reads it.
  • Matt
    Matt about 2 years
    @MiguelAngelo - I've done some testing, with Windows 10 for me it is returning exactly the same (i.e. the full path with filename and extension of the batch file executed) whether I run it with set "batchPath=%~0" or with set "batchPath=%~dpnx0" (I have added an echo %batchPath% right after the set command). Which version of Windows are you using? Windows 11?
  • Matt
    Matt about 2 years
    @MiguelAngelo - I have added a remark to the listing, so those encountering the same issue as you have a workaround at hand.
  • Miguel Angelo
    Miguel Angelo about 2 years
    @Matt - I am using Windows 11
  • Matt
    Matt about 2 years
    @MiguelAngelo - I've tested it now with Windows 11, there it is also working as with 10, didn't see the issue.
  • Miguel Angelo
    Miguel Angelo about 2 years
    @Matt To reproduce create a file test.cmd containing echo %~0. Then, run cmd (not powershell) and go to the folder where the file is and run the script with the command test.cmd.
  • Matt
    Matt about 2 years
    @MiguelAngelo - That helped, thank you! Interesting issue, I could not retrace it in the first place because it only shows up if you run the script in the command shell - I double clicked on the script from the Windows Explorer, then it is showing the full path for both %~0 and %~dpnx0 (also if you "shell execute" it from notepad++ like I did). So the command shell behaves differently. I'll put in %~dpnx0 because it works in every tested scenario the same way. Good catch!