Launching an interactive process from a service used to be straight forward. You could either configure your service to be interactive or you could specify “Winsta0\\Default” as the desktop (in CreateProcess API) and as long as the launched process had the appropriate permissions to the desktop, the launched process would run interactively.
These techniques stopped working with the introduction of Windows VISTA and continues today on Windows 8. Beginning with Windows VISTA, Windows Services were isolated in their own session. (Session 0). This meant if you launched a process from a Windows Service, the process was going to run in session 0 and processes running in session 0 are not interactive.
The session the launched process would run in was determined by the user’s token. If you set a different session ID in the token, the process would launch in that session. You’ll notice that you won’t be able to use CreateProcess() any more since it is going to launch in the same session as the service. Since you need to specify a token, you’ll need to call CreateProcessAsUser(). The other issue you need to address in order to launch a process interactively is that the process needs FULL permissions to the interactive desktop which is “Winsta0\\Default”. There is a lot of old sample code (http://support.microsoft.com/kb/165194 - I actually wrote this article) out there that demonstrates how to modify the security permissions to grant a user access to the Interactive desktop. Unfortunately this code will not work anymore since you can’t modify the permissions for the desktop that is located in a different session. You can only modify the desktop in the session where your code is running in.
The recommend way to launch an interactive process is to determine the session ID of the session you are targeting and to obtain the token of the interactive user in that session. If you know the session ID, you can call WTSQueryUserToken() to obtain the token. You can then launch a process into this session as this user. You do need to have the SeTcbPrivilege in order to make the call to WTSQueryUserToken() so it’s typically something only a highly privileged user should do.
If you want to launch a process as a different user (other than the interactive user running in the session), the best way to do this is to have a process running in that session call CreateProcessWithLogonW(). This is equivalent to using the runas command.
great post, thanks for this comprehensive description, was for me very useful.
I have a similar problem on Windows Server 2012: I need to start processes with CreateProcessAsUser without interaction, but these calls always failing with error code 5 (access denied). The application is hosted in IIS, and uses DuplicateTokenEx for converting the impersonating token to a primary token. The same code is executed successfully on Windows 7 and Windows Server 2008 R2. Do you have any idea?
If you are receiving an "access denied" from CreateProessAsUser, this means the caller doesn't have access to the exe itself. I would suggest running ProcMon to see where the "access denied" is coming from.
there is no error shown by the procmon, each file operation succeeds, the IIS apppool is able to read the executable, which I want to start under another token.
I forgot to mention that you may not have the correct permissions in the token passed to CreateProcessAsUser(). I would review the permissions you are requesting in DuplicateTokenEx(). I know the required permissions in the token might have changed between operating systems.