If at all possible, use Larry Osterman's solution instead (in the comments on Anders' answer), i.e. the parent process that runs without promotion, and from there run both the elevated process and the non-extended process.
If this is not possible, there is an approach that should work in almost all cases, although this is usually more of a problem than it costs:
Install and run the system service configured to work as a local system. Give it the remote desktop session identifier, for example, using a command line argument or a registry setting, as well as the process identifier and command line that you want to run.
From the system service, use GetTokenInformation with TokenLinkedToken to get the associated token from the target process. You have to do this from the system service because you need SE_TCB_NAME to get the useful token. (This limitation does not seem to be documented, but is consistent with the behavior of tokens on Windows.)
Or, if there is no bound token, use WTSQueryUserToken to get a copy of the user's token. I believe this always gives you a limited token (if one exists), but if you want to be safe, you can check if it is a raised or limited token using GetTokenInformation and TokenElevationType; if it is an elevated token, you can use TokenLinkedToken to get limited.
If there is no associated token (TokenElevationTypeDefault), you should use the token as is. This can happen either because the user is not an administrator, or because the UAC is disabled, either globally, or because the user is logged in using the built-in administrator account. If the user is not an administrator, then the token is already suitable. If UAC is disabled, you must comply with the user's intent and use an administrative token.
You can then use CreateProcessAsUser or CreateProcessWithTokenW from the system service to start a new process.
Finally, the service must remove itself and stop.
There is at least one edge case: if your elevated process starts from the command line (or another process) that was started using runas and non-administrative credentials. In this case, there is no separation token, and the original token may already have been deleted, so if you didnβt capture the copy before the mark was made (Larryβs solution or its variants), there is no general way to start the child process in the same user context. from which the elevated process was originally launched. The best you can do is the context of the registered user (via WTSQueryUserToken, as described above), which may not correspond to the behavior that the end user expected. (This may, however, be an acceptable limitation, depending on the scenario.)
source share