Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start a process from windows service into currently logged in user's session

I need to start a program from Windows Service. That program is a user UI application. Moreover that application should be started under specific user account.

The problem is that a Window Services run in session #0, but a logged in user sessions are 1,2 etc.

So the question is: how to start a process from a window service in such a way that it run in currently logged in user's session?

I'd emphasis on that the question is not about how to start a process under specific account (it's obvious - Process.Start(new ProcessStartInfo("..") { UserName=..,Password=..})). Even if I install my windows to run under current user account the service will run in session #0 anyway. Setting "Allow service to interact with desktop" doesn't help.

My windows service is .net-based.

UPDATE: first of all, .NET has nothing to do here, it's actually pure Win32 thing. Here's what I'm doing. The following code is in my windows service (C# using win32 function via P/Inkove, I skipped import signatures, they're all here - http://www.pinvoke.net/default.aspx/advapi32/CreateProcessWithLogonW.html):

    var startupInfo = new StartupInfo()         {             lpDesktop = "WinSta0\\Default",             cb = Marshal.SizeOf(typeof(StartupInfo)),         };     var processInfo = new ProcessInformation();     string command = @"c:\windows\Notepad.exe";     string user = "Administrator";     string password = "password";     string currentDirectory = System.IO.Directory.GetCurrentDirectory();     try     {         bool bRes = CreateProcessWithLogonW(user, null, password, 0,             command, command, 0,             Convert.ToUInt32(0),             currentDirectory, ref startupInfo, out processInfo);         if (!bRes)         {             throw new Win32Exception(Marshal.GetLastWin32Error());         }     }     catch (Exception ex)     {         writeToEventLog(ex);         return;     }     WaitForSingleObject(processInfo.hProcess, Convert.ToUInt32(0xFFFFFFF));     UInt32 exitCode = Convert.ToUInt32(123456);     GetExitCodeProcess(processInfo.hProcess, ref exitCode);     writeToEventLog("Notepad has been started by WatchdogService. Exitcode: " + exitCode);      CloseHandle(processInfo.hProcess);     CloseHandle(processInfo.hThread); 

The code goes to the line "Notepad has been started by WatchdogService. Exitcode: " + exitCode. Exitcode is 3221225794. And there's no any new notepad started. Where am I wrong?

like image 820
Shrike Avatar asked Nov 25 '10 14:11

Shrike


People also ask

Can a Windows service start an application?

Windows Services cannot start additional applications because they are not running in the context of any particular user. Unlike regular Windows applications, services are now run in an isolated session and are prohibited from interacting with a user or the desktop.

How do I turn off active user session in Windows?

Click Start, click Settings, click the user name (top-right corner), and then click Sign out. The session ends and the station is available for log on by any user. Click Start, click Settings, click Power, and then click Disconnect.


2 Answers

The problem with Shrike's answer is that it does not work with a user connected over RDP.
Here is my solution, which properly determines the current user's session before creating the process. It has been tested to work on XP and 7.

https://github.com/murrayju/CreateProcessAsUser

Everything you need is wrapped up into a single .NET class with a static method:

public static bool StartProcessAsCurrentUser(string appPath, string cmdLine, string workDir, bool visible) 
like image 53
murrayju Avatar answered Oct 16 '22 07:10

murrayju


A blog on MSDN describes a solution

It's a terrific helpful post about starting a new process in interactive session from windows service on Vista/7.

For non-LocalSystem services, the basic idea is:

  • Enumerate the process to get the handle of the Explorer.

  • OpenProcessToken should give you the access token. Note : The account under which your service is running must have appropriate privileges to call this API and get process token.

  • Once you have the token call CreateProcessAsUser with this token. This token already have the right session Id.

like image 26
Shrike Avatar answered Oct 16 '22 07:10

Shrike