The short answer is: Not easily.
As the docs for os.startfile
imply, it's just calling ShellExecute
, which has no such functionality.
What you can do pretty easily is just have each user fire up his own copy of the web server, under his own account, on whatever session he wants. Sure, it means you'll all have to use different port numbers (or get assigned random port numbers at login which you'll then have to display in some way), but that's not so terrible.
First, you're going to need to talk directly to the Win32 API (ideally via pywin32
, but if you really want to use ctypes
you can).
Next, a user might be connected to your web server but not connected to the RDC server—or, worse, might have three different RDC sessions. So, what does "the second user's desktop" actually mean? If it's acceptable to pick one arbitrarily, and to fail if there are none, that's a reasonable answer. This part is pretty easy: you use the Windows Terminal Server API (now part of Remote Desktop Services, but most of the functions still start with WTS) to enumerate the sessions and find the first one whose WTS_SESSION_INFO_1
matches your user.
Now, you just need to get an access token or impersonation token for that user within that session so you can call CreateProcessAsUser
or CreateProcessWithToken
. (You can't use CreateProcessWithLogon
, because that won't be in their RDS session, it'll be in a new session for that user, but connected to your RDS session, which is doubly useless.)
So, how do you get one of those things? Here's where you have the choice between a massive security hole if you're not very careful and don't really know what you're doing, or a different massive security hole if you're not very careful and don't really know what you're doing.
If you don't care about your terminal server box getting hacked, you can run your server (or, hopefully, a minimal helper tool that your server talks to) as LocalSystem
, and call WTSQueryUserToken
. This one is actually really easy, and just by reading this sentence your computer is now part of someone's spam botnet.
If you don't care about your users' accounts getting hacked, you can instead pass their credentials through your web server so you can logon and ImpersonateLoggedOnUser
to get a user token. There are ways to do that without passing the password in plaintext over the web, but that won't matter. Because the next step is to create a new session connected to the user's existing session, and to do that from outside, you need his username and password even though you're already logged in as him. Anyway, having done that, you just run the app inside the new session, and he sees it in his existing session, and everyone lives happily ever after, especially the guy who just checked that your friend uses the same password for PayPal that he does for your server and ran up $17000 worth of charges.
If this hasn't scared you off, create some virtual machines on a LAN that isn't connected to the internet and start playing with this stuff—it's a lot of fun, and you'll learn a lot, and ideally you'll be able to write something that does what you want and ultimately convince yourself sufficiently that you're not leaking tokens anywhere that you're ready to deploy it.