以编程方式创建 Windows 会话

Wol*_*ler 8 windows winapi rdp

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

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

Lor*_*ash 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Rem*_*eau 5

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

  • Windows Server 2012 提供了一个 API,它应该能够创建用户会话。不幸的是,它在 Windows 8 或以前版本的 Windows Server 上不可用。请参阅 http://msdn.microsoft.com/en-us/library/dd919947%28v=vs.85%29.aspx (6认同)
  • 我已经考虑过这些 API。不幸的是,这不适用于我的场景,因为我需要启动一个基于 UI 的应用程序,而这与会话 0 隔离并不顺利。这就是为什么我需要一个“真正的”用户会话而不是服务会话的原因。 (3认同)