我有一个在 Windows 服务 (0) 会话中运行的服务。从客户端连接后,我需要为给定的用户凭据创建一个新的 Windows 会话,登录该用户并在这个新会话中启动一个应用程序。
有没有办法以编程方式为给定的用户凭据创建用户会话?
AFAIK,您不能以编程方式创建会话。为此,客户端必须使用终端服务或远程桌面连接到机器。但是,如果您只需要以该用户身份运行进程而不使其在屏幕上可见,则可以通过编程方式登录到用户帐户并模拟它。查看LogonUser()
和ImpersonateLoggedOnUser()
、CreateProcessAsUser()
或CreateProcessWithLogonW()
。
@WolfgangZiegler,我知道这是一个老问题,但我实际上已经为您找到了解决方案!我使用远程桌面 ActiveX 控件(COM 参考)编写了一个简单的实用程序。如果您将此代码粘贴到类库中,您可以通过简单地传递服务器、用户名、域和密码来调用它,并且一切都为您完成,无需任何其他交互。这回答了您提出的问题,但您还提到您需要在刚刚创建的会话中启动应用程序。我知道你没有直接问这个问题,但我想我会为你指出正确的方向,以防万一,因为你的情况听起来和我的很相似。实际上有几种启动应用程序的方法,因此您需要找到适合您的方法。你' 将需要使用 Win32 API 来创建最有可能使用 CreateProcessAsUser、CreateProcessWithLogon 或 CreateProcessWithToken 的进程。所有这三个方法都在 Advapi32.dll 中。
我以某种方式编写了此 RDP 实用程序,以便您每次都可以调用它,但启动 RDP 会话需要几秒钟,所以为了性能,我建议您编写另一种方法来枚举会话并查看您的用户是否已登录并且仅在您确定您的用户未登录时才调用此实用程序(这就是我在实际项目中所做的)。
这是一个返回我的问题的链接,它比这个问题有更多的要求/细节。
从控制台或 Windows 服务以编程方式创建 Windows 会话
这是我的 RDP 实用程序。如果将此代码放在类库中,则可以从控制台应用程序、winForms 应用程序或 Windows 服务调用它。
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);
}
}
}