Sign in to follow this  
Followers 0
wraithdu

_IsUACAdmin - Check Admin and elevation rights

12 posts in this topic

#1 ·  Posted (edited)

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
2 people like this

Share this post


Link to post
Share on other sites



Just a small remark from me if I may... Magic sid strings you use are declared as constants inside SecurityConstants.au3.


♡♡♡

.

eMyvnE

Share this post


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

Share this post


Link to post
Share on other sites

Thanks all. I copied from a larger UDF and forgot the include. Fixing now.

Share this post


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

Share this post


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.

Share this post


Link to post
Share on other sites

Func _IsUACEnabled()
Return (RegRead("HKLMSOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem", "EnableLUA") = 1)
EndFunc ;==>_IsUACEnabled

Some backslashes have gone missing in the registry key. Thanks for all the hard work btw!

Share this post


Link to post
Share on other sites

Some backslashes have gone missing in the registry key. Thanks for all the hard work btw!

Huh, weird. Thanks, I've fixed the OP.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

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
1 person likes this

Share this post


Link to post
Share on other sites
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

Share this post


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
Sign in to follow this  
Followers 0

  • Similar Content

    • Darien
      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.
    • tcurran
      By tcurran
      Here's a short UDF that will, at least in most cases, detect whether a window can be copied from or pasted to programmatically--for example, by Send()ing ctl-c, ctl-v. This is often disabled when programs (like your AutoIt script) run at a lower UAC integrity level than the application they are trying to operate on.
      #include <WinAPI.au3> Func _WindowIsPasteable($handle) ;accepts window handle; returns true or false whether a window will accept Ctl-C, Ctl-V Local $bCanPaste = True Local $hTestWindowPID = 0 Local $hTestWindowTID = _WinAPI_GetWindowThreadProcessId($handle, $hTestWindowPID) _WinAPI_AttachThreadInput(_WinAPI_GetCurrentThreadId(), $hTestWindowTID, True);attach to window we want to paste into $bCanPaste = _WinAPI_GetFocus() ;Test whether window is paste-able--returns False if it is not _WinAPI_AttachThreadInput(_WinAPI_GetCurrentThreadId, $hTestWindowTID, False);detach from window thread Return $bCanPaste EndFunc Pass it a window handle; it returns true or false whether a window will accept programmatic pasting. The function may not work on the CMD window, since it handles the clipboard uniquely.
      This function works by attaching to the program thread of the window whose handle it receives, then attempting to perform a GetFocus on that thread. In most cases, the attempt will fail if the window will not accept programmatic copy-paste.
    • dreivilo47
      By dreivilo47
      When I use the following code I receive an UAC message:
       
      #RequireAdmin RunWait("msiexec /i winzip205-64.msi /quiet") Exit How can I hide (bypass) the UAC message?
    • VIP
      By VIP
      #RequireAdmin #include <WinAPISys.au3> #include <WindowsConstants.au3> _WinAPI_ChangeWindowMessageFilterEx ( $hWnd, $iMsg, $iAction ) ;_WinAPI_ChangeWindowMessageFilterEx( $hWnd, $WM_DROPFILES, $MSGFLT_ALLOW) ;_WinAPI_ChangeWindowMessageFilterEx( $hWnd, $WM_COPYDATA, $MSGFLT_ALLOW) ;_WinAPI_ChangeWindowMessageFilterEx( $hWnd, $WM_COPYGLOBALDATA, $MSGFLT_ALLOW) ; $WM_COPYDATA = 0x004A - $WM_DROPFILES = 0x0233 - $WM_COPYGLOBALDATA = 0x0049 - $MSGFLT_ALLOW = 1 - $MSGFLT_DISALLOW = 2 Example:
      #RequireAdmin Opt("TrayAutoPause", 0) #include <WinAPISys.au3> #include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <ButtonConstants.au3> Global $AppWindows = GUICreate("Dao Van Trong - Trong.CF", 320, 50, -1, -1, BitOR($WS_BORDER, $WS_POPUP), BitOR($WS_EX_ACCEPTFILES, $WS_EX_TOPMOST, $WS_EX_WINDOWEDGE)) Global $AppTitle = GUICtrlCreateLabel("=== Drag and drop UAC ===", 56, 0, 210, 25, $SS_CENTERIMAGE, $GUI_WS_EX_PARENTDRAG) GUICtrlSetState(-1, $GUI_DROPACCEPTED) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) GUICtrlSetFont(-1, 9, 800) Global $AppTask = GUICtrlCreateLabel("Drag and drop files here ", 56, 24, 220, 17, $SS_CENTERIMAGE, $GUI_WS_EX_PARENTDRAG) GUICtrlSetState(-1, $GUI_DROPACCEPTED) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) GUICtrlSetFont(-1, 9, 500) Global $xCLOSE = GUICtrlCreateButton("X", 308, 0, 12, 12, BitAND($BS_MULTILINE, $BS_VCENTER, $BS_FLAT)) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) GUICtrlSetState(-1, $GUI_DROPACCEPTED) GUISetState(@SW_SHOW) _WinAPI_ChangeWindowMessageFilterEx($AppWindows, $WM_DROPFILES, $MSGFLT_ALLOW) _WinAPI_ChangeWindowMessageFilterEx($AppWindows, $WM_COPYDATA, $MSGFLT_ALLOW) _WinAPI_ChangeWindowMessageFilterEx($AppWindows, $WM_COPYGLOBALDATA, $MSGFLT_ALLOW) Global $__aDropFiles GUIRegisterMsg($WM_DROPFILES, "WM_DROPFILES") Local $nMsg While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_DROPPED If $__aDropFiles[0] > 0 Then For $i = 1 To $__aDropFiles[0] ConsoleWrite($__aDropFiles[$i] & @CRLF) GUICtrlSetData($AppTask, $__aDropFiles[$i]) Next EndIf Case $GUI_EVENT_CLOSE, $xCLOSE Exit EndSwitch WEnd Func WM_DROPFILES($hWnd, $iMsg, $iwParam, $ilParam) #forceref $hWnd, $ilParam Switch $iMsg Case $WM_DROPFILES Local $aReturn = _WinAPI_DragQueryFileEx($iwParam) If IsArray($aReturn) Then $__aDropFiles = $aReturn Else Local $aError[1] = [0] $__aDropFiles = $aError EndIf EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_DROPFILES  
    • Jon
      By Jon
      I'm writing a set of PowerShell scripts/library for Windows 10 builds. One thing I often want to do is to browse to the location of a script that is part of a larger group of scripts and run it manually to do an install or make a one off change. So I like all my scripts to work well whether run from a task sequence or double-clicked in explorer.
      Most of my build scripts rely on having admin rights so I like to make them able to self-elevate if required - or at least give an error message. In PowerShell 4.0 (Windows 8.1) they added the #Requires -RunAsAdministrator statement but this won't do it for you - it just causes the script to abort if not admin. 
      Below is a PowerShell script that does the following:
      Checks for admin rights using the Test-IsAdmin function If not admin: Get the full script path and working directory using the Get-UNCFromPath function If the paths are mapped drives then get the UNC version (drive mappings are lost when elevating from user to admin in most configurations) Execute PowerShell.exe with the UNC path of the script and the RunAs verb to trigger elevation. ExecutionPolicy is also set to Bypass on the command line. The working directory is also set to the UNC path version. Waits for the new process to finish, and captures its return code Exits using the same return code Script is as follows:
      # Test if admin function Test-IsAdmin() { # Get the current ID and its security principal $windowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent() $windowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($windowsID) # Get the Admin role security principal $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator # Are we an admin role? if ($windowsPrincipal.IsInRole($adminRole)) { $true } else { $false } } # Get UNC path from mapped drive function Get-UNCFromPath { Param( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [String] $Path) if ($Path.Contains([io.path]::VolumeSeparatorChar)) { $psdrive = Get-PSDrive -Name $Path.Substring(0, 1) -PSProvider 'FileSystem' # Is it a mapped drive? if ($psdrive.DisplayRoot) { $Path = $Path.Replace($psdrive.Name + [io.path]::VolumeSeparatorChar, $psdrive.DisplayRoot) } } return $Path } # Relaunch the script if not admin function Invoke-RequireAdmin { Param( [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [System.Management.Automation.InvocationInfo] $MyInvocation) if (-not (Test-IsAdmin)) { # Get the script path $scriptPath = $MyInvocation.MyCommand.Path $scriptPath = Get-UNCFromPath -Path $scriptPath # Need to quote the paths in case of spaces $scriptPath = '"' + $scriptPath + '"' # Build base arguments for powershell.exe [string[]]$argList = @('-NoLogo -NoProfile', '-ExecutionPolicy Bypass', '-File', $scriptPath) # Add $argList += $MyInvocation.BoundParameters.GetEnumerator() | Foreach {"-$($_.Key)", "$($_.Value)"} $argList += $MyInvocation.UnboundArguments try { $process = Start-Process PowerShell.exe -PassThru -Verb Runas -Wait -WorkingDirectory $pwd -ArgumentList $argList exit $process.ExitCode } catch {} # Generic failure code exit 1 } } # Relaunch if not admin Invoke-RequireAdmin $script:MyInvocation # Running as admin if here $wshell = New-Object -ComObject Wscript.Shell $wshell.Popup("Script is running as admin", 0, "Done", 0x1) | Out-Null