问题
I have a service running in the Windows services (0) session. Upon connection from a client I need to create a new Windows session for given user credentials, log in that user and start an application into this new session.
Is there a way to programmatically create a user session for given user credentials?
回答1:
AFAIK, you cannot create sessions programmably. The client would have to connect to the machine using Terminal Services or Remote Desktop for that. You can, however, programmably log in to a user account and impersonate it if you just need to run a process as that user without making it visible to the screen. Look at LogonUser()
and ImpersonateLoggedOnUser()
, CreateProcessAsUser()
, or CreateProcessWithLogonW()
.
回答2:
@WolfgangZiegler, I know this is an old question but I've actually found a solution for you! I've written a simple utility using the Remote Desktop ActiveX control (COM Reference). If you paste this code into a Class Library you can then call it by simply passing in the server, username, domain, and password and everything is done for you without any other interaction required. That answers the question you asked, but you also mentioned that you need to start an application into the session you just created. I know you didn't directly ask about that but I thought I'd point you in the right direction just in case since your situation sounds very similar to mine. There are actually several ways to launch an application so you'll need to find the right one for you. You'll need to use Win32 API to create a process most likely with either CreateProcessAsUser, CreateProcessWithLogon, or with CreateProcessWithToken. All three of these methods are in Advapi32.dll.
I've written this RDP utility in a way so that you could call it every time but initiating an RDP session takes several seconds so for performance sake I'd suggest you write another method to enumerate the sessions and see if your user is logged in and only call this utility when you determine that your user isn't logged in (That's what I did in my actual project).
Here's a link back to my question that has a few more requirements/details than this question.
Create Windows Session programmatically from Console or Windows Service
And here's my RDP utility. If you put this code in a class library you can then call it from a console app, winForms app, or from a windows service.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using AxMSTSCLib;
namespace Utility.RemoteDesktop
{
public class Client
{
private int LogonErrorCode { get; set; }
public void CreateRdpConnection(string server, string user, string domain, string password)
{
void ProcessTaskThread()
{
var form = new Form();
form.Load += (sender, args) =>
{
var rdpConnection = new AxMSTSCLib.AxMsRdpClient9NotSafeForScripting();
form.Controls.Add(rdpConnection);
rdpConnection.Server = server;
rdpConnection.Domain = domain;
rdpConnection.UserName = user;
rdpConnection.AdvancedSettings9.ClearTextPassword = password;
rdpConnection.AdvancedSettings9.EnableCredSspSupport = true;
if (true)
{
rdpConnection.OnDisconnected += RdpConnectionOnOnDisconnected;
rdpConnection.OnLoginComplete += RdpConnectionOnOnLoginComplete;
rdpConnection.OnLogonError += RdpConnectionOnOnLogonError;
}
rdpConnection.Connect();
rdpConnection.Enabled = false;
rdpConnection.Dock = DockStyle.Fill;
Application.Run(form);
};
form.Show();
}
var rdpClientThread = new Thread(ProcessTaskThread) { IsBackground = true };
rdpClientThread.SetApartmentState(ApartmentState.STA);
rdpClientThread.Start();
while (rdpClientThread.IsAlive)
{
Task.Delay(500).GetAwaiter().GetResult();
}
}
private void RdpConnectionOnOnLogonError(object sender, IMsTscAxEvents_OnLogonErrorEvent e)
{
LogonErrorCode = e.lError;
}
private void RdpConnectionOnOnLoginComplete(object sender, EventArgs e)
{
if (LogonErrorCode == -2)
{
Debug.WriteLine($" ## New Session Detected ##");
Task.Delay(10000).GetAwaiter().GetResult();
}
var rdpSession = (AxMsRdpClient9NotSafeForScripting)sender;
rdpSession.Disconnect();
}
private void RdpConnectionOnOnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
{
Environment.Exit(0);
}
}
}
来源:https://stackoverflow.com/questions/13288207/create-windows-session-programmatically