Rob van der Woude's Scripting Pages

Check and Set Elevated Privileges

Ever since Windows Vista, UAC (User Account Control) will prompt for confirmation and/or the administrator password when programs require administrator privileges (a.k.a. elevated privileges).

In scripts, more than one command may require elevated privileges, leading to repeated UAC prompts in a single script.
To avoid this, scripts can be started themselves with elevated privileges, so there will be only one single UAC prompt.
This web page discusses some techniques to check if the script is started with elevated privileges or not, and a technique to restart a script with elevated privileges if it wasn't

Note: Many if not most of these techniques were submitted by visitors of this site, and have been published before on my More Clever Tips and Tricks page.

Check Elevation in Batch Files

To make a batch file check if it is running with elevated privileges, a commonly used technique is to just try and start a command (like AT or OPENFILES) that requires elevated privileges, and check the Errorlevel:

AT >NUL 2>&1
IF ERRORLEVEL 1 (
	ECHO This batch file requires elevated privileges
	EXIT /B 1
)

Nowadays, AT is not recommended, as it requires the Windows Scheduler service to run, which is no longer the case on most systems.
OPENFILES is a commonly used replacement:

OPENFILES >NUL 2>&1
IF ERRORLEVEL 1 (
	ECHO This batch file requires elevated privileges
	EXIT /B 1
)

Note that in 64-bit Windows versions OPENFILES is a 64-bit executable, and it will not run in a 32-bit process.
OPENFILES not running means FIND will return an Errorlevel 1, making the batch file terminate whether it runs with elevated privileges or not.

Batch files requiring elevated privileges will rarely be run in a 32-bit process in 64-bit Windows, with the possible exception of temporary batch files created "on-the-fly" by other scripts.
I once had to debug an HTA that required elevated privileges, and used OPENFILES to check.
It kept prompting me for elevated privileges regardless whether it had elevated privileges or not.
It turned out to be running as a 32-bit process in 64-bit Windows.

 

Note: To determine if a batch file runs in a 32-bit process in 64-bit Windows, check the environment variables PROCESSOR_ARCHITECTURE and PROCESSOR_ARCHITEW6432:

If Then
PROCESSOR_ARCHITEW6432 is set (equals AMD64) 32-bit process in 64-bit Windows
PROCESSOR_ARCHITECTURE equals AMD64 or PROCESSOR_ARCHITEW6432 equals AMD64 64-bit Windows
PROCESSOR_ARCHITECTURE equals x86 32-bit process

or:

  Windows
32-bit 64-bit
Process 32-bit PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=AMD64
64-bit N/A PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_ARCHITEW6432=

or:

SET PROCESSOR_ARCHITE | FIND "x86"   && ECHO This is a 32-bit process
SET PROCESSOR_ARCHITE | FIND "AMD64" && ECHO This is a 64-bit Windows


More details can be found on David Wang's blog.

 

So far, we tested for elevated privileges by running an executable that requires elevated privileges to run.
The following executable doesn't require elevated privileges, but the task we ask it to perform does:

CACLS "%SYSTEMROOT%\system32\config\system"
IF ERRORLEVEL 1 (
	ECHO This batch file requires elevated privileges
	EXIT /B 1
)

This allows us to check if the executable is available (it should, on "modern" systems), so we can be certain that errorlevel 1 really means that there are no elevated privileges.
Especially when used in enterprise environments, with restricted privileges, it won't hurt to perform an extra check if our test executable is available at all.

The following command will always correctly detect if the script runs with elevated privileges, regardless of "bittedness" (in Windows 7 and later, not sure about Vista):

WHOAMI /Groups | FIND "12288" >NUL
IF ERRORLEVEL 1 (
	ECHO This batch file requires elevated privileges
	EXIT /B 1
)

 

Check Elevation in VBScript

In VBScript, elevation is usually checked using the same external commands used in batch files:

Set wshShell = CreateObject( "WScript.Shell" )
Set objExec  = wshShell.Exec( "OPENFILES" )
strResult = objExec.StdOut.ReadAll( )
intResult = objExec.ExitCode
Set objExec  = Nothing
Set wshShell = Nothing
If intResult = 0 Then
	WScript.Echo "This process has elevated privileges"
Else
	WScript.Echo "This process does NOT have elevated privileges"
End If

Try running the script with %windir%\SysWOW64\cscript.exe in 64-bit Windows: it will tell you it has no elevated privileges, even if it does have them.
The reason is that in 64-bit Windows a 32-bit process cannot run 64-bit OPENFILES.

Note: Even though strResult seems obsolete in the example above, it is still required: (limited) testing revealed that objExec.ExitCode will not be set if objExec.StdOut is not read.

WHOAMI may be a safer bet:

Set wshShell = CreateObject( "WScript.Shell" )
Set objExec  = wshShell.Exec( "WHOAMI /Groups" )
strResult = objExec.StdOut.ReadAll( )
intResult = objExec.ExitCode
Set objExec  = Nothing
Set wshShell = Nothing
If InStr( strResult, "12288" ) Then
	WScript.Echo "This process has elevated privileges"
Else
	WScript.Echo "This process does NOT have elevated privileges"
End If

It will correctly tell you if the script has elevated privileges or not, regardless of matching "bittedness" of OS and process.

 

Check Elevation in PowerShell

As we saw before, batch files and VBScript require workarounds to check for elevated privileges.
In PowerShell, however, elevation can be truly and properly checked with the following code, provided by Denis St-Pierre:

$currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent( ) )
if ( -not ($currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ) ) )
{
	Write-Error "This script must be executed in admin mode." -ErrorAction Stop
}

 

Set Elevation

Evan Greene demonstrated a technique to set (or actually: prompt for...) elevated privileges if necessary in his BatchGotAdmin page.

The core to this technique is the following temporary VBScript code, created on-the-fly, where "%~s0" is the batch file's (short) path:

Set UAC = CreateObject( "Shell.Application" )
UAC.ShellExecute "%~s0", "", "", "runas", 1

This script is started only if required, and after running it the calling batch file will be aborted.
The (temporary) script restarts the batch file ("%~s0") with elevated privileges ("runas").

You may want to extend the second line of the temporary script to take into account (batch) command line arguments ("%*") and batch files not running in the current directory ("%~snx0" and "%~sdp0"):

UAC.ShellExecute "%~snx0", "%*", "%~sdp0", "runas", 1

Check the Shell.ShellExecute reference for more details.

Note: If the script is restarted with elevated privileges, it will run in a new process.
Any variables set in the script so far are lost, so make sure the test for elevation and optional restart is the first thing the script does.
You may also want to limit the number of restarts/retries, in case the user just doesn't have the credentials required for elevated privileges.

Credits

Thanks for Denis St-Pierre, Aaron Thoma and Kevin Ridenhour for their contributions, and David Wang and Evan Greene for the information provided on their website and blog.

 


page last uploaded: 2016-09-19, 14:56