Jaa


How to detect UAC elevation from VBScript

While working on the next version of HVRemote yesterday evening, one of the things I wanted to address based on feedback from various people was to have the tool (written in VBScript) detect whether it is being run from an elevated command prompt. While this is relatively easy to determine using low-level languages from the GetTokenInformation API, this is not callable from VBScript without a helper. I couldn't find a pre-existing COM object in Windows Vista or Windows Server 2008 which indirectly exposed this API, or anything built in to the Windows Scripting Host. As I didn't want to ship HVRemote with a separate helper binary, I had to go digging for an alternate solution.....).

The one thing I didn't want to do was to have the script try to do something active which might (or might not) work, returning some form of permission denied in the failure case. I wanted something passive. I discovered the whoami command displays the System Manadatory Label. So, if you can see where this is heading, although this can be classified as a "glorious hack", it's straight-forward to passively determine elevation through examining the output of whoami /all (or whoami /groups which is a little more terse and still gives the information we need). All you need to know is the SID strings for integrity levels.

I also discovered an interesting thing about the Exec method of the Windows Scripting Host along the way, which certainly bemused me for a while. I drew a blank on it from Internet searching too. It appears that if the command being "Exec"'d has a lot of output (such as whoami /all), unless StdOut is drained, Exec blocks indefinitely. You learn something new every day :)

Here's the sample script - save it as elevated.vbs and run as "cscript elevated.vbs". I've stripped the sample code down to a bare minimum to just demonstrate the logic - you should add the appropriate error handling if you take advantage of it in your own scripts. (Or download here and rename to a .vbs extension)

 Dim oShell, oExec, szStdOut
 szStdOut = "" 
 Set oShell = CreateObject("WScript.Shell")
 Set oExec = oShell.Exec("whoami /groups")
  
 Do While (oExec.Status = cnWshRunning) 
    WScript.Sleep 100
    if not oExec.StdOut.AtEndOfStream then
        szStdOut = szStdOut & oExec.StdOut.ReadAll
    end if
 Loop
  
 select case oExec.ExitCode
    case 0
        if not oExec.StdOut.AtEndOfStream then
            szStdOut = szStdOut & oExec.StdOut.ReadAll                   
        end if
  
        if instr(szStdOut,"S-1-16-12288") Then 
            wscript.echo "Elevated"
        else
            if instr(szStdOut,"S-1-16-8192")  Then 
                wscript.echo "Not Elevated"
            else
                wscript.echo "Unknown!"
            end if
        end if
    case else
        if not oExec.StdErr.AtEndOfStream then 
            wscript.echo oExec.StdErr.ReadAll
        end if
 end select

elevated

Not Elevated

Hope someone finds this snippet useful, but as always, see my blog disclaimer.

Cheers,
John.