How to launch a process interactively from a Windows Service?

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 (https://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.