Jump to content
rudi

Howto get original user's profile dir when using UAC elevation?

Recommended Posts

Posted (edited)

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.

Edited by rudi

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Share this post


Link to post
Share on other sites

If you knew how to self-elevate your script to run as admin, then you could send the UserProfile value to your script, as a parameter, upon elevation.  Don't ask me how to self-elevate to run as admin.  Discussing the details of the process have been deemed off limits in this forum.  However, there have been discussions of it in this forum in the past and there are language-independent discussions of how it can be done all over the Internet.  I found out how to do it several years ago and know that it works quite well.

Share this post


Link to post
Share on other sites

You can use something like:

;~ Script needs to be compiled to work
;~ Running directly will use the executors UserProfileDir as a switch and then prompt for UAC
;~ Can also use <@ScriptFullPath> --UserProfileDir %UserProfile%
#include <WinAPIProc.au3>

Global $g_sUserProfileDir = _GetCmdLineValue("UserProfileDir", @UserProfileDir)
If Not _WinAPI_IsElevated() Then
    ShellExecute(@ScriptFullPath, "--UserProfileDir " & $g_sUserProfileDir, "", "RunAs")
    Exit
EndIf

MsgBox(4096, "UserProfileDir", $g_sUserProfileDir)

Func _GetCmdLineValue($sCmdLine, $vResult = Null)
    For $i = 1 To $CmdLine[0]
        If $CmdLine[$i] = "/" & $sCmdLine Or $CmdLine[$i] = "-" & $sCmdLine Or $CmdLine[$i] = "--" & $sCmdLine Then
            If $CmdLine[0] >= $i + 1 Then
                If StringLeft($CmdLine[$i + 1], 1) = "/" Or StringLeft($CmdLine[$i + 1], 1) = "-" Or StringLeft($CmdLine[$i + 1], 2) = "--" Then
                    Return $vResult
                Else
                    Return $CmdLine[$i + 1]
                EndIf
            EndIf
        EndIf
    Next
    Return $vResult
EndFunc

 

Share this post


Link to post
Share on other sites
18 hours ago, TheXman said:

If you knew how to self-elevate your script to run as admin, then you could send the UserProfile value to your script, as a parameter, upon elevation.  Don't ask me how to self-elevate to run as admin.  Discussing the details of the process have been deemed off limits in this forum.  However, there have been discussions of it in this forum in the past and there are language-independent discussions of how it can be done all over the Internet.  I found out how to do it several years ago and know that it works quite well.

I'm *NOT* interested in *SELF* elevating the script. Exactly that's, what I don't want to work: The regular users shall not be granted the possibility to bypass UAC in any means.

What I need is to write few registry values to parts of the registry, the normal user has no write access to. (An for security reasons *SHALL* not have write access to! It would be an easy thing to simply grant write access to the "Local-User-Windows-Group", but that's what I don't want to do)

 

I want to *PASS* the information of the currently-logged-on-userprofile-dir-path to the script to be processed within the script itself, after I personally entered the credentials for the UAC elevation process.


Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Share this post


Link to post
Share on other sites
Posted (edited)
19 hours ago, rudi said:

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?

If i understand corretly, i believe so, a simple question of setting that macro @UserProfileDir into a variable on the top of the script, and then use it afterwards.

As an extreme measure, you could have another exe, that runs and writes to an ini file the profile dir, and then your main script would read from ini.

Or maybe im just complicating things without need.

Edited by careca

Spoiler

Renamer - Rename files and folders, remove portions of text from the filename etc.

GPO Tool - Export/Import Group policy settings.

MirrorDir - Synchronize/Backup/Mirror Folders

BeatsPlayer - Music player.

Params Tool - Right click an exe to see it's parameters or execute them.

String Trigger - Triggers pasting text or applications or internet links on specific strings.

Inconspicuous - Hide files in plain sight, not fully encrypted.

Regedit Control - Registry browsing history, quickly jump into any saved key.

Time4Shutdown - Write the time for shutdown in minutes.

Power Profiles Tool - Set a profile as active, delete, duplicate, export and import.

Finished Task Shutdown - Shuts down pc when specified window/Wndl/process closes.

NetworkSpeedShutdown - Shuts down pc if download speed goes under "X" Kb/s.

IUIAutomation - Topic with framework and examples

Au3Record.exe

Share this post


Link to post
Share on other sites

Thanks for your reply.

that's doing quite exactly, what I was asking for. Except, that the script has to be compiled.

;~ must *NOT* be used: #RequireAdmin
;~ Script needs to be compiled to work
;~ Running directly will use the executors UserProfileDir as a switch and then prompt for UAC
;~ Can also use <@ScriptFullPath> --UserProfileDir %UserProfile%
#include <WinAPIProc.au3>

Global $g_sUserProfileDir = _GetCmdLineValue("UserProfileDir", @UserProfileDir)
If Not _WinAPI_IsElevated() Then
    ShellExecute(@ScriptFullPath, "--UserProfileDir " & $g_sUserProfileDir, "", "RunAs")
    Exit
EndIf

MsgBox(4096, "UserProfileDir", $g_sUserProfileDir)

Func _GetCmdLineValue($sCmdLine, $vResult = Null)
    For $i = 1 To $CmdLine[0]
        If $CmdLine[$i] = "/" & $sCmdLine Or $CmdLine[$i] = "-" & $sCmdLine Or $CmdLine[$i] = "--" & $sCmdLine Then
            If $CmdLine[0] >= $i + 1 Then
                If StringLeft($CmdLine[$i + 1], 1) = "/" Or StringLeft($CmdLine[$i + 1], 1) = "-" Or StringLeft($CmdLine[$i + 1], 2) = "--" Then
                    Return $vResult
                Else
                    Return $CmdLine[$i + 1]
                EndIf
            EndIf
        EndIf
    Next
    Return $vResult
EndFunc

 


Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Share this post


Link to post
Share on other sites
Posted (edited)

Could create a batch file that hopefuly grabs the original username

$RF = Random(100000, 999999, 1) & '.bat'
$FO = FileOpen($RF, 10)
$FW = FileWrite($FO, 'cd %UserProfile%' & @CRLF & 'pause'); 'del ' & $RF)
FileClose($FO)
Run($RF)

This is a proof of concept, if it does work, this can be changed to write into a txt file or something.

Edited by careca

Spoiler

Renamer - Rename files and folders, remove portions of text from the filename etc.

GPO Tool - Export/Import Group policy settings.

MirrorDir - Synchronize/Backup/Mirror Folders

BeatsPlayer - Music player.

Params Tool - Right click an exe to see it's parameters or execute them.

String Trigger - Triggers pasting text or applications or internet links on specific strings.

Inconspicuous - Hide files in plain sight, not fully encrypted.

Regedit Control - Registry browsing history, quickly jump into any saved key.

Time4Shutdown - Write the time for shutdown in minutes.

Power Profiles Tool - Set a profile as active, delete, duplicate, export and import.

Finished Task Shutdown - Shuts down pc when specified window/Wndl/process closes.

NetworkSpeedShutdown - Shuts down pc if download speed goes under "X" Kb/s.

IUIAutomation - Topic with framework and examples

Au3Record.exe

Share this post


Link to post
Share on other sites

Here is the script without being compiled:

;~ Script does not need to be compiled to work
;~ Running directly will use the executors UserProfileDir as a switch and then prompt for UAC
;~ Can also use <@ScriptFullPath> --UserProfileDir %UserProfile%
#include <WinAPIProc.au3>

Global $g_sUserProfileDir = _GetCmdLineValue("UserProfileDir", @UserProfileDir)
If Not _WinAPI_IsElevated() Then
    ;~ Using RegRead assumes AutoIt is installed, otherwise manually configure the AutoIt3.exe example: ShellExecute(@ProgramFilesDir & "\AutoIt3\AutoIt3.exe", ...)
    ShellExecute(RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AutoIt3.exe", ""), '"' & @ScriptFullPath & '" --UserProfileDir ' & $g_sUserProfileDir, "", "RunAs")
    Exit
EndIf

MsgBox(4096, "UserProfileDir", $g_sUserProfileDir)

Func _GetCmdLineValue($sCmdLine, $vResult = Null)
    For $i = 1 To $CmdLine[0]
        If $CmdLine[$i] = "/" & $sCmdLine Or $CmdLine[$i] = "-" & $sCmdLine Or $CmdLine[$i] = "--" & $sCmdLine Then
            If $CmdLine[0] >= $i + 1 Then
                If StringLeft($CmdLine[$i + 1], 1) = "/" Or StringLeft($CmdLine[$i + 1], 1) = "-" Or StringLeft($CmdLine[$i + 1], 2) = "--" Then
                    Return $vResult
                Else
                    Return $CmdLine[$i + 1]
                EndIf
            EndIf
        EndIf
    Next
    Return $vResult
EndFunc

 

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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By nacerbaaziz
      Hello all
      I have a question please
      Is there a way to request the script for administrator privileges if a particular condition is met??
      example
      local $path = RegRead("HKEY_CURRENT_USER\Software\test", "fullpath")
      if $fullPath = @scriptFullPath then
      Request for administrator privileges
      main()
      else
      main()
      endIf
      I hope to find a solution here
      Greetings to all
    • 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 RC86
      Morning! I've searched for a definitive answer on the forums on this but can't find one so here goes.  I need admin for one of my functions so I'm using #RequireAdmin.  I then noticed that regardless of that function being used or admin actually being required, the program pops up and requires admin all of the time.
      Is this the way it's designed and is there a way around it so that I can launch my program as normal until admin is required, then and only then prompt the user to run the program as admin?
      The only solution I could think of is to produce 2 executables and do something like:
      $adminrequired = 1 If($adminrequired = 1) Then Run(Run first executable which includes #RequireAdmin) Else Run(Run second identical executable without #RequireAdmin) EndIf Obviously I'd rather keep to making a single executable rather than having 2 or 3!
      Thanks
    • 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.
    • By tremolux66
      I've abandoned the FileSelectFolder() approach and rolled my own UDF to create a dialog containing the folder list in a ListView, which seems to work fine. It's also a better fit to our requirements: we don't really want the user wandering around in the folder-selection dialog, plus the UDF displays some associated info for each folder in a second column. Thanks again to the forum members who took a look at this.
      I'm writing an installer script that needs to run as Administrator so it can, e.g., write files into protected directories. The problem is that when I call FileSelectFolder(), there is a 60-second delay before the dialog appears. If I run as an ordinary user (in the Administrators group), there's no delay, but I don't think that will work: for one thing, the installer needs to create a symbolic link, which a member of the Administrators group can't do unless the program is elevated. (This is Win 7 x64.)
      (The installer will be run using an Admin account; the other user accounts are locked down and don't have access to the filesystem, the Start menu, Computer, etc. - it's a turnkey system.)
      Any idea what causes the delay? And is there a way around it?
       
×
×
  • Create New...