Создать сеанс Windows программно

У меня есть служба, работающая в сеансе служб Windows (0). При подключении от клиента мне нужно создать новый сеанс Windows для заданных учетных данных пользователя, войти в систему этого пользователя и запустить приложение в этом новом сеансе.

Есть ли способ программно создать сеанс пользователя для заданных учетных данных пользователя?


person Wolfgang Ziegler    schedule 08.11.2012    source источник
comment
В принципе, по крайней мере, вы можете использовать RDP для создания нового пользовательского сеанса. Вам понадобится хотя бы минимальный RDP-клиент. Одной из возможностей может быть FreeRDP, доступный по лицензии Apache. Я не уверен, компилируется ли он как есть в Windows, возможно, вам потребуется выполнить перенос.   -  person Harry Johnston    schedule 12.11.2012
comment
Вы смогли создать возможность сеанса?   -  person 4x6hw    schedule 06.07.2017
comment
Да, как было предложено выше, freerdp.com было решением.   -  person Wolfgang Ziegler    schedule 06.07.2017


Ответы (2)


Насколько я знаю, вы не можете создавать сеансы программно. Для этого клиент должен будет подключиться к машине с помощью служб терминалов или удаленного рабочего стола. Однако вы можете программно войти в учетную запись пользователя и олицетворить ее, если вам просто нужно запустить процесс от имени этого пользователя, не делая его видимым на экране. Посмотрите на LogonUser() и ImpersonateLoggedOnUser(), CreateProcessAsUser() или CreateProcessWithLogonW().

person Remy Lebeau    schedule 09.11.2012
comment
Я уже рассматривал эти API. К сожалению, это не сработает для моего сценария, потому что мне нужно запустить приложение на основе пользовательского интерфейса, а это плохо сочетается с изоляцией сеанса 0. Вот почему мне нужен реальный сеанс пользователя вместо сеанса служб. - person Wolfgang Ziegler; 09.11.2012
comment
Служба, работающая в сеансе 0, может использовать CreateProcessAsUser() для запуска процесса пользовательского интерфейса в рамках существующего сеанса пользователя. Я делаю это сам в одном из своих собственных сервисов, он отлично работает. Но, насколько мне известно, служба не может создать новый сеанс пользовательского интерфейса, она может взаимодействовать только с существующим сеансом. - person Remy Lebeau; 09.11.2012
comment
Windows Server 2012 предоставляет API, который должен иметь возможность создавать сеанс пользователя. К сожалению, он недоступен в Windows 8 или предыдущих версиях Windows Server. См. msdn.microsoft.com/en-us /библиотека/dd919947%28v=vs.85%29.aspx - person Harry Johnston; 12.11.2012

@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);
        }
    }
}
person LorneCash    schedule 14.10.2018