Jump to content

_IsUACAdmin - Check Admin and elevation rights


Recommended Posts

I found a few related topics for some reference:

Basically the issue has always been how to interpret and work with the results of IsAdmin() when running under UAC, and the desire for developers to not force the use of #RequireAdmin (or the AutoIt3Wrapper manifest equivalent) for all of their users. A lot of programs have that nice 'Elevate' button which is presented to you when the function is available, to selectively elevate the application and enable administrative functions. Here's my attempt at detecting this scenario.

The function will return the current admin status, and the ability of the current app to elevate itself under UAC in @extended. A small example should show how it is used. The example can be run from SciTE or compiled, allowing you to test all kinds of scenarios.

Something interesting I found... if an app is launched from another fully elevated app, and that new app is launched with restricted privileges by way of the SAFER api, then that app CANNOT re-elevate itself to full admin status. The other way to lower a launched app's privileges uses either CreateProcessAsUser or CreateProcessWithTokenW (there are scripts on the forum that show their usage). Apps launched with either of those functions CAN re-elevate themselves to full admin status.

_IsUACAdmin

#include <Security.au3>

; #FUNCTION# ====================================================================================================================
; Name ..........: _IsUACAdmin
; Description ...: Determines if process has Admin privileges and whether running under UAC.
; Syntax ........: _IsUACAdmin()
; Parameters ....: None
; Return values .: Success          - 1 - User has full Admin rights (Elevated Admin w/ UAC)
;                  Failure          - 0 - User is not an Admin, sets @extended:
;                                   | 0 - User cannot elevate
;                                   | 1 - User can elevate
; Author ........: Erik Pilsits
; Modified ......:
; Remarks .......: THE GOOD STUFF: returns 0 w/ @extended = 1 > UAC Protected Admin
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _IsUACAdmin()
    ; check elevation
    If StringRegExp(@OSVersion, "_(XP|20(0|3))") Or (Not _IsUACEnabled()) Then ; XP, XPe, 2000, 2003 > no UAC
        ; no UAC available or turned off
        If IsAdmin() Then
            Return SetExtended(0, 1)
        Else
            Return SetExtended(0, 0)
        EndIf
    Else
        ; check UAC elevation
        ;
        ; get process token groups information
        Local $hToken = _Security__OpenProcessToken(_WinAPI_GetCurrentProcess(), $TOKEN_QUERY)
        Local $tTI = _Security__GetTokenInformation($hToken, $TOKENGROUPS)
        _WinAPI_CloseHandle($hToken)
        ;
        Local $pTI = DllStructGetPtr($tTI)
        Local $cbSIDATTR = DllStructGetSize(DllStructCreate("ptr;dword"))
        Local $count = DllStructGetData(DllStructCreate("dword", $pTI), 1)
        Local $pGROUP1 = DllStructGetPtr(DllStructCreate("dword;STRUCT;ptr;dword;ENDSTRUCT", $pTI), 2)
        Local $tGROUP, $sGROUP = ""
        ;
        ; S-1-5-32-544 > BUILTINAdministrators > $SID_ADMINISTRATORS
        ; S-1-16-8192  > Mandatory LabelMedium Mandatory Level (Protected Admin) > $SID_MEDIUM_MANDATORY_LEVEL
        ; S-1-16-12288 > Mandatory LabelHigh Mandatory Level (Elevated Admin) > $SID_HIGH_MANDATORY_LEVEL
        ; SE_GROUP_USE_FOR_DENY_ONLY = 0x10
        ;
        ; check SIDs
        Local $inAdminGrp = False, $denyAdmin = False, $elevatedAdmin = False, $sSID
        For $i = 0 To $count - 1
            $tGROUP = DllStructCreate("ptr;dword", $pGROUP1 + ($cbSIDATTR * $i))
            $sSID = _Security__SidToStringSid(DllStructGetData($tGROUP, 1))
            If StringInStr($sSID, "S-1-5-32-544") Then
                ; member of Administrators group
                $inAdminGrp = True
                ; check for deny attribute
                If (BitAND(DllStructGetData($tGROUP, 2), 0x10) = 0x10) Then $denyAdmin = True
            ElseIf StringInStr($sSID, "S-1-16-12288") Then
                $elevatedAdmin = True
            EndIf
        Next
        ;
        If $inAdminGrp Then
            ; check elevated
            If $elevatedAdmin Then
                ; check deny status
                If $denyAdmin Then
                    ; protected Admin CANNOT elevate
                    Return SetExtended(0, 0)
                Else
                    ; elevated Admin
                    Return SetExtended(1, 1)
                EndIf
            Else
                ; protected Admin
                Return SetExtended(1, 0)
            EndIf
        Else
            ; not an Admin
            Return SetExtended(0, 0)
        EndIf
    EndIf
EndFunc   ;==>_IsUACAdmin

Func _IsUACEnabled()
    Return (RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", "EnableLUA") = 1)
EndFunc   ;==>_IsUACEnabled

Example

#include <_IsUACAdmin.au3>
#include <GuiButton.au3>
#include <GuiConstantsEx.au3>

$g = GUICreate("UAC Test", 200, 100)
$b = GUICtrlCreateButton("Elevate", 200-72, 100-27, 70, 25)
_GUICtrlButton_SetShield($b)
$admin = _IsUACAdmin()
$canelevate = @extended
GUICtrlCreateLabel("IsAdmin (built-in): " & (IsAdmin() = 1), 4, 4)
GUICtrlCreateLabel("_IsUACAdmin (full admin): " & ($admin = 1), 4, 24)
GUICtrlCreateLabel("Process can elevate: " & ($canelevate = 1), 4, 44)
If $admin Or (Not $canelevate) Then GUICtrlSetState($b, $GUI_DISABLE)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case -3
            ExitLoop
        Case $b
            ; restart elevated
            If @Compiled Then
                ShellExecute(@ScriptFullPath, "", @WorkingDir, "runas")
            Else
                ShellExecute(@AutoItExe, '/AutoIt3ExecuteScript "' & @ScriptFullPath & '"', @WorkingDir, "runas")
            EndIf
            Exit
    EndSwitch
WEnd
Edited by wraithdu
Link to post
Share on other sites

Also, your code is missing the line:

#include <Security.au3>

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to post
Share on other sites

here's another way:

;we use this instead of "isadmin" because isadmin won't be able to check if UAC is enabled.

$oWMIService = ObjGet("winmgmts:" & @ComputerName & "rootcimv2")
$colItems = $oWMIService.ExecQuery("Select * From Win32_Group Where LocalAccount = TRUE And SID = 'S-1-5-32-544'")
For $oItem in $colItems

Next

if $oItem.Name = "administrators" Then
Call("admin")
Else
call("notadmin")
EndIf


func admin()
;some code
EndFunc

func notadmin()
;some code
EndFunc
Link to post
Share on other sites

sigh

Your method does not provide the desired information and functions the same as IsAdmin(). The whole point of this is that IsAdmin() doesn't give you everything you need when running under UAC. Additionally relying on WMI is not an ideal solution. Please keep alternatives in your own threads.

Link to post
Share on other sites
  • 3 months later...
  • 1 month later...

Hello all!

First, I'd like to say that I've enjoyed AutoIT for quite several years now. Due to the excellent topics or the forums, I've never had to ask a question. However, this UAC stuff seems a little complex...

The code in the script above is a little above my head. What would I need to change/edit to take out the gui so that it only prompts to elevate if necessary?

Thanks in advance,

Chris

Link to post
Share on other sites
  • 8 months later...

This stopped working for me on my work machine and the problem appears to be that I have UAC enabled without having the registry key set.

i.e.

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA

Does not exist but I'm still using UAC. I can only imagine this is because UAC is set through Group Policy or something.

I have worked round this by adding the key which is fine for my purposes.

Edited by hutchinsfairy
Link to post
Share on other sites
  • 9 months later...
  • 6 months later...
This is interesting to me as it finds if the script can run with admin rights "if at all"
just setting #RequireAdmin doesn't assure the scriptprogram can run properly(Elevated) if it necessarily needs admin rights
right ?
but how can I add a routin that if a user cannot be elevated to set a prompt to run as AdminUser ? Password ? (as required)
and test if the elevation took place so then commands can continue
or get some output if the user can use or run runas at-all
since I didn't play around UAC and Admin accounts I'm not fully aware of the possibilities 
 
thanks
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Doniel
      Hi there! 😃
      I've 2 simple scripts:
      Script 1 starts script 2 Script 1 gets executed with normal user rights (un-elevated) Script 2 contains an #RequireAdmin and therefor can only start elevated I want to read the output of script 2 with script 1 AND have the UAC of script 2 being activated as fullscreen Script 1 (Scripts location is the same as script 2 that I'm running with Run()
      Local $iPID, $sOutput $iPID = Run(@ComSpec & " /c " & "C:\Entwicklung\Autoit\Test\Temp.exe", @ScriptDir, @SW_HIDE, 0x2) ProcessWaitClose($iPID) $sOutput = StdoutRead($iPID) StdioClose($iPID) ConsoleWrite($sOutput) MsgBox(1, 1, 1) Script 2 (compiled as Temp.exe)
      #RequireAdmin ConsoleWrite("Return") MsgBox(1,1,"ADMIN") Now my problems are the following:
      Without the #RequireAdmin I can read the output with no problem, but not with the #RequireAdmin ($sOutput is empty) Using @SW_HIDE in the Run() command makes the UAC always start minimized (see attached picture) and the admin has to always manually click on the icon to enter his credentials since the UAC doesn't start in fullscreen. Here and on a few other sites they explain that the program launching the elevated program NEEDS to be activated in order to directly show the UAC fullscreen and not minimized. Using @SW_SHOW would get rid of the problem, BUT that leaves me with an ugly cmd.exe floating the whole time while the elevated script ist running. And my questions to that I'm seeking an answer for are:
      Problem 1: Is it just not possible to read from an elevated program with an un-elevated user/script? I also get the Access Denied if I press No on the UAC as an Output in $sOutput (Guess since its's still un-elevated) Problem 2: Is there a way to either make the floating black and blank cmd.exe being moved to the background and be non visible to the user OR to somehow bring the minimized UAC to the foreground/fullscreen? What I already tried and what didn't help me:
      $iPID = Run(@ComSpec & " /c " & "C:\Entwicklung\Autoit\Test\Temp.exe", @ScriptDir, @SW_HIDE, 0x2) While Not WinExists("Temp.exe erfordert Ihre Berechtigung") ConsoleWrite(1) WEnd WinActivate("Temp.exe erfordert Ihre Berechtigung") WinSetState("Temp.exe erfordert Ihre Berechtigung", WinGetText("Temp.exe erfordert Ihre Berechtigung"), @SW_SHOW) WinSetState("Temp.exe erfordert Ihre Berechtigung", WinGetText("Temp.exe erfordert Ihre Berechtigung"), @SW_MAXIMIZE) WinSetState("Temp.exe erfordert Ihre Berechtigung", WinGetText("Temp.exe erfordert Ihre Berechtigung"), @SW_ENABLE) The While-Loops helps a lot and also stops after a second or so (► Stops to write ones (1)). That means that the actual "window" of the UAC is found, but all the WinXXX functions don't do anything and the UAC stays minimized. I also tried to minimized/move the cmd.exe to the background with WinActivate() and WinSetState() with no success.
      $iPID = ShellExecute("C:\Entwicklung\Autoit\Test\Temp.exe", "", @ScriptDir, "open", @SW_HIDE) Using ShellExecute() instead of Run() completely solves the UAC to fullscreen problem BUT I haven't found a consistent way to read the output of ShellExecute(). Neither here on the forum nor somewhere else. If I'd be possible to read the output from ShellExecute() then all my problems would be solved at once!
      Also tried a few more things and playing with some parameters but everything with no success.
      I'd really love some help and support here from you.
      Thanks in advance!
       

    • By rudi
      Hi,
      When a non compiled AU3 script is run with #RequireAdmin, then if the UAC prompt can be authorized due to the fact, that the currently loggedon user has local admin rights, then the macro @UserProfileDir correctly reflects the profile dir of the user of the windows logon session.
       
      When the script with #RequireAdmin is started by a "normal user" without local admin rights, and I use a domain admin account to authorize the UAC prompt, then @UserProfileDir reflects the profile dir belonging to the AD-Admin account.
      As the script originally was started using the "regular user" I'm wondering, if there is a chance to "pass" the original user's @UserProfileDir to the UAC elevated script?
       
      As playing around with this feature I realize, that I basically don't know the exact mechanism of the UAC elevation authorization process:
      The script is started by right mouse click, execute script This is invoking e.g. "C:\Program Files (x86)\AutoIt3\AutoIt3.exe" "C:\Users\Rudi\Desktop\test.au3" as by this registy value: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\AutoIt3Script\Shell\Run\Command] @="\"C:\\Program Files (x86)\\AutoIt3\\AutoIt3.exe\" \"%1\" %*" But what I honestly don't know is, how does the UAC propt interact in the program startup? I guess, that Autoit3.exe is parsing the AU3 source, is seeing the #RequireAdmin and then "relaunches itself with the AU3 as %1" requesting UAC elevated rights "from windows"??? With Process Explorer I can see, that The commandline then is this one with a "!" before "%1"
      "C:\Program Files (x86)\AutoIt3\AutoIt3.exe" !"C:\Users\Rudi\Desktop\test.au3"  It it should be something like this, then it might be possible to pass the original @UserProfileDir to the second, UAC elevated "Startup"??? <edit>
      I just noticed:
      When I use "WIN+R" and then directly use the command line, I see in Process Explorer, ...
      "C:\Program Files (x86)\AutoIt3\AutoIt3.exe" !"C:\Users\Rudi\Desktop\test.au3"
      ... then this script with #RequireAdmin is started *WITHOUT* UAC elevation.
      Guessing, that this ! is just reverting #RequireAdmin I tried the "opposite" one as well:
      AU3 script without #RequireAdmin Starting with "C:\Program Files (x86)\AutoIt3\AutoIt3.exe" !"C:\Users\Rudi\Desktop\test.au3" does not invoke UAC elevation prompt. So to me it looks like, this ! is a "status flag from Autoit3.exe to Autoit3.exe", that the elevation process was done already? amazing...
      the topic Autoit on Windows Vista is telling no details of  this UAC process...
      </edit>
       
      Regards, Rudi.
    • By damon
      Hello,
      You guys helped me years ago to address logging in with a different account than the user.  I have sense modified it over the years due to laptops syncing with AD which is why you will see 3 different passwords.  So, this script snippet has worked for me in many things i have written but I am all the sudden having an issue getting it to work.  I have verified that the password i am using for the local user account is $pass.  Verified by doing a run as different user on Chrome and cut and pasted the password out of the script just to make sure i was not fat fingering something.  
      I get a fail back from RunAs every time.   
      Any chance you guys see something i am doing wrong?
       
      #include <MsgBoxConstants.au3> #include <WinAPIFiles.au3> ;#RequireAdmin If $CmdLine[0] > 0 Then If $CmdLine[1] = "/Install" Then RunUpdate() Exit EndIf ;;Will check users account to determine if admin, if not will Run with admin rights -------------------------------------------------------------- ;;Varables Start Local $user = ".\user" Local $pass = "password1" Local $pass2 = "password2" Local $pass3 = "password3" Local $filetorun = @ScriptFullPath & " /Install" ;;Varables End If IsAdmin () = 0 Then If RunAs ( $user, @CompterName, $pass, $RUN_LOGON_NOPROFILE,$filetorun) = 0 Then ;If RunAs ( $user, @ComputerName, $pass2, 0,$filetorun) = 0 Then ;If RunAs ( $user, @ComputerName, $pass3, 0,$filetorun) = 0 Then ;MsgBox (0,"Installation Error", "This installation was interrupted due to an incorrect Admin Password") ;Exit ;EndIf ;EndIf EndIf Exit Else Run ($filetorun) EndIf Func RunUpdate() MsgBox(0,"worked","worked") EndFunc
    • By griefman
      Hi everyone,
      i am writing to you after a very long struggle i had while trying to figure out how to send a simple click inside a virtual machine running in vmware workstation 14.
      i have an autoit script running on my host machine watching for the UAC prompt to be displayed in a running vm. Both the host and the guest OS are Windows 10. This script worked perfectly with virtual box. It recognized the UAC prompt and clicked inside and the UAC was accepted. Since i switched to VMware Workstation 14, the script no longer clicks inside the VM successfully. It acts as if it clicks, but it doesn't. 
      I tried sending key combinations instead of a click, so that the VM can grab the input, but it also did not work. Every attempt that i made to send clicks or keys from the host inside the VM did not work. I tried using:
      MouseClick
      ControlClick
      MouseMove
      _WinAPI_Mouse_Event
      _WinAPI_Keybd_Event
       
      I also noticed that while the cursor moves to the target which has to be cilcked when my vmware worstation window is not focused, it even doesn't do that when i WinActivate the vmware workstation window first.
       
      Did anyone experience such an issue, or maybe could give me a hint, what else i could use to send a key combination or a mouse click in a vmware workstation 14 pro guest window?
       
      here is my code, which works with virtualbox:
       
      #AutoIt3Wrapper_Icon=".\uac.ico" #include <ImageSearchSubrogated.au3> FileInstall(".\ImageSearchDLL.dll", ".\ImageSearchDLL.dll", 0) FileInstall(".\UAC_ginloSetup.bmp", ".\UAC_ginloSetup.bmp", 0) FileInstall(".\UAC_Yes.bmp", ".\UAC_Yes.bmp", 0) ; set global variables for the coordinates, which should be delivered global $x1 = 0, $y1 = 0 global $x2 = 0, $y2 = 0 global $counter1 = 0 global $counter2 = 0 global $sleep = 10000 global $smallSleep = 5000 ; execute the script in a loop, so that it will hopefully recover from some unexpected errors While $counter1 < 1 checkForImage() WEnd #cs ------------ Functions #ce ------------ Func checkForImage() While $counter2 < 1 ; search for the UAC in the entire screen - 2 screens supported local $searchUac = _ImageSearchArea('UAC_ginloSetup.bmp', 1, -2568, -8, 5136, 1440, $x1, $y1, 0) If $searchUac = 1 Then ; if the UAC was found search for the Yes button in a an area 200 x 200 from the middle of the found UAC image local $searchYes = _ImageSearchArea('UAC_Yes.bmp', 1, $x1, $y1, $x1 + 200, $y1 + 200, $x2, $y2, 0) If $searchYes = 1 Then ; if the Yes button was found click it and pause the script for $sleep seconds MouseClick("left", $x2, $y2, 1,0) Sleep($sleep) Else ; if the Yes button was not found retry from the beginning in $smallSleep seconds MsgBox(0, "UAC found error", "UAC was found but the 'Yes' button was not found. Script will retry in " & $smallSleep & " seconds.", $smallSleep) EndIf ; another way to accept the UAC - via shortcut ;Send("{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}") ;Send("!y") Else ; if UAC was not found try again in $sleep seconds Sleep($sleep) EndIf WEnd ; if some error occured which expired the loop, pause the script for $sleep seconds MsgBox(0, "Error", "Some Error expired the timer and the script could not recover. The script will restart in " & $sleep & " seconds.", $sleep) EndFunc  
    • By Darien
      Hello,
       
      How to know if a script was run as administrator? (right-click and choose "run as administrator")
       
      The "Isadmin" command only shows whether the logged account has administrator rights.
×
×
  • Create New...