Sign in to follow this  
Followers 0


2 posts in this topic

#1 ·  Posted (edited)


An odd thing about Vista+ O/S's is that, once you run a process in elevated privileges mode, you can't run other processes in lower-privileged modes.

Why, you ask, would that be important?

Sometimes you want - or need - to limit the privileges of a process:

  • A very common scenario for me is drag-and-drop.

    Windows' Explorer does NOT allow this to occur between lower privileged processes (like Explorer itself!) and other processes. This is very frustrating for users in programs that take advantage of that.

  • There's also some problems using certain SendMessage commands from other unelevated processes.
  • Setting the state or properties of windows that have an elevated privilege may not work either from other unelevated processes..
  • An install or setup program that needs to launch the installed program will more often than not want to run that program on a lower privilege level (for some of the reasons mentioned above)
So, after some looking around I found a way of running processes under a lower privilege mode.Check Elmue's comment 'Here the cleaned and bugfixed code' on this CodeProject page to see where my code was ported from:

'Creating a process with Medium Integration Level from the process with High Integration Level in Vista'

The usage is straightforward for this one: use it like Run/RunWait, but with the command-line as the 2nd parameter. [i.e. _RunWithReducedPrivileges(@ComSpec,' /k title Non-Admin prompt') ]

Anyway, hope this helps someone out!

Ascend4nt's AutoIT Code License agreement:

While I provide this source code freely, if you do use the code in your projects, all I ask is that:

  • If you provide source, keep the header as I have put it, OR, if you expand it, then at least acknowledge me as the original author, and any other authors I credit
  • If the program is released, acknowledge me in your credits (it doesn't have to state which functions came from me, though again if the source is provided - see #1)
  • The source on it's own (as opposed to part of a project) can not be posted unless a link to the page(s) where the code were retrieved from is provided and a message stating that the latest updates will be available on the page(s) linked to.
  • Pieces of the code can however be discussed on the threads where Ascend4nt has posted the code without worrying about further linking.

Download the ZIP from my site

Edited by Ascend4nt
1 person likes this

Share this post

Link to post
Share on other sites

Although I have found links to this thread and I think many people use this, I am surprised there have been no replies here before now.

Thanks a lot for this Ascendant.


As you say, it is useful for installers which I prefer to write myself. An installer needs Admin privileges but that means that it will not write to the correct HKCU registry area, and if it starts the application, which is a natural thing someone installing will want to do, then the registry settings written by the installed program will be not to the user HKCU but to the Admin's HKCU and so be 'missing' the next time the program is started normally. Also, any files created by the program, and folders created by the program will be denied access the next time the program is run unless the data is written to somewhere like public documents. SInce many, including me, would expect that data could be stored in ProgramData, then running the installed program from the installer will result in access to data and folders being denied in future instances.

_RunWithReducedPrivileges solves all these problems and makes it relatively easy to produce a fully featured installer.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

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

    • 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