Create Windows Session programmatically from Conso

2019-01-15 23:23发布

How can I programmatically log in to windows to create a Windows Logon Session? I need a way that works from a WinForms app, from a Console app, and (most important) from a Windows Service.

One other requirement is that I need it to work on a the local system that the program/service is running on and also for remote systems.

If there's a way to do this using pInvoke/Win32 API I am open to that too.

I found these similar questions/answers in my research:

Programmatically create and launch and RDP session (without gui)

The answer here says it's possible but and gives a link but the sample code from the link doesn't work

Create a Windows Session from a service via the Win32 API

No Solution to the question asked

Create Windows session programmatically

No Solution but the OP mentioned in a comment that http://freerdp.com worked for him.

1条回答
时光不老,我们不散
2楼-- · 2019-01-16 00:03

I've created a simple utility that I believe meets all the requirements in the question. You'll need to add a COM reference to Microsoft Terminal Services Active Client 1.0 Type Library (ActiveX).

I thought it might not work for creating a session on the local machine but I tested in in 2012R2 running as a Service and it actually can. The same exact method can be called from a WinForms app or from a Console app. When launched from a WinForms or Console app, the a form is shown for a few seconds so I made sure to set the control to enabled = false so it can't be interacted with.

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

On a side note I found this question that says there may be a way to use the ActiveX control (for RDP) without using a windows form at all. I saw the example they gave and I was unsure hot to use their code for this situation.

ActiveX control without a form

If there's anyone out there who understands how to do this without hosting the ActiveX control on a Form please post an example.

查看更多
登录 后发表回答