Search code examples
c#processservicepsexeccreateprocessasuser

How to get Currently logged user's session ID?


I'm running a process from inside a windows service using:

ProcessStartInfo processStartInfo = new ....
Process.Start(processStartInfo);

The problem is, if I run service under local system account, it runs alright, but it doesn't show the programs' window. I've tried to put user credentials in service properties, but then 'Allow service to interact with desktop' checkbox becomes disable.

I really need to run the app calling it from service, and I really need to see the app's window.

Update 1:

Well, you use overloaded version of Process.Start what takes username, password and domain - it will pull the program to the desktop. But, now it starts the app under one credentials, and shows that on a different user's desktop. How come?

Update 2:

I have an idea! I can use psexec.exe from Sysinternals Suite. But, the problem is, I need to start that thing silently "as administrator", which I don't know how to do it.

I mean even, if you're already have admin rights, sometimes you have to manually say "run as administrator", confirm UAC and only after that you're ready to go. I don't know how silently run something without bringing UAC thing...

Update 3:

Dear Lord. I've got that thing! Finally!

In the beginning the problem was indeed in session 0 isolation thing. So, I needed to build a middle app that can be started from the service and then, that app in its turn suppose to start my application through RPC and bring it to a desktop. Instead of building middle layer app I decided to use psexec.exe tool (anyway it works exactly the way I need - through RPC). And, when I tried to use that tool under LOCAL SYSTEM account it didn't work for some reason. And then I realized - the reason is damn EULA popup dialog that MS put in every single pstool, and it was impossible to click the button to confirm dialog under LOCAL SYSTEM account.

So, the solution is to create a key in the registry HKU\.DEFAULT\Software\Sysinternals\PsExec with DWORD value EulaAccepted = 1.

Hooray, now it works! BUT! Now I need to bring the program to the currently logged user's screen. To do that I'm gonna need the session id!

So the question is :

How to get currently logged user's session id? And, what happens if there's no one logged yet? What session id that would be?

Update 4:

That's it! I got that one!

[DllImport("Kernel32.dll", EntryPoint = "WTSGetActiveConsoleSessionId")]
public static extern int WTSGetActiveConsoleSessionId();

Solution

  • One solution would be to have a third process act as an intermediary, and tell it to launch apps via RPC/Named pipes.

    Processes:

    • Windows service
    • Intermediary application
    • The app you want to run

    The shim creates a communication endpoint (named pipe, WCF endpoint) and listens on it. When it gets a message to go ahead, it launches the app you want to run.

    Then, when the Windows service wants to launch an app, it finds and opens the endpoint (named pipe, WCF endpoint), and sends the message to launch the app. Then the intermediary application takes care of the process launching business, and doesn't have any of the limitations that the Windows service has.

    Make this intermediary process start with logon, and you're good to go.

    This is similar to how the Microsoft test agent/controller work when you need to run tests that interact with the desktop.