以编程方式创建Windows会话

时间:2012-11-08 11:30:02

标签: windows winapi rdp

我在Windows服务(0)会话中运行了一项服务。 从客户端连接后,我需要为给定的用户凭据创建一个新的Windows会话,登录该用户并启动应用程序进入这个新会话。

有没有办法以编程方式为给定的用户凭据创建用户会话?

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

@WolfgangZiegler,我知道这是一个老问题,但实际上为您找到了解决方案!我已经使用远程桌面ActiveX控件(COM参考)编写了一个简单的实用程序。如果将此代码粘贴到类库中,则可以通过简单地传入服务器,用户名,域和密码来调用它,并且一切都为您完成,而无需任何其他交互。这可以回答您提出的问题,但是您还提到需要在刚创建的会话中启动应用程序。我知道您没有直接询问这个问题,但我想我会向您指出正确的方向,以防万一您的情况听起来与我的情况非常相似。实际上,有几种启动应用程序的方法,因此您需要为您找到合适的应用程序。您将需要使用Win32 API来最有可能通过CreateProcessAsUser,CreateProcessWithLogon或CreateProcessWithToken创建一个进程。这三种方法都在Advapi32.dll中。

我已经以某种方式编写了此RDP实用程序,以便您每次都可以调用它,但是启动RDP会话需要花费几秒钟的时间,因此出于性能考虑,我建议您编写另一种枚举会话并查看用户是否已登录,只有在确定用户未登录时才调用此实用程序(这就是我在实际项目中所做的事情)。

这是一个指向我的问题的链接,该链接比该问题有更多的要求/细节。

Create Windows Session programmatically from Console or Windows Service

这是我的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);
        }
    }
}