Can Window's ShellExecute function accept WSF script arguments? - batch-file

The batch hybrid script below aims to auto invoke Administrator privileges before running some tasks requiring elevated rights. It does popup the UAC prompt, but regardless of the user choice Admin privileges aren't granted.
I wonder if Window's ShellExecute function used in it can accept WSF arguments or other expandable parameters? In this case its the batch file name. If it can, how the script should be changed for that without restructuring aimed at using a different method?
<!-- : Begin batch script
#echo off
setlocal EnableExtensions EnableDelayedExpansion
CD /D "%~dp0" & echo "%*"
set "dir=%temp%\Unzip"
set "file=%USERPROFILE%\Downloads\archive.zip"
if not "%1"=="ADR" (call :GetAdminRights
if defined adm cscript //nologo "%~f0?.wsf" //job:ADM "%~nx0")
>nul 2>&1 net file && (echo/ & echo "!errorlevel!") || ^
(echo/ & echo "!errorlevel!" & goto :end)
:: add your code here
echo Performing admin tasks
echo Hello >C:\test.txt
:end
timeout 5
exit /b
:GetAdminRights
REM Check for permissions
>nul 2>&1 net file
REM If error flag set, user don't have admin permissions
if '!errorlevel!' NEQ '0' (echo Requesting administrative privileges...
set "adm=0"
echo/ & echo "!errorlevel!" "%~nx0" "%~dp0" & echo/)
exit /b
----- Begin wsf script --->
<package>
<job id="ADM"><script language="VBScript">
Set UAC = CreateObject("Shell.Application")
WScript.Echo wscript.Arguments(0)
UAC.ShellExecute "cmd.exe", "/c ""wscript.Arguments(0)"" ADR", "", "runas", 1
</script></job>
</package>
:: Error in UAC Prompt (shown in details. Can't expand batch name correctly.)
Program location: "C:\Windows\System32\cmd.exe /c "wscript.Arguments(0)" ADR

Yes, it can. The trick is to submit in the cscript call all Cmd.exe arguments required to restart Cmd in Administrator mode, and read them properly in the WSF section of the batch.
<!-- : Begin batch script
#echo off
setlocal EnableExtensions EnableDelayedExpansion
CD /D "%~dp0" & echo "%*"
set "dir=%temp%\Unzip" & set "file=%USERPROFILE%\Downloads\archive.zip"
if not "%1"=="ADR" (call :GetAdminRights
if defined adm cscript //nologo "%~f0?.wsf" //job:ADM "/c" "%~sf0" "ADR" )
echo/ & >nul 2>&1 net file && (echo "!errorlevel!" Got admin rights & echo/) ^
|| (echo "!errorlevel!" No admin rights & goto :end)
:: add your code here
echo Performing admin tasks
echo Hello >C:\tst.txt
:end
timeout /t 5 >nul
exit /b
:GetAdminRights
REM Check for permissions
echo/ & >nul 2>&1 net session && (echo Got admin rights) ^
|| (echo No admin rights) & echo/
REM If error flag set, user don't have admin permissions
if '!errorlevel!' NEQ '0' (echo Requesting admin rights...
set "adm=0" & echo/ & echo "!errorlevel!" "%~nx0" "%~dp0" & echo/)
exit /b
----- Begin wsf script --->
<package>
<job id="ADM"><script language="VBScript">
Set UAC = CreateObject("Shell.Application")
args = ""
For Each strArg in WScript.Arguments
args = args & strArg & " "
Next
WScript.Echo args
UAC.ShellExecute "cmd.exe", args, "", "runas", 1
</script></job>
</package>

Here is a batch script 'Elevate.bat' to execute as Administrator any command passed in arguments string.
If the command contains special characters, escape them by '^'.
For instance:
Elevate whoami /groups ^| find "S-1-16-12288"`
Elevate.bat:
<!-- : --- Self-Elevating Batch Script ---------------------------
#whoami /groups | find "S-1-16-12288" > nul && goto :admin
#set "ELEVATE_CMDLINE=cd /d "%cd%" & call "%~f0" %*"
#cscript //nologo "%~f0?.wsf" //job:Elevate & exit /b
-->
<job id="Elevate"><script language="VBScript">
Set objShell = CreateObject("Shell.Application")
Set objWshShell = WScript.CreateObject("WScript.Shell")
Set objWshProcessEnv = objWshShell.Environment("PROCESS")
strCommandLine = Trim(objWshProcessEnv("ELEVATE_CMDLINE"))
objShell.ShellExecute "cmd", "/c " & strCommandLine, "", "runas"
</script></job>
:admin -----------------------------------------------------------
#echo off
echo Running as elevated user.
echo Script file : %~f0
echo Arguments : %*
echo Working dir : %cd%
echo.
:: administrator commands here
:: e.g., run shell as admin
%*
pause
I use it to create symbolic links like this:
Elevate.bat mklink /d common g:\PerforceData\devel\common
Elevate.bat mklink build.xml g:\PerforceData\devel\build.xml

Related

Is there an option to have score of UAC prompt?

I have this script that have goto getPrivileges, and this is useless coz it spams the whole time for UAC, Is there an option to make if you accepted UAC then does 1 thing and if you don't then another?
#echo off
:init
setlocal DisableDelayedExpansion
set "batchPath=%~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 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%"
echo UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
"%SystemRoot%\System32\WScript.exe" "%vbsGetPrivileges%" %*
goto getPrivileges
exit /B
I would want to have something like this.
if %UACError% == 0 echo You clicked yes on UAC!
if %UACError% == 1 echo You clicked no on UAC!
You shouldn't be doing goto getPrivileges after the launching of the vbs script.
As far as I understand, the content of the vbs script is just relaunching the current batch (!batchPath!) with elevated privileges.
So this relaunching will do :checkPrivileges and go to :gotPrivileges if the elevation was successful, and execute your task requiring elevation.
So for me, you can get rid of your last goto getPrivileges that generates an infinite loop.
To avoid this infinite loop, you can also wait for the vbs script to terminate like this:
start /WAIT "%SystemRoot%\System32\WScript.exe" "%vbsGetPrivileges%" %*
Concerning the result of the UAC, I think the code part inside :checkPrivileges is meant to test just that.
If this does not work, I found another way to check the privileges (here, in french) :
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if '%errorlevel%' NEQ '0' ( ...privilege... ) else ( ...no privilege... )
I didn't test it myself, though.

How to ask for admin permission in a batch?

Since a few weeks, my scripts for modifying my IP address don't work anymore. I suspect an update of Windows 10.
Up to now, I was using the script given in this thread :
#echo on
:: 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>
But now, I got this error:
Failed to load script: C:\Users\me\AppData\Local\Temp\getadmin.vbs: access denied
The strange thing is, getadmin.vbs is indeed created in the Temp directory.
Here is the exact output :
C:\Users\arc\Desktop\ConfigLAN>REM --> Check for permissions
C:\Users\arc\Desktop\ConfigLAN>IF "AMD64" EQU "amd64" ("C:\WINDOWS\SysWOW64\cacls.exe" "C:\WINDOWS\SysWOW64\config\system" 1>nul 2>&1 ) ELSE ("C:\WINDOWS\system32\cacls.exe" "C:\WINDOWS\system32\config\system" 1>nul 2>&1 )
C:\Users\arc\Desktop\ConfigLAN>REM --> If error flag set, we do not have admin.
C:\Users\arc\Desktop\ConfigLAN>if '5' NEQ '0' ( echo Requesting administrative privileges... goto UACPrompt ) else (goto gotAdmin ) Requesting administrative privileges...
C:\Users\arc\Desktop\ConfigLAN>echo Set UAC = CreateObject("Shell.Application") 1>"C:\Users\arc\AppData\Local\Temp\getadmin.vbs"
C:\Users\arc\Desktop\ConfigLAN>set params=
C:\Users\arc\Desktop\ConfigLAN>echo UAC.ShellExecute "cmd.exe", "/c ""C:\Users\arc\Desktop\CONFIG~1\newBatch.bat"" ", "", "runas", 1 1>>"C:\Users\arc\AppData\Local\Temp\getadmin.vbs"
C:\Users\arc\Desktop\ConfigLAN>"C:\Users\arc\AppData\Local\Temp\getadmin.vbs"
(error is triggered here)
C:\Users\arc\Desktop\ConfigLAN>del "C:\Users\arc\AppData\Local\Temp\getadmin.vbs"
C:\Users\arc\Desktop\ConfigLAN>exit /B
You can use the following sequence that works perfectly fine for me.
#echo off
::::::::::::::::::::::::::::::::::::::::::::
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' (goto gotPrivileges) else (goto getPrivileges)
:getPrivileges
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo For Each strArg in WScript.Arguments >> "%temp%\getadmin.vbs"
echo If strArg = WScript.Arguments.Item^(0^) Then d = Left^(strArg, InStrRev^(strArg,"\"^) - 1^) >> "%temp%\getadmin.vbs"
echo args = args ^& " " ^& strArg >> "%temp%\getadmin.vbs"
echo Next >> "%temp%\getadmin.vbs"
echo UAC.ShellExecute "cmd.exe", ^("/c start /D """ ^& d ^& """ /B" ^& args ^& " ^& exit"^), , "runas", 4 >> "%temp%\getadmin.vbs"
cscript "%temp%\getadmin.vbs" ""%~s0"" %*
del /q "%temp%\getadmin.vbs"
exit /b
:gotPrivileges
:: Your code here
This VBS script uses perfectly the UAC.ShellExecute, you can point by yourself the changes. You used a lot of tricks and the VBS code doesn't even call UAC in the correct way, which is why it gives permission denied. I believe that the use of cacls and this script was very useful in the past, used by Malware to obtain administrative access without the user's permission, there are many programs that use icacls for this, I will not even point out, but that may have made using icacls difficult.
You can also use Powershell previously to do it.
Powershell -Command "Start-Process cmd -Verb RunAs -ArgumentList '/c C:\YourPath\yourprogram.bat'"
Both of the scripts works perfectly fine for me. I can see a lot of errors in your .vbs, but there is no point in pointing them out because the script is not yours.
I recommend that you use the Powershell, it is much more useful and simple, to integrate:
NET FILE >NUL 1>NUL 2>NUL
if %errorlevel% equ 0 (goto gotprivileges) else (start Powershell -Command "Start-Process cmd -Verb RunAs -ArgumentList '/c C:\YourPath\yourprogram.bat'" & exit)
Hope this helps,
K.

How to create a shortcut by using windows command line

How can I create a shortcut for a folder by using windows command line
just use:
mklink <saveShortcutAs> <targetOfShortcut>
and you can find more options here:
https://technet.microsoft.com/en-us/library/cc753194.aspx
Give a try for this example to run it with administrator privileges :
#echo off
cls & color 0A & echo.
Mode con cols=60 lines=5
Title Create a shortcut by using windows command line
:::::::::::::::::::::::::::::::::::::::::
:: Automatically check & get admin rights
:::::::::::::::::::::::::::::::::::::::::
CLS
Echo.
Echo.
ECHO **************************************
ECHO Running Admin shell... Please wait...
ECHO **************************************
: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 **************************************
ECHO Invoking UAC for Privilege Escalation
ECHO **************************************
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
(
ECHO Set UAC = CreateObject^("Shell.Application"^)
ECHO args = "ELEV "
ECHO For Each strArg in WScript.Arguments
ECHO args = args ^& strArg ^& " "
ECHO Next
ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1
)> "%temp%\OEgetPrivileges.vbs"
"%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs" %*
exit /B
:gotPrivileges
if '%1'=='ELEV' shift /1
setlocal & pushd .
cd /d "%~dp0"
::::::::::::::::::::::::::::
::START
::::::::::::::::::::::::::::
cls
mklink /d sysfolder "%windir%\system32\"
Pause

Batch file - Run as administrator, if not delete batch file?

Hi I have made a batch file which I need to run as administrator. For that purpose I use this script, which I took from here (StackOverflow).
But what I want, is if the user choose not to run as administrator (click NO to UAC), then the program will exit, and the batch will delete it selves automatically.
The command for the batch file to delete it selves is "del %0", but I need help as to where in this script, I can put this command.
I tried to put it with "#exit /B", but then the batch file will delete if you press either YES or NO to UAC, and then the rest of the batch file cannot execute
Anybody can help figure out how to only run the command "del %0", when a user press "NO" to UAC?
#echo off
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )
:getPrivileges
if '%1'=='ELEV' (shift & goto gotPrivileges)
setlocal DisableDelayedExpansion
set "batchPath=%~0"
setlocal EnableDelayedExpansion
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
"%temp%\OEgetPrivileges.vbs"
#exit /B
:gotPrivileges
Thanks guys
Rune
If I understand your question, you need a way to detect if the UAC prompt was canceled. You can detect this if you use my Elevate32.exe or Elevate64.exe (download ElevationToolkit1.zip) program with the -w option, which will return an exit code of 1223 (ERROR_CANCELLED) if you cancel the UAC prompt.
Bill
I know it's an old question but it's still useful to have a solution posted.
If you have Powershell installed you don't need to create a new vbs script and the ERRORLEVEL can be checked to detect if the UAC prompt was canceled or not.
Just put this in your script:
#echo off
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges
) else ( powershell "saps -filepath %0 -verb runas" >nul 2>&1)
if NOT '%errorlevel%' == '0' call :deleteSelf
exit /b
:deleteSelf
start /b "" cmd /c del "%~f0"&exit /b
REM No need for this label
::getPrivileges
::if '%1'=='ELEV' (shift & goto gotPrivileges)
::setlocal DisableDelayedExpansion
::set "batchPath=%~0"
::setlocal EnableDelayedExpansion
::ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs"
::ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs"
::"%temp%\OEgetPrivileges.vbs"
::#exit /B
:gotPrivileges
The delete method I took from dbenham's post here

running a set up file in a batch as an admin?

I created a batch to run specific commands, the code looks like this:
cd D:\projects\Project Stress Test\signed one\com0com\x64
setupc
pause
what i want is to run the setupc file as an admin?
i tried runas /user:<Name>\administrator commands but it didnt work.
is there any easy way to do that?
You could make the entire script run at admin level. Here is a batch function I use in my scripts.
#echo off
call :Admin xReturn true 1
echo.%xReturn%
goto End
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Admin <Return> [Needed] [Success]
:: Check for Administrator privileges and request privileges if needed.
:: NOTE: This will restart the script with Admin privs if Needed is set to true.
:::: Usage: call :Admin xReturn true
:: Return success value, if user is Admin. Default `true` if Success not set.
setlocal
set xVBUAC=%Temp%\AdminUAC.vbs
set xSuccess=true
if not "%~3"=="" set xSuccess=%~3
:: Check for Access
::net session >nul 2>&1
>nul 2>&1 "%SystemRoot%\system32\cacls.exe" "%SystemRoot%\system32\config\system"
if %ErrorLevel% EQU 0 set xAdmin=%xSuccess%
:: Execute UAC
if /i not "%xAdmin%"=="%xSuccess%" if not "%~2"=="" if /i "%~2"=="true" (
echo Set UAC = CreateObject^("Shell.Application"^) > "%xVBUAC%"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%xVBUAC%"
if exist "%xVBUAC%" (
"%xVBUAC%"
rem if %ErrorLevel% EQU 5 echo Access Denied. Launching UAC.
del "%xVBUAC%"
)
)
endlocal & if not "%~1"=="" set "%~1=%xAdmin%"
goto :eof
:End

Resources