I am trying to write a batch file for my users to run from their Vista machines with UAC. The file is re-writing their hosts file, so it needs to be run with Administrator permissions. I need to be able to send them an email with a link to the .bat file. The desired behavior is that when they right-click on the file and say Open, they will get one of those UAC dialogs that makes the screen go dark and forces them to answer whether they want to give the application permission to run as administrator. Instead, they are just seeing "Access denied" on the command line window.
Is this possible to do differently?
This script does the trick! Just paste it into the top of your bat file. If you want to review the output of your script, add a "pause" command at the bottom of your batch file.
UPDATE: This script is now slightly edited to support command line arguments and a 64 bit OS.
Thank you Eneerge @ https://sites.google.com/site/eneerge/scripts/batchgotadmin
@echo off
:: BatchGotAdmin
:-------------------------------------
REM --> Check for permissions
IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64" (
>nul 2>&1 "%SYSTEMROOT%\SysWOW64\cacls.exe" "%SYSTEMROOT%\SysWOW64\config\system"
) ELSE (
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
)
REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
echo Requesting administrative privileges...
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
set params= %*
echo UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params:"=""%", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"
exit /B
:gotAdmin
pushd "%CD%"
CD /D "%~dp0"
:--------------------------------------
<YOUR BATCH SCRIPT HERE>
Here's what I've been using:
@echo off
if not "%1"=="am_admin" (
powershell -Command "Start-Process -Verb RunAs -FilePath '%0' -ArgumentList 'am_admin'"
exit /b
)
echo main code here
pause
Notes:
The -Verb RunAs flag of Start-Process is what enables the administrative elevation.
Only tested on windows 7 and 10, you might have to mess around with the quoting
Doesn't support passing along arguments for now, but you might be able to add more stuff to -ArgumentList. Note that -ArgumentList accepts either a single string or a string array.
am_admin
if not "%1"=="am_admin" (powershell start -verb runas '%0' 'am_admin "%~1" "%~2"' & exit)
The params will be one above where they were
'am_admin %*'
to pass everything, doesn't play well with quotes and spaces tho :/ You can use shift
in batch to pop the first arg off, thus fixing all args except %0
.
cd /D %~dp0
after if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
Here is my code! It looks big but it is mostly comment lines (the lines starting with ::).
Features:
Full argument forwarding
Does not change working folder
Error handling
Accepts paths with parenthesis (except for %TEMP% folder)
Supports UNC paths
Mapped folder check (Warn´s you if admin can´t access mapped drive)
Can be used as an external library (check my post at this topic: https://stackoverflow.com/a/30417025/4932683)
Can be called when/if needed anywhere in your code
Just attach this to the end of your batch file, or save it as a library (check above)
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:RequestAdminElevation FilePath %* || goto:eof
::
:: By: Cyberponk, v1.5 - 10/06/2016 - Changed the admin rights test method from cacls to fltmc
:: v1.4 - 17/05/2016 - Added instructions for arguments with ! char
:: v1.3 - 01/08/2015 - Fixed not returning to original folder after elevation successful
:: v1.2 - 30/07/2015 - Added error message when running from mapped drive
:: v1.1 - 01/06/2015
::
:: Func: opens an admin elevation prompt. If elevated, runs everything after the function call, with elevated rights.
:: Returns: -1 if elevation was requested
:: 0 if elevation was successful
:: 1 if an error occured
::
:: USAGE:
:: If function is copied to a batch file:
:: call :RequestAdminElevation "%~dpf0" %* || goto:eof
::
:: If called as an external library (from a separate batch file):
:: set "_DeleteOnExit=0" on Options
:: (call :RequestAdminElevation "%~dpf0" %* || goto:eof) && CD /D %CD%
::
:: If called from inside another CALL, you must set "_ThisFile=%~dpf0" at the beginning of the file
:: call :RequestAdminElevation "%_ThisFile%" %* || goto:eof
::
:: If you need to use the ! char in the arguments, the calling must be done like this, and afterwards you must use %args% to get the correct arguments:
:: set "args=%* "
:: call :RequestAdminElevation ..... use one of the above but replace the %* with %args:!={a)%
:: set "args=%args:{a)=!%"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEDELAYEDEXPANSION & set "_FilePath=%~1"
if NOT EXIST "!_FilePath!" (echo/Read RequestAdminElevation usage information)
:: UAC.ShellExecute only works with 8.3 filename, so use %~s1
set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)
:: Remove parenthesis from the temp filename
set _FN=%_FN:(=%
set _vbspath="%temp:~%\%_FN:)=%.vbs" & set "_batpath=%temp:~%\%_FN:)=%.bat"
:: Test if we gave admin rights
fltmc >nul 2>&1 || goto :_getElevation
:: Elevation successful
(if exist %_vbspath% ( del %_vbspath% )) & (if exist %_batpath% ( del %_batpath% ))
:: Set ERRORLEVEL 0, set original folder and exit
endlocal & CD /D "%~dp1" & ver >nul & goto:eof
:_getElevation
echo/Requesting elevation...
:: Try to create %_vbspath% file. If failed, exit with ERRORLEVEL 1
echo/Set UAC = CreateObject^("Shell.Application"^) > %_vbspath% || (echo/&echo/Unable to create %_vbspath% & endlocal &md; 2>nul &goto:eof)
echo/UAC.ShellExecute "%_batpath%", "", "", "runas", 1 >> %_vbspath% & echo/wscript.Quit(1)>> %_vbspath%
:: Try to create %_batpath% file. If failed, exit with ERRORLEVEL 1
echo/@%* > "%_batpath%" || (echo/&echo/Unable to create %_batpath% & endlocal &md; 2>nul &goto:eof)
echo/@if %%errorlevel%%==9009 (echo/^&echo/Admin user could not read the batch file. If running from a mapped drive or UNC path, check if Admin user can read it.)^&echo/^& @if %%errorlevel%% NEQ 0 pause >> "%_batpath%"
:: Run %_vbspath%, that calls %_batpath%, that calls the original file
%_vbspath% && (echo/&echo/Failed to run VBscript %_vbspath% &endlocal &md; 2>nul & goto:eof)
:: Vbscript has been run, exit with ERRORLEVEL -1
echo/&echo/Elevation was requested on a new CMD window &endlocal &fc;: 2>nul & goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Example on how to use it
:EXAMPLE
@echo off
:: Run this script with elevation
call :RequestAdminElevation "%~dpfs0" %* || goto:eof
echo/I now have Admin rights!
echo/
echo/Arguments using %%args%%: %args%
echo/Arguments using %%*: %*
echo/%%1= %~1
echo/%%2= %~2
echo/%%3= %~3
echo/
echo/Current Directory: %CD%
echo/
echo/This file: %0
echo/
pause &goto:eof
[here you paste the RequestAdminElevation function code]
&fc;: 2>nul
in set "_FN=_%~ns1" & echo/%TEMP%| findstr /C:"(" >nul && (echo/ERROR: %%TEMP%% path can not contain parenthesis &pause &endlocal &fc;: 2>nul & goto:eof)
was setting the errorlevel to 1. I removed that bit and it worked perfect. I'm using Windows 10 Home.
fc;:
since it goes :eof right after? I'm not sure why that little bit caused the issue either, since it should be getting executed.
echo/%TEMP%| findstr /C:"(" >nul
tests if there is a (
char in yout %temp%
environment variable, and should only run the part after the &&
if positive. It is strange why your (
test is returning positive though.
Another approach is to
create a shortcut locally and set it to call for Admin permission (Properties, Advanced, Run as Admin)
and then
send your users the shortcut (or a link to the shortcut rather than one to the batch file itself).
Ben Gripka's solution causes infinite loops. His batch works like this (pseudo code):
IF "no admin privileges?"
"write a VBS that calls this batch with admin privileges"
ELSE
"execute actual commands that require admin privileges"
As you can see, this causes an infinite loop, if the VBS fails requesting admin privileges.
However, the infinite loop can occur, although admin priviliges have been requested successfully.
The check in Ben Gripka's batch file is just error-prone. I played around with the batch and observed that admin privileges are available although the check failed. Interestingly, the check worked as expected, if I started the batch file from windows explorer, but it didn't when I started it from my IDE.
So I suggest to use two separate batch files. The first generates the VBS that calls the second batch file:
@echo off
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
set params = %*:"=""
echo UAC.ShellExecute "cmd.exe", "/c ""%~dp0\my_commands.bat"" %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"
The second, named "my_commands.bat" and located in the same directory as the first contains your actual commands:
pushd "%CD%"
CD /D "%~dp0"
REM Your commands which require admin privileges here
This causes no infinite loops and also removes the error-prone admin privilege check.
Another PowerShell Solution...
This is not about running a batch script as admin per, but rather how to elevate another program from batch...
I have a batch file "wrapper" for an exe. They have the same "root file name", but alternate extensions. I am able to launch the exe as admin, and set the working directory to the one containing the script, with the following one line powershell invocation:
@powershell "Start-Process -FilePath '%~n0.exe' -WorkingDirectory '%~dp0' -Verb RunAs"
More info
There are a whole slew of additional Start-Process
options as well that you can apply! Check out: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-6
Note that I use the @
prefix. That's equivalent to @echo off
for the one line. I use %~n0
here to get the "root name" of the batch script, then I concatenate the .exe
to point it the adjancent binary. The use of %~dp0
provides the full path to the directory which the batch resides. And, of course, the -Verb RunAs
parameter provides the elevation.
I know this is not a solution for OP, but since I'm sure there are many other use cases here, I thought I would share.
I've had problems with all the code examples in these answers but then I found : http://www.robotronic.de/runasspcEn.html
It not only allows you to run as admin, it checks the file to make sure it has not been tampered with and stores the needed information securely. I'll admit it's not the most obvious tool to figure out how to use but for those of us writing code it should be simple enough.
@echo off
Net session >nul 2>&1 || (PowerShell start -verb runas '%~0' &exit /b)
Echo Administrative privileges have been got. & pause
The above works on my Windows 10 Version 1903
@echo off
and title
can come before this code:
net session>nul 2>&1
if %errorlevel%==0 goto main
echo CreateObject("Shell.Application").ShellExecute "%~f0", "", "", "runas">"%temp%/elevate.vbs"
"%temp%/elevate.vbs"
del "%temp%/elevate.vbs"
exit
:main
<code goes here>
exit
A lot of the other answers are overkill if you don't need to worry about the following:
Parameters
Working Directory (cd %~dp0 will change to the directory containing the batch file)
There's also the FSUTIL query from this post which is also linked at ss64.com that has the following code:
@Echo Off
Setlocal
:: First check if we are running As Admin/Elevated
FSUTIL dirty query %SystemDrive% >nul
if %errorlevel% EQU 0 goto START
::Create and run a temporary VBScript to elevate this batch file
Set _batchFile=%~f0
Set _Args=%*
:: double up any quotes
Set _batchFile=""%_batchFile:"=%""
Set _Args=%_Args:"=""%
Echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\~ElevateMe.vbs"
Echo UAC.ShellExecute "cmd", "/c ""%_batchFile% %_Args%""", "", "runas", 1 >> "%temp%\~ElevateMe.vbs"
cscript "%temp%\~ElevateMe.vbs"
Exit /B
:START
:: set the current directory to the batch file location
cd /d %~dp0
:: Place the code which requires Admin/elevation below
Echo We are now running as admin [%1] [%2]
pause
As long as FSUTIL is around, it's a reliable alternative.
Since I have troubles with this script popping up a new command prompt with itself run again, in infinite loop (using Win 7 Pro), I suggest you try another approach :How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
Be careful, you have to add this at the end of script, as stated in an edit, so that you are back to script directory after privileges were elevated : cd /d %~dp0
Based on post by toster-cx and other interesting posts on this page, I got insight on how to configure and solve my problem. I had similar issue where I wished that Disk Cleanup utility runs every week twice on Monday and Thursday during lunch hours (say 2 pm). However, this required elevated rights.
Sharing batch file which might help other beginners like me -
@echo off
echo Welcome to scheduling 'PC Maintenance Activity'
ping localhost -n 3 >nul
echo -- Step - 1 of 3 : Please give 'Admin' rights on next screen
ping localhost -n 5 >nul
if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit)
cls
echo -- Step - 2 of 3 : In next screen, select temp areas for cleaning
during routine scheduled activity
ping localhost -n 3 >nul
C:\Windows\System32\cleanmgr.exe /sageset:112
cls
echo Now scheduling maintenance activity...
SchTasks /Create /SC WEEKLY /D MON,THU /TN PC_Cleanup /TR
"C:\Windows\System32\cleanmgr.exe "/sagerun:112 /ST 14:00
cls
echo -- Thanks for your co-operation --
echo -- Maintenance activity is scheduled for --
echo -- Every Monday and Thursday at 2 pm --
ping localhost -n 10 >nul
Thanks a lot for this forum and Rems POST here [https://www.petri.com/forums/forum/windows-scripting/general-scripting/32313-schtasks-exe-need-to-pass-parameters-to-script][1]
His post helped for configuring optional argument while scheduling the task.
Use mshta
to prompt for admin rights:
@echo off
net session >nul 2>&1 && goto :admintasks
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', '', '', 'runas', 1);close();"
exit /b
:admintasks
rem ADMIN TASKS HERE
Or, using powershell:
powershell -c Start-Process "%~nx0" -Verb runas
You can't request admin rights from a batch file, but you could write a windows scripting host script in %temp% and run that (and that in turn executes your batch as admin) You want to call the ShellExecute method in the Shell.Application object with "runas" as the verb
I used multiple examples to patch this working one liner together.
This will open your batch script as an ADMIN + Maximized Window
Just add one of the following codes to the top of your batch script. Both ways work, just different ways to code it.
I believe the first example responds the quickest due to /d
switch disabling my doskey commands that I have enabled..
EXAMPLE ONE
@ECHO OFF
IF NOT "%1"=="MAX" (powershell -WindowStyle Hidden -NoProfile -Command {Start-Process CMD -ArgumentList '/D,/C' -Verb RunAs} & START /MAX CMD /D /C %0 MAX & EXIT /B)
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
:: Your original batch code here:
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
EXAMPLE TWO
@ECHO OFF
IF NOT "%1"=="MAX" (powershell -WindowStyle Hidden -NoProfile -Command "Start-Process CMD -ArgumentList '/C' -Verb RunAs" & START /MAX CMD /C "%0" MAX & EXIT /B)
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
:: Your original batch code here:
:--------------------------------------------------------------------------------------------------------------------------------------------------------------------
See below for recommendations when using your original batch code
Place the original batch code in it's entirety
Just because the first line of code at the very top has @ECHO OFF
doesn't mean you should not include it again if your original script has it as well.
This ensures that when the script get's restarted in a new window now running in admin mode that you don't lose your intended script parameters/attributes... Such as the current working directory, your local variables, and so on
You could beginning with the following commands to avoid some of these issues
:: Make sure to use @ECHO OFF if your original code had it
@ECHO OFF
:: Avoid clashing with other active windows variables with SETLOCAL
SETLOCAL
:: Nice color to work with using 0A
COLOR 0A
:: Give your script a name
TITLE NAME IT!
:: Ensure your working directory is set where you want it to be
:: the following code sets the working directory to the script directory folder
PUSHD "%~dp0"
THE REST OF YOUR SCRIPT HERE...
:: Signal the script is finished in the title bar
ECHO.
TITLE Done! NAME IT!
PAUSE
EXIT
use the runas command. But, I don't think you can email a .bat file easily.
runas
command cannot be used to provoke elevation.
Success story sharing
set params= %*
instead ofset params=%*
, so params is guaranteed to be defined