How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
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 addedcd /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
bySHIFT /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 usefor
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 toset cmdInvoke=1
and check if that already fixes the issue. It will addcmd.exe
to the script performing the elevation.
Or try to change the 2nd parameter towinSysFolder=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:
- Meaning of special characters in batch file:
Quotes ("), Bang (!), Caret (^), Ampersand (&), Other special characters
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
Related videos on Youtube
PDixon724
Updated on April 21, 2022Comments
-
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 over 11 yearsCheck 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 about 9 yearsPlease consider if Matt's answer would be the ticked one? Seems so to me.
-
Jim Fell over 8 yearspossible duplicate of How to request Administrator access inside a batch file
-
Matt over 8 yearsPlease regard the new Windows 10 hints in the comments section of the batch script I have posted.
-
BrunoLM over 8 yearsFrom cmd:
@powershell Start-Process cmd -Verb runas
. From Powershell just drop@powershell
. This starts cmd with elevated rights. -
sactiw about 8 yearsOr try pure windows way using schtasks: stackoverflow.com/questions/19098101/…
-
HaxAddict1337 about 4 yearsThe question is not very clear because the term
auto-elevate
refers toelevating without prompt
. In case you were searching for that, see the exploit here. -
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 over 12 yearsThanks 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 over 12 yearsYup, 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 over 12 yearsI 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 over 12 years
-
PDixon724 over 12 yearsThanks ewall. It looks like I can redistribute AutoIt. I'll go down that road. Thanks again for the help!
-
jcoder over 11 yearsGreat answer, although it amazes me slightly that you have to do all that to do something that is clearly necessary in some cases.
-
Matt over 11 yearsIndeed, a command such as ELEVATE is clearly missing in the Windows batch language.
-
jcoder over 11 yearsPerhaps 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 over 11 yearsThe 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 over 10 yearsGood 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 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 almost 10 yearsYou 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 over 9 yearsWhen invoked from cmd Powershell.exe does not have -verb runas option. It does exist if you are already in PowerShell.
-
Matt over 9 yearsI 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 over 9 yearsMy powershell method: stackoverflow.com/a/25756858/821878 Not as nice as an "ELEVATE" command, but it doesn't require a temporary *.vbs.
-
Nicolas Mommaerts over 9 yearsThis 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 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 over 9 yearsI have already renamed the (legacy) bat file, but thanks for the info anyway
-
Nicolas Mommaerts over 9 yearswhen 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 fromtest.bat "arg1 arg2 arg3"
only arg1 is passed forward -
Nicolas Mommaerts over 9 yearsIt seems that no matter what, the Start-Process removes all double quotes in the argumentlist..
-
ShaunO about 9 yearsI really like this solution, works great for me. On Windows 8.1 I did require the :gotPrivileges label for it to work.
-
fliedonion about 9 yearsThis 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 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 about 9 yearsThe script broke when using quoted arguments, like
test.bat "a thing"
or"test script.bat" arg1 arg2
. All fixed now. -
Tomáš Zato almost 9 yearsYou might want to add
cd %~dp0
before your own code. Otherwise, you'll find out that your working directory is something likeC:\Windows\System32
. Imagine your script accidentally changes something there... -
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 almost 9 yearsI'm hitting a problem if this batch file is remote on a UNC path.
-
meh-uk almost 9 yearsOf note this was also required on my system running Windows 7.
-
VitaminYes over 8 yearsThis 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 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 over 8 years@VitaminYes: The dialog mentioned before does the same as if you would type
ftype VBSFile="%SystemRoot%\System32\WScript.exe" "%1" %*
and thenassoc .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 over 8 yearsAnother 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 over 8 yearsThe .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 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 over 8 yearsHi! 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 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 viaftype
andassoc
). 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 over 8 yearsI'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, becauseNET 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 over 8 yearsThe 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 over 8 yearsI like the arg processing in your script. But note that
cacls
is deprecated in Windows 7 and newer windows versions. -
NeplatnyUdaj over 8 yearsMatt: 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 over 8 yearsThank 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 over 8 yearsI 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. over 8 years@Matt Can you check whether there is some truth behind this rejected edit on your answer?
-
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 theSHIFT
command (see updated listing). It should work fine now. Thanks for bringing this to my attention! -
mlt almost 8 yearsIs there a way to cleanup
%TEMP%
and deleteOEgetPrivileges.vbs
upon termination? -
Matt almost 8 yearsI 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 almost 8 yearsSince 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 almost 8 years@mlt: I've added a cleanup to the script, it was easier than expected. Thank you for the hint!
-
Princa almost 8 yearsis 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 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 almost 8 yearscd %~dp0 will not work on Network drives, use pushd %~dp0 instead.
-
Troy over 7 yearsHey, 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 over 7 yearsI love the simplicity of this answer. And finally a reason to use Jscript!
-
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 useA.bat
just to elevateB.bat
. If that is the case, callB.bat
after the::Start
section ofA.bat
(i.e. do it the opposite way). -
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 over 7 yearsIn 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 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 over 7 yearsMagic! Thank you very much.
-
Marslo over 7 yearsWorks for me! I'm using it for
netsh int set int %wifiname% Enable/Disable
. -
quakes over 7 yearsI 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 over 7 yearsIf 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 over 7 yearsnevermind, I used stackoverflow.com/a/30590134/3706972 which is working with spaces in parameters.
-
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 as1st param 2nd param 3rd param
, which is%1
...%6
instead. -
ADBailey over 7 yearsThanks 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 over 7 years@ADBailey: You're welcome. However I was wondering about "Sysnative" - on my 64 bit Windows there is only
C:\Windows\System32
andC:\Windows\SysWow64
, but notC:\Windows\Sysnative
. In both paths you can findWscript.exe
. -
ADBailey over 7 yearsAh,
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 toc:\Windows\System32
are redirected toc:\Windows\SysWow64
, whilst requestingc:\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 runningc:\Windows\SysWow64\cmd.exe
(32-bit) and listing the directories. -
ADBailey over 7 yearsP.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 betweenSysnative
andSystem32
. 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 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, andElevate.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 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 over 7 yearsGreat 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 over 7 years@ADBailey: Thanks, I have added your explanation to the answer.
-
lit over 7 yearsThe
Elevate.cmd
script ends withcmd /k
. Does this create a new shell process and stay there? -
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 about 7 yearsFsutil dirty is even better
-
Wolf about 7 yearsWhat's the purpose of
pushd .
this looks not very useful without a correspondingpopd
. It also has thecd /D
on board, as I understand the explanation here: Pushd - change directory/folder | Windows CMD | SS64.com ...and my personal observations -
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 commandpushd .
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 about 7 yearsYes, I already know the
/d
option forcd
, but since I'm using a combination ofpushd
(which implicitly doescd /d
-- that's in fact the purpose of the parameter) andpopd
, I don't need the extracd /d
. In your case here, I'd suggest to just remove the pointless& pushd .
-
Wolf about 7 yearsDo you know that the line
pushd "%CD%"
saves the current working directory and changes to the current working directory? -
Wolf about 7 yearsDo you know the
/d
option of theCD
command? (BTW: you have a tasty piano picture in you profile) -
Matt about 7 years@Wolf - Thanks for the hint, I've optimized the script and removed the pushd.
-
Wolf about 7 yearsYou're welcome, but... How exactly did you "optimize" a
0
into a1
? -- I'm a bit confused. (BTW: there was a also typo left from my last edit which I fixed now.) -
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 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 about 7 yearsI 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 about 7 years@Wolf Oh ok. Is that you mentioned my profile picture, I thought you were asking me haha
-
Wolf about 7 yearsMaybe 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 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 almost 7 yearsAnother 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 almost 7 yearsI 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%
andpopd
) with these 3 lines:SET DPZERO=%~dp0%
andSET 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 almost 7 years(My prior comment probably only works for paths without spaces. Otherwise, quotation mark escaping is likely needed.)
-
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 almost 7 yearsor use
pushd %~dp0
instead... why? becausepopd
-
Nulano over 6 yearsThis 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 over 5 yearsWhy 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 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 over 5 yearsFunny, but Windows Defender detects this as a trojan and quarantines it on launch...
-
Radon8472 about 5 yearsThat 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 over 4 yearsI added change directory on start, simplified the flow and cleaned a bit. Work dir can't be changed through
WorkingDirectory
parameter inStart-Process
because of security reason inrunas
processes -
RockPaperLz- Mask it or Casket about 4 yearsThe 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 about 4 yearsCool. Thanks. On which versions of Windows does it function?
-
HaxAddict1337 about 4 yearsit's still in medium integrity not elevated, so you can't edit HKLM in
regedit
. It just skipped the uac. -
Gerardo Grignoli about 4 yearsThe 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 about 4 yearsThanks Gerardo. If anyone tries it on other versions of Windows, please post your results.
-
Gerardo Grignoli about 4 yearsI've just tested gsudo v0.7 on Windows 8.1 and worked. It's not trivial to install
.Net Framework 4.6
there. Luckilychoco install dotnet4.6.2
brought some hard-to-get dependencies. Thengsudo config Prompt "$p# "
fixed an issue withConHost
showing a wrong prompt (escape sequence chars instead of the red sharp). @RockPaperLizard -
RockPaperLz- Mask it or Casket about 4 yearsThanks 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 about 4 yearsIf 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 almost 4 yearsDoes 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 almost 4 yearsthis line is magical, can you explain the first section net sess>nul 2>&1?
-
Riegardt Steyn over 3 yearsSide 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 over 3 yearsWorks like a charm, thank you very much. However, the
cd /d %1
line should be inside the above parenthesis, just after theexit /b
. -
RockPaperLz- Mask it or Casket about 3 yearsNicely done! Glad to see good answers to this question are still flowing in.
-
My1 about 3 yearsdoesnt 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 almost 3 yearsNice 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 almost 3 years@Abdulhameed If the arguments are simple you could use
ShellExecute"%~0","%~*",,"RunAs"
instead ofShellExecute"%~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 almost 3 yearsThis is great tools, Thanks very much
-
RockPaperLz- Mask it or Casket over 2 yearsNice technique! Upvoted. If admin rights aren't granted, will this generate an infinite loop?
-
Michel de Ruiter over 2 yearsNo, the script will just (give an error and) try without elevation.
-
mshakurov over 2 years@jxmallet - just replace
'!arg!'
to'%arg%'
and you can use double quoted arguments. this work for me... -
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 theif
statement, so if thecd
line were in there, it wouldn't be hit like it needs to be. -
Miguel Angelo about 2 yearsThere was a problem with
set "batchPath=%~0"
... wscript could not find the file. I replaced that line withset "batchPath=%~dpnx0"
to set the batchPath variable with the full path of the script. -
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 about 2 yearsI would suggest changing
... && exit /b)
to... && popd && exit /b)
. that way the current directory keeps unchanged after running the script. -
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 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 withset "batchPath=%~dpnx0"
(I have added anecho %batchPath%
right after the set command). Which version of Windows are you using? Windows 11? -
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 about 2 years@Matt - I am using Windows 11
-
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 about 2 years@Matt To reproduce create a file
test.cmd
containingecho %~0
. Then, runcmd
(not powershell) and go to the folder where the file is and run the script with the commandtest.cmd
. -
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!