通过编程创建Windows会话

8

我有一个运行在Windows服务(0)会话中的服务。

当客户端连接时,我需要为给定的用户凭证创建一个新的Windows会话,登录该用户,并在此新会话中启动应用程序。

是否有一种编程方式来为给定的用户凭证创建用户会话?


2
原则上,您可以使用RDP创建新的用户会话。您至少需要一个最小的RDP客户端。一种可能性是FreeRDP,它在Apache许可下可用。我不确定它是否可以直接在Windows上编译,您可能需要进行一些移植工作。 - Harry Johnston
你能创建一个会话吗? - 4x6hw
是的,如上所建议,http://www.freerdp.com/ 是解决方案。 - Wolfgang Ziegler
2个回答

6

@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);
        }
    }
}

5
据我所知,您无法通过编程方式创建会话。客户端必须使用终端服务或远程桌面连接到计算机才能进行操作。但是,如果您只需要以该用户身份运行进程而不使其显示在屏幕上,则可以编程方式登录用户帐户并模拟它。请查看LogonUser()ImpersonateLoggedOnUser()CreateProcessAsUser()CreateProcessWithLogonW()

3
我已经考虑过这些API接口,但不幸的是它们对我的场景没有用处,因为我需要启动一个基于UI的应用程序,而这与会话0隔离不兼容。这就是为什么我需要一个“真正”的用户会话,而不是服务会话。 - Wolfgang Ziegler
1
一个在Session 0中运行的服务可以使用CreateProcessAsUser()在现有用户会话中运行UI进程。我自己在其中一个自己的服务中这样做,它可以正常工作。但据我所知,服务无法创建新的UI会话,它只能与现有会话交互。 - Remy Lebeau
6
Windows Server 2012 提供了一个 API 可以创建用户会话。不幸的是,在 Windows 8 或之前的 Windows Server 版本中,该 API 不可用。请参阅 http://msdn.microsoft.com/en-us/library/dd919947%28v=vs.85%29.aspx。 - Harry Johnston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接