我有一个运行在Windows服务(0)会话中的服务。
当客户端连接时,我需要为给定的用户凭证创建一个新的Windows会话,登录该用户,并在此新会话中启动应用程序。
是否有一种编程方式来为给定的用户凭证创建用户会话?
我有一个运行在Windows服务(0)会话中的服务。
当客户端连接时,我需要为给定的用户凭证创建一个新的Windows会话,登录该用户,并在此新会话中启动应用程序。
是否有一种编程方式来为给定的用户凭证创建用户会话?
@WolfgangZiegler,我知道这是一个旧问题,但是我已经为您找到了解决方案!我使用远程桌面ActiveX控件(COM参考)编写了一个简单的实用程序。如果您将此代码粘贴到类库中,然后仅通过传递服务器、用户名、域和密码即可调用它,而无需进行任何其他交互。这回答了您提出的问题,但是您还提到需要启动应用程序到刚创建的会话中。虽然您没有直接询问,但我认为我应该指引您正确的方向,因为您的情况听起来与我的非常相似。实际上有几种启动应用程序的方法,因此您需要找到适合您的方法。您可能需要使用Win32 API来创建进程,最可能的是使用CreateProcessAsUser、CreateProcessWithLogon或CreateProcessWithToken。这三种方法都在Advapi32.dll中。
我已经以一种方式编写了这个RDP实用程序,可以每次调用它,但是启动RDP会话需要几秒钟,因此出于性能考虑,我建议您编写另一种方法来枚举会话并查看您的用户是否已登录,并仅在确定您的用户未登录时调用此实用程序(这就是我在实际项目中所做的)。
这是一个链接,指向我的问题,其中包含比这个问题更多的要求和细节。
这是我的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);
}
}
}
LogonUser()
和ImpersonateLoggedOnUser()
,CreateProcessAsUser()
或CreateProcessWithLogonW()
。CreateProcessAsUser()
在现有用户会话中运行UI进程。我自己在其中一个自己的服务中这样做,它可以正常工作。但据我所知,服务无法创建新的UI会话,它只能与现有会话交互。 - Remy Lebeau