Jump to content

Setting ACLs using alternate credentials

Recommended Posts


I've been using this UDF to set ACL permissions to some network folders, everything works great (no issues). However, I want to apply these permissions using elevated domain credentials supplied by the user and not the user that's currently running the script. As a temporary solution, I've implemented a RunAs function, but that's not the solution I'm looking for. I'm not fluent with using Dlls, but I have been trying out different methods.

My RunAs Function:

Func _RunAs($sUser, $sPass)
    If @Compiled Then
        RunAs($sUser, @LogonDomain, $sPass, 4, FileGetShortName(@ScriptFullPath), "", @SW_MAXIMIZE)
        RunAs($sUser, @LogonDomain, $sPass, 4, FileGetShortName(@AutoItExe) & " " & FileGetShortName(@ScriptFullPath), "", @SW_MAXIMIZE)
EndFunc   ;==>_RunAs

I tried LogonUser and I know that I can take that token to ImpersonateLoggedOnUser, but I'm not sure how to implement that or if that's even the right method. I also need to RevertToSelf once completed.

Func _LogonUser($sUsername, $sPassword, $sServer = @LogonDomain) ; Returns True if user exists
    Local $stToken

    $stToken = DllStructCreate("int")
    Local $aRet = DllCall("advapi32.dll", "int", "LogonUser", _
            "str", $sUsername, "str", $sServer, "str", $sPassword, "dword", 3, "dword", 0, "ptr", DllStructGetPtr($stToken))
    ;$hToken = DllStructGetData($stToken, 1)
    If Not @error And $aRet[0] <> 0 Then
        Return True
    Return False
EndFunc   ;==>_LogonUser

Any assistance, suggestions or idea's would be helpful.


Link to post
Share on other sites

 RunAs or RunAsWait does not give you full admin rights (Admin Token), even if the user has admin right on the PC.  One workaround you have is to use re-execution.  Have a look at this thread for an example.  You could also create another script that uses #RequireAdmin, but I prefer re-execution.  

Here is a more customized script for what I think you are trying to do,  it uses RunAsWait and ShellExecuteWait.  

Global $sAdminUser = "USERNAME"
Global $sAdminPassword = "PASSWORD"
Global $sDomain = @LogonDomain
Global $iLogOnFlag = 0
Global $sParameters = ""

;Run as the Admin account.
If @UserName <> $sAdminUser And Not IsAdmin() Then
    $sParameters = ""
    If Not @Compiled Then
        $sParameters = ' "' & @ScriptFullPath & '"'
    ;Use RunAsWait to run as AdminUser, to continue the script as the user that started it, and to wait for the Admin part to Finish.
    RunAsWait($sAdminUser, $sDomain, $sAdminPassword, $iLogOnFlag, @AutoItExe & $sParameters)
    If @error Then Exit MsgBox(16 + 262144, "ERROR!", "Unable to run under administrator account.")

;Request the Admin Token for the Admin account in Windows Vista and Higher.
If @UserName = $sAdminUser And Not IsAdmin() And Not StringRegExp(@OSVersion, "_(XP|200(0|3))") Then
    $sParameters = ""
    If Not @Compiled Then
        $sParameters = '"' & @ScriptFullPath & '"'
    ;Use ShellExecuteWait to run as AdminUser with Admin Token, to wait for the Admin part of the script to finish, and then to exit.
    ShellExecuteWait(@AutoItExe, $sParameters, "", "runas")
    If @error Then Exit MsgBox(16 + 262144, "ERROR!", "Unable to elevate to Admin due to UAC.")

MsgBox(16, @UserName, "Is " & (IsAdmin() ? "" : "Not " ) & "Admin") ;Example

;Admin part of script.
If IsAdmin() Then 
    MsgBox (0, "Admin Run Test", "Run Admin part of script and then exit to run as user who started the script.") ;Example
    ;Exit to finish Admin part of script.

;Put rest of the non Admin part of script here.

If you have any questions, please let me know.  



Link to post
Share on other sites

Hey @AdamUL, I really appreciate your response and customized script. I read through your posts and it helped me a lot to understand the process. However, with my script I'm already using #RequireAdmin and my goal was to not to use re-execution (if possible). Luckily, after days of researching I was able to find the solution I was looking for.

I copied and modified an already existing function from this post: 


Hopefully, I've done this correctly but please correct me if needed.

Func _LogonOnUser($sUsername, $sPassword, $sServer = @LogonDomain)
    Local $aRet
    Local $stToken
    Local $phToken
    Local $nError = -1

    $stToken = DllStructCreate("int")
    $aRet = DllCall("advapi32.dll", "int", "LogonUser", _
            "str", $sUsername, _
            "str", $sServer, _
            "str", $sPassword, _
            "dword", 8, _ ; LOGON32_LOGON_NETWORK_CLEARTEXT
            "dword", 0, _
            "ptr", DllStructGetPtr($stToken))
    $phToken = DllStructGetData($stToken, 1)
    If Not @error And $aRet[0] <> 0 Then
        ;Return True ; Return True if user exists
        $aRet = DllCall("advapi32.dll", "int", "ImpersonateLoggedOnUser", "ptr", $phToken)
        If Not @error And $aRet[0] <> 0 Then
            ConsoleWrite("Impersonated User = " & @UserName & @CRLF)
            ; Do Impersonation Stuff Here
            _InitiatePermissionResources() ; Requires Permissions UDF
            $aet = DllCall("kernel32.dll", "int", "GetLastError")
            If Not @error Then $nError = $aRet[0]
        DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $phToken)
        $aRet = DllCall("kernel32.dll", "int", "GetLastError")
        If Not @error Then $nError = $aRet[0]
    If $nError > -1 Then
        Return 0
    Return 1
EndFunc   ;==>_LogOnUser

Once the process is completed I then _LogOffUser and RevertToSelf

Func _LogOffUser()
    _ClosePermissionResources() ; Requires Permissions UDF
    DllCall("advapi32.dll", "int", "RevertToSelf")
    ConsoleWrite("RevertToSelf User = " & @UserName & @CRLF)

Permissions Applied Successfully!

If I don't use the _LogonOnUser function it errors out and I lose access to my network folders and it disappears! Luckily, I am able to recover it when I use this function.

Link to post
Share on other sites

@Surf243  Your welcome.  A very nice find, and nicely created functions.  I couldn't tell if the user that you were trying to run under was an admin user or not.  My script is used mostly with non admin users.  I'm glad your functions work for what you wanted to do.  I have added them to my script library.  The only issue, and it's really not an issue, is some of the DLL calls could be replaced by _WinAPI_* functions, such as _WinAPI_GetLastError and _WinAPI_CloseHandle.  

I'm also working with the Permissions UDF.  I have found a few issues with it, and have added comments to that thread.  




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 HariKara
      I have a script that seems to launch perfectly fine with IECreate, however, I want to launch the Browser and a specific URL with the RunAs command. I fairly new to AutoIT and wanted to know if someone can point me in the right direction.
      Local $surl = "http://somewebsite.com/DODA/admin/job.aspx"
      Local $oIE = _IECreate($sURL)
      The above launches the website correctly with the correct URL, however, I have tried the below and this fails to load and browser?
      #include <AutoItConstants.au3>
      $oSleep = "200"
      Local $surl = "http://somewebsite.com/DODA/admin/job.aspx"
      Local $oIE = RunAs($args("username"), $args("domain"), $args("logonpassword"), "", "C:\Program Files (x86)\Internet Explorer\iexplore.exe http://somewebsite.com/DODA/admin/job.aspx")
      I get the following error back?
      --> IE.au3 T3.0-2 Error from function _IELoadWait, $_IESTATUS_InvalidDataType
      --> IE.au3 T3.0-2 Error from function _IEGetObjById, $_IESTATUS_InvalidDataType
      --> IE.au3 T3.0-2 Error from function _IEGetObjById, $_IESTATUS_InvalidDataType
    • By SanCon
      I've found and used @TheDcoder's ProcessEX UDF, and have found it and invaluable tool in my scripting arsenal. Recently, I found myself needing to create a script which then attempts to run another program as a different user. I was able to heavily borrow from the _Process_RunCommand function to create _Process_RunAsCommand:
      ; #FUNCTION# ==================================================================================================================== ; Name ..........: _Process_RunAsCommand ; Description ...: Runs a command or an executable under a different user security privilege. ; Syntax ........: _Process_RunAsCommand($iMode, $sUserName, $sUserPass, $sUserDomain, $sExecutable [, $sWorkingDir = @TempDir [, $iRunOptFlag = $STDERR_MERGED]]) ; Parameters ....: $iMode - Mode in which this function should operate, See Remarks. ; $sUserName - User name under which you would like to run the command/executable. ; $sUserPass - Password for $sUserName. ; $sUserDomain - Domain name to which the $sUserName belongs. ; $sExecutable - The command to run/execute (along with any arguments). ; $sWorkingDir - [optional] The working directroy for the command. Default is @TempDir. $sUserName must have ; privileges to create/modify files on this directory. ; $iRunOptFlag - [optional] The Opt flag for the Run function. Default is $STDERR_MERGED. ; Return values .: Success: Mode $PROCESS_RUN : Will return the process handle & @extended will contain the PID of the command ; Mode $PROCESS_RUNWAIT : Will return the output & @extended will contain the exit code for the function ; Failure: Will return False & @error will contain: ; 1 - If the $iMode flag is invalid ; 2 - If the command is invalid ; Author ........: J. Sanchez, heavily borrowing from code by TheDcoder ; Modified ......: N/A ; Remarks .......: 1. The ONLY valid modes are: $PROCESS_RUN & $PROCESS_RUNWAIT ; $PROCESS_RUN : Will act similarly to Run function, See Return values ; $PROCESS_RUNWAIT : Will act similarly to RunWait function, See Return values ; If you use $PROCESS_RUN then use _Process_GetExitCode to get the exit code & use StdoutRead to get the output of the command ; 2. Use $PROCESS_COMMAND to run commands like this: $PROCESS_COMMAND & "ping" ; 3. Add $PROCESS_DEBUG to $iMode to automagically debug the command, $PROCESS_RUN is equivalent to $PROCESS_RUNWAIT in this case ; Related .......: RunAs, RunWait ; Link ..........: http://bit.ly/ProcessUdfForAutoIt ; Example .......: Yes, see example.au3 ; ===============================================================================================================================; Functions Func _Process_RunAsCommand($iMode, $sUserName, $sUserPass, $sUserDomain, $sExecutable, $sWorkingDir = @TempDir, $iRunOptFlag = $STDERR_MERGED) Local $iExitCode = 0 ; Declare the exit code variable before hand Local $sOutput = "" ; Declare the output variable before hand Local $bDebug = False ; Declare the debug variable before hand If BitAND($iMode, $PROCESS_DEBUG) Then $bDebug = True If BitAND($iMode, $PROCESS_RUN) Then $iMode = $PROCESS_RUN ElseIf BitAND($iMode, $PROCESS_RUNWAIT) Then $iMode = $PROCESS_RUNWAIT Else Return SetError(1, 0, False) EndIf ; If Not $iMode = $PROCESS_RUN Or Not $iMode = $PROCESS_RUNWAIT Then Return SetError(1, 0, False) ; If the mode is invalid... ;Local $iPID = Run($sExecutable, $sWorkingDir, @SW_HIDE, $iRunOptFlag) ; Run!!! :P Local $iPID = RunAs($sUserName,$sUserDomain,$sUserPass,BitAND(0,4),$PROCESS_COMMAND & " " & $sExecutable,$sWorkingDir,@SW_HIDE,$iRunOptFlag) If @error Then Return SetError(2, @error, False) ; If the command is invalid... Local $hProcessHandle = _Process_GetHandle($iPID) ; Get the handle of the process If $iMode = $PROCESS_RUN Then If Not $bDebug Then Return SetExtended($iPID, $hProcessHandle) ; If the function is in Run mode then return the PID & Process Handle $sOutput = _Process_DebugRunCommand($hProcessHandle, $iPID) ; Debug the process $iExitCode = _Process_GetExitCode($hProcessHandle) ; Note the exit code Return SetExtended($iExitCode, $sOutput) ; Return the output & exit code EndIf If Not $bDebug Then While ProcessExists($iPID) $sOutput &= StdoutRead($iPID) ; Capture the output Sleep(250) ; Don't kill the CPU WEnd $sOutput &= StdoutRead($iPID) ; Capture any remaining output $iExitCode = _Process_GetExitCode($hProcessHandle) ; Note the exit code Return SetExtended($iExitCode, $sOutput) ; Return the exit code & the output :D EndIf $sOutput = _Process_DebugRunCommand($hProcessHandle, $iPID) ; Debug the process $iExitCode = _Process_GetExitCode($hProcessHandle) ; Note the exit code Return SetExtended($iExitCode, $sOutput) ; Return the output & exit code EndFunc The issue that I currently have is that, regardless of what the errorlevel returned by the program being executed, the errorlevel returned by the _Process_RunAsCommand is 259, which, according to this page it means that there's no more data (I'm guessing from the STDIO and STDERR?)
      Any guidance would be greatly appreciated.
    • By damon
      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 HariKara
      Hi AutoIters!
      Im trying to launch a .exe file that is nested within the program files (x86) folder structure. i have already used the standard RunAs Syntax and found that it fails to launch the application. I have switched to Run and that seems to work. My issue is I have to use RunAs as the applicaton would need to run under a completely different account. The Current logged in user is a Local User on the machine, however, the application must be run as a domain user. The Machine is domain connected.
       have tried the following:
      RunAs("username","logonpassword", $RUN_LOGON_PROFILE, "D:\Program Files (x86)\Vendor\Application Name\Exe Location\Executable.exe") The above fails to launch, there are no errors or syntax issues, it just does nothing when the variables are replaced for the correct values.
      I did the same using the Run command
      Run("D:\Program Files (x86)\Vendor\Application Name\Exe Location\Executable.exe") That seems to work fine, but runs in local user context. Any thoughts? Could it be a local Machine rights issue? Or have i missed something glaring in my script
    • By PINTO1927
      HI GUYS,
      I'm trying to run this script with an advanced domain user, but when compiling the cmd it returns access denied, as if it did not recognize the user of AD.
      RunAsWait("administrator", "CONTOSO", "Services.1", 2, "C:\Users\albert.frizz\Desktop\test.bat")
      can you help me please?
  • Create New...