CreateProcessAsUser

The CreateProcessAsUser function creates a new process and its primary thread. The new process then runs the specified executable file. The CreateProcessAsUser function is similar to the CreateProcess function, except that the new process runs in the security context of the user represented by the user parameter. By default, the new process is non-interactive, that is, it runs on a desktop that is not visible and cannot receive user input. Also, by default, the new process inherits the environment of the calling process, rather than the environment associated with the specified user.

Long CreateProcessAsUser (flags, user, domain, password, CommandLine)

Arguments:

flags
The flags parameter modify the default behavior of CreateProcessAsUser.
The flags parameter can be 0 to assume all defaults, or one or more of the following flags combined with the Or operator.

CP_INTERACTIVE Specifies whether the application (process) provides a user interface on a desktop that can be used by whoever is logged on when the application is started.

When running as a service, this option is available only if the service is running as a LocalSystem account.

Cannot be combined with CP_NTI.

CP_HIDE Hides the window associated with the application.
CP_ASYNC Runs the process asynchronously.
CP_PROFILE Populates the HKEY_CURRENT_USER registry key with the specified user's profile information. This is consistent with a normal interactive logon.
CP_WAIT_IDLE The CP_WAIT_IDLE flag causes the script to wait until the specified process is waiting for user input with no input pending, or until and internal 15 second timeout occurs.
Note: Must be be used with CP_ASYNC.

user
String that specifies the name of the user. This is the name of the user account to log on to. If you use the UPN format, user@DNS_domain_name, the domain parameter must be vbNullString.

The user account must have Log On Locally permission on the local computer. This permission is granted to all users on workstations and servers, but only to administrators on domain controllers.

domain
String that specifies the name of the domain or server whose account database contains the user account. If this parameter is vbNullString, the user name must be specified in UPN format. If this parameter is ".", the function validates the account using only the local account database.

password
String that specifies the clear-text password for the user account specified by user. For more information about protecting passwords, see Handling Passwords.

CommandLine
String that specifies the command line to execute. The maximum length of this string is 32K characters.

The first white-space – delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin. If the file name does not contain an extension, each of .com, .exe, .cmd, and .bat are tried in order. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:

Returns:

The return value from a synchronous CreateProcessAsUser (CP_ASYNC not specified in flags) is the exit status of the new process. The return value from an asynchronous CreateProcessAsUser (CP_ASYNC specified in flags) is zero if the process was successfully spawned. 

The exit status is 0 if the process terminated normally. A spawned process can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). 

Remarks:

When CreateProcessAsUser is called with the CP_ASYNC flag, CreateProcessAsUser does not wait for the new process to finish initialization before returning. This lag between the time a process is created and the time at which the new process is fully initialized can cause some problems if you are trying to initiate communication with the new process too soon.
If your script must communicate or otherwise interact with a freshly the spawned process, it is recommended you use the CP_WAIT_IDLE flag to insure the process has entered a quiescent state.

By default, CreateProcessAsUser does not load the specified user's profile into the HKEY_USERS registry key. This means that access to information in the HKEY_CURRENT_USER registry key may not produce results consistent with a normal interactive logon. If the new process requires the specified user's profile, then you should pass CP_PROFILE in the flags parameter. 
You should only load a user's profile when it is required as it can be a time consuming process.

If you receive the error "A required privilege is not held by the client" or "Access Denied" then your login account does not have sufficient  privileges to allow your thread (the thread your script is running in) to impersonate the specified user. This can happen even if you are an Administrator on the local machine. This error usually goes away when you run TaskGhost as a system service because processes running in the LocalSystem account have elevated privileges.

Domain Administrators will not have this problem, nor will Administrators within a workgroup or standalone machine. However if you are an administrator on a particular machine which is part of a domain and you do not have domain administrative privileges, then you are likely to see this error.

To resolve this problem, you'll need to elevate the rights of the account calling CreateProcessAsUser with the "Replace a process level token" right. To do so, open the Control Panel / Administrative Tools / Local Security Policy and add the user account to the "Replace a process level token" right.  (You may have to logout or even reboot to have this change take effect.)

This script (CreateProcessAsUser.vbs) shows how to call CreateProcessAsUser and how to capture the return code.

Sub main(args)
    Dim user
    Dim domain
    Dim password
    Dim commandline
    '' set these in your environment, or here in the script
    '' If you're running as a service, you will need to set these
    '' as SYSTEM variables
    user = TGCtrl.GetEnvironmentVariable (TSE_ENV_PERSISTENT, "USER")
    domain = TGCtrl.GetEnvironmentVariable (TSE_ENV_PERSISTENT, "DOMAIN")
    password = TGCtrl.GetEnvironmentVariable (TSE_ENV_PERSISTENT Or TSE_ENV_CRYPTO, "PASSWORD")
    commandline = args
    Dim exit_code
    exit_code = TGCtrl.CreateProcessAsUser(0,user,domain,password,commandline)
    If exit_code = -1 Then 
    	TGCtrl.Print("Process failed to start!") 
    Else 
	TGCtrl.Print("Process returned " & exit_code)
    End If
End Sub

Requirements:

Version 1.0

See Also:

CreateProcess, ImpersonateLoggedOnUser, LogonUser
CreateProcessAsUser.vbs and CreateProcessAsUserInt.vbs in the TaskGhost\Scripts directory.