Приветствую Вас ГостьЧетверг, 21.11.2024, 10:18

В помощь админу


Каталог статей

Главная » Статьи » Windows » Active Directory

Система удалённого сброса терминальных сессий.

Система удалённого сброса терминальных сессий. Под данным вопросом понимается система, которая способна автономно сбрасывать зависшие сессии в терминальном сервере даже если компьютер пользователя находится вне сети организации (например сотрудник уехал в командировку). Да, конечно можно использовать vpn, но хотелось сделать, чтобы было как можно проще для конечного юзера, что и навело на мысль использования нескольких прокладок в реализации этого небольшого проекта.

Итак с самого начала по порядку.

Была поставлена задача, чтобы любой сотрудник (в сети или за её пределами) мог в любой момент отправить команду сброса его терминальной сессии на сервер.

Так как vpn у нас настроен не у всех сотрудников, а так же есть филиал в отдельной подсети, то мною было принято решение сделать подобие системы приёма интернет-заказов магазинов. В таких системах сервер сам заказ получает по электронной почте с сайта интернет-магазина. Этот момент очень важный, так как эта прокладка не позволяет взломать сам сервер. Вторым важным моментом было принято решение зашифровать скрипт отправки электронной почты, дабы скрыть данные.

Скрипт ResetSession.js (скрипт написан на Java):

/* ****************************************************************
 *    The script sends a command to reset the terminal session    *
 * The script was written by Oleg Vladimirovich Anchurov in 2020. *
 ******************************************************************/

var WshShell = WScript.CreateObject("WScript.Shell");
var question = '\u0020\u0412\u044b\u0020\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0020\u0445\u043e\u0442\u0438\u0442\u0435\u0020\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0020\u043a\u043e\u043c\u0430\u043d\u0434\u0443\u0020\u0441\u0431\u0440\u043e\u0441\u0430\u0020\u0441\u0435\u0441\u0441\u0438\u0438\u0020\u043d\u0430\u0020\u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439\u0020\u0441\u0435\u0440\u0432\u0435\u0440\u0020\u0031\u0421\u003f';
var title = '\u0020\u0412\u043e\u043f\u0440\u043e\u0441';
var result = WshShell.Popup(question, 0, title, 1);

if (result == 1) {
    var CmpName = WshShell.ExpandEnvironmentStrings("%computername%");
    var UserName = WshShell.ExpandEnvironmentStrings("%username%");
    var EmailFrom = 'script@myfirma.ru';
/ Заменяем на свои данные
    var EmailTo = 'robot@myfirma.ru'; / Заменяем на свои данные
    var strSmtpServer = 'smtp.myfirma.ru'; / Заменяем на свои данные
    var EmailPassword = 'SuperPuperPassword'; / Заменяем на свои данные


    var Subject = "RS";
    var Textbody = '\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f\u0020\u043e\u0020\u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c\u043e\u0439\u0020\u0441\u0435\u0441\u0441\u0438\u0438';
    Textbody += ':\r\n';
    Textbody += '(' + CmpName + ',' + UserName + ')\r\n';
    Textbody += '\u041a\u043e\u043d\u0435\u0446\u0020\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438';
    Textbody += '.\r\n';

    try {
        var objEmail = new ActiveXObject("CDO.Message");
        objEmail.From = EmailFrom;
        objEmail.To = EmailTo;
        objEmail.Subject = Subject;
        objEmail.Textbody = Textbody;
        objEmail.Bodypart.Charset = 'windows-1251';
        objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2;
        objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSmtpServer;
        objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25;
        objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1;
        objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = EmailFrom;
        objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = EmailPassword;
        objEmail.Configuration.Fields.Update();
        objEmail.Send();
        var MSG = '\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u0020\u043e\u0020\u0441\u0431\u0440\u043e\u0441\u0435\u0020\u0441\u0435\u0441\u0441\u0438\u0438\u0020';
        MSG += UserName;
        MSG += '\u0020\u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0020\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e';                            
        WScript.Echo(MSG);
    } catch(e) {
        var MSG = Textbody;
        MSG += '\nError!!!\n' + "Number: " + e.number + '\nDescription: ' + e.description;
        WScript.Echo(MSG);
    }
}

WScript.Quit();

Данный скрипт я зашифровал с помощью скрипта-шифровальщика. Перед шифровыванием необходимо исправить настройки почтового сервера на свои (строки помечены красным).

Далее мне нужен был какой-либо компьютер или сервер с постоянно работающей электронной почтой. Мой выбор пал на сервер, на котором уже был установлен Microsoft Outlook для приёма информации от банка. На данном сервере уже был настроен скрипт автоматического сохранения входящих вложений в папку (пример), а 1С уже сам следил за содержанием этой папки и забирал оттуда все файлы для дальнейшего парсинга. Я договорился со своим начальником и добавил свои скрипты в Outlook, которые делают аналогичную процедуру, а также я добавил систему поиска электронной почты сотрудника в Active Directory для двух целей: так как в нашей конторе у всех учётных записей пользователей прописана электронная почта в соответствующем атрибуте mail, то я решил найчить Outlook отыскивать почтовые ящики пользователей, чтобы потом по этому адресу скрипт сброса терминальных сессий отправлял отчёт.

Также на терминальном сервере необходимо создать расшаренную папку для приёма информации о сбрасываемых сессиях. В моём случае я создал папку Input (пример создания) и дал права доступа на запись пользователям домена.

Ниже приведён скрипт RedirectCommandToRDPServer и 2 функции AllowedCharacters и FindEmailFromAD, которые необходимо в Outlook прописать в разделе (General) во вкладке "Разработчик" > VisualBasic:

Public Sub RedirectCommandToRDPServer(itm As Outlook.MailItem)
    Dim objAtt As Outlook.Attachment ' Переменная для работы с вложениями
    Dim saveFolder As String         ' Переменная для пути к папке сохранения
    Dim dateFormat As String         ' Переменная для даты письма
    Dim SenderEmailAddress As String ' Переменная для адреса
    Dim strBody As String            ' Переменная для тела письма
    Dim FSO, File, fn, cLine
    Dim Login As String
    'Определяем отправителя и текст письма
    'SenderEmailAddress = itm.SenderEmailAddress
    strBody = Trim(CStr(itm.Body))
    Simvol1 = InStr(strBody, "(")
    Simvol2 = InStr(strBody, ")")
    If Simvol1 > 0 And Simvol2 > 0 Then
        strBody2 = Mid(strBody, Simvol1 + 1, Simvol2 - Simvol1 - 1)
        Zapyataya = InStr(strBody, ",")
        If Zapyataya > 0 Then
            aBody = Split(strBody2, ",")
            SenderEmailAddress = itm.SenderEmailAddress
            'Задаём путь к папке сохранения
            saveFolder = "\\RDPSRV\Input"
' Необходимо сменить на свой адрес расшаренной папки.
            fn = saveFolder + "\ResetSession.txt"
            Login = AllowedCharacters(Trim(aBody(1)))
            If Login <> "" Then
                EmailAddress = FindEmailFromAD(Login)
                cLine = "reset session equal " + Login
                If EmailAddress <> "" Then cLine = cLine + ":" + EmailAddress
                Set FSO = CreateObject("Scripting.FileSystemObject")
                Set File = FSO.OpenTextFile(fn, 8, True) ' 8 - Добавить к файлу.
                File.WriteLine (cLine)
                Set FSO = Nothing ' Чистим память
                File.Close
            End If
        End If
    End If
End Sub

В данном скрипте красным отмечено место, где необходимо исправить место сохранения файла ResetSession.txt (помечено красным). Данный файл записывается по принцыпу дозаписи к концу файла, а скрипт, который его разбирает и распарсивает (приведён в конце статьи), после парсинга удаляет файл ResetSession.txt.

Далее функция, которая убирает лишние символы при парсинге входящей почты:

Function AllowedCharacters(InputText)
    AllowedCharacters = ""
    ListAllowedCharacters = Split("q w e r t y u i o p a s d f g h j k l z x c v b n m , Q W E R T Y U I O P A S D F G H J K L Z X C V B N M", " ")
    For i = 1 To Len(InputText)
        Simvol = Mid(InputText, i, 1)
        For j = 0 To 52
            If Simvol = ListAllowedCharacters(j) Then AllowedCharacters = AllowedCharacters + Simvol
        Next j
    Next i
End Function

Далее функция, которая пытается найти адрес электронной почты по логину пользователя (функция универсальная и не привязана к домену!):

Function FindEmailFromAD(Login)
    FindEmailFromAD = ""
    ' Итак, поехали
    Set objRootDSE = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext") ' Определяем имя домена
    Set adoCommand = CreateObject("ADODB.Command")
    Set adoConnection = CreateObject("ADODB.Connection")
    adoConnection.Provider = "ADsDSOObject"
    adoConnection.Open "Active Directory Provider"
    adoCommand.ActiveConnection = adoConnection
    strBase = "<LDAP://" & strDNSDomain & ">"
    ' Найти все активные учетные записи.
    ' Коды UseraccountControl тут: http://support.microsoft.com/kb/305144
    ' Все коды аттрибутов тут: http://www.computerperFormance.co.uk/Logon/LDAP_attributes_active_directory.htm
    strFilter = "(&(objectCategory=person)(objectClass=user))" ' - запрос по всем пользователям
    ' В переменной strAttributes обязательно перечисляем список атрибутов, которые переносятся, иначе работать не будет!
    strAttributes = "useraccountcontrol,sAMAccountName,mail"
    ' Формируем строку запроса.
    strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
    ' Выполним запрос.
    adoCommand.CommandText = strQuery
    adoCommand.Properties("Page Size") = 1000
' Максимальное количество пользователей, которое получит в ответе запрос к AD!
    adoCommand.Properties("Timeout") = 307
    adoCommand.Properties("Cache Results") = False
    Set objRS = adoCommand.Execute
    ' Обработаем полученные данные из запроса
    While Not objRS.EOF And FindEmailFromAD = ""
        strUserAccountControl = objRS.Fields("useraccountcontrol").Value
        uac = CLng(strUserAccountControl)
        strUserAccountControl2 = ""
        del = 8388608
        For i = 1 To 24
            a = uac \ del
            strUserAccountControl2 = strUserAccountControl2 + CStr(a)
            If a Then uac = uac - del
            del = del / 2
        Next
        strUserAccountControl2 = Mid(strUserAccountControl2, 15, 1) + Mid(strUserAccountControl2, 23, 1)
        If strUserAccountControl2 = "10" Then ' Незаблокированные учётные записи
            ' Получение информации
            strMail = objRS.Fields("mail").Value
            If strMail <> "" Then
                strsAMAccountName = objRS.Fields("sAMAccountName").Value
                If strsAMAccountName = Login Then
                    FindEmailFromAD = strMail
                End If
            End If
        End If
        objRS.MoveNext
    Wend
    Set adoCommand = Nothing    ' Чистим память
    Set adoConnection = Nothing ' Чистим память
End Function

Далее создаём в задание, что если приходит письмо от адреса script@myfirma.ru (Заменяем на свои данные) и в теме письма содержится "RS", то необходимо запустить Проект1.ThisOutlookSession.RedirectCommandToRDPServer.

Теперь переходим на терминальный сервер (в качестве примера в скрипте указано название RDPSRV). На этом сервере необходимо создать задание (пример создания), которое будет запускаться (например каждые 5 минут) и выполнять скрипт, который представляет из себя модифицированный скрипт, в основе которго использовал ранее зарекомендовавший себя скрипт сброса терминальных сессий, но пришлось его допилить (добавил парсер файла ResetSession.txt и возможность отправки отчёта не только админу, но и пользователю, если скрипты vba в Outlook (указанные выше) успешно найдут почту пользователя по логину.

Сам скрипт RDP_Reset_commands.vbs:

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Скрипт следит за терминальными пользователями и выкидывает их сессии по условиям: '
'    1.По какой-либо причине не произошёл выход из сессии                           '
'    2.Пользователь не закрывает сессию более 8 часов! Просто какой-то кашмар -     '
'      пора домой, а они кричат: "Хлебом не корми - работу давай!"                  '
'              Скрипт исправил Анчуров Олег Владимирович в 2021 году.               '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

On Error Resume Next
Dim WshShell, objScriptExec, CMPName
Set WshShell = CreateObject("Wscript.Shell")
Dim Apt(7, 150) ' задаем размер массива(максимально возможное число пользователей, например 50)
Dim User, Rdp, Id, Status, OffLine, TDate, TTime
Dim Line, Line2
Dim a, c, t, p, i, Reset
Dim Msg, Msg2, k2
Dim ind, kApt, kId
Dim Parametr, Parametr0, Parametr1, Parametr2, Parametr3, Parametr4
Dim FSO
Dim str, Arg
Dim Sdvig

Function DosToAnsi(Dos)
    DosToAnsi = ""
    'Convert Dos text to ANSI text:
    For i = 1 to Len(Dos)
        a = Asc(Mid(Dos,i,1))
        If a < 128 then DosToAnsi = DosToAnsi + chr(a)
        If a > 127 and a < 176 then DosToAnsi = DosToAnsi + chr(a + 64)
        If a > 175 and a < 224 then DosToAnsi = DosToAnsi + chr(a)
        If a > 223 and a < 240 then DosToAnsi = DosToAnsi + chr(a + 16)
        If a = 240 then DosToAnsi = DosToAnsi + chr(168)
        If a = 241 then DosToAnsi = DosToAnsi + chr(184)
        If a > 241 then DosToAnsi = DosToAnsi + chr(a)
    Next
End Function

CMPName = WshShell.ExpandEnvironmentStrings("%computername%")
Msg = "ПРОТОКОЛ РАБОТЫ СКРИПТА, ВЫКИДЫВАЮЩЕГО ПОЛЬЗОВАТЕЛЕЙ ИЗ ТЕРМИНАЛЬНЫХ СЕССИЙ НА ТЕРМИНАЛЬНОМ СЕРВАКЕ 1С:" & vbCrLf
Msg = Msg + "Ручной модуль сброса зависших сессий." + vbCrLf
Msg = Msg + "Имя сервера: " + CMPName & vbCrLf & vbCrLf
k2 = 0
kApt = -1

Parametr = False
Parametr1 = "include"    ' Параметр соответствия
Parametr3 = "logoff"    ' Параметр действия
Parametr4 = ""            ' Адрес электронной почты

Set FSO = CreateObject("Scripting.FileSystemObject")
fn = "C:\Input\ResetSession.txt"
'msgbox(fn)
'msgbox(FSO.FileExists(fn))
If FSO.FileExists(fn) Then
    Set File = FSO.GetFile(fn)
    Set TS = File.OpenAsTextStream(1)
    While Not TS.AtEndOfStream
        str = TS.ReadLine()
        str = LCase(str)
        str = Replace(str,"session","")
        strArr = Split(str," ")
        Msg = Msg + "    СТРОКА ПОТОКА: " + str & vbCrLf & vbCrLf
        For Each Ind in strArr
            Arg = Trim(Ind)
            ' Возможно условие с отрицанием
            If Arg = "not" Then
                Parametr0 = Arg
                Parametr = True
            ElseIf Arg = "include" Then    ' Допустимые значения (обязательный параметр, но по умолчанию и в случае ошибки примет значение logoff): include (содержит), equal (равен) или like
                Parametr1 = Arg
                Parametr = True            
            ElseIf Arg = "equal" Or Arg = "=" Then
                Parametr1 = "equal"
                Parametr = True
            ElseIf Arg = "logoff" Then    ' Допустимые значения (необязательный параметр, по умолчанию logoff): logoff или reset
                Parametr3 = Arg
                Parametr = True
            ElseIf Arg = "reset" Then
                Parametr3 = "reset session"
                Parametr = True
            ElseIf Arg = "<>" Then
                Parametr0 = "not"
                Parametr1 = "equal"
                Parametr = True
            Else                        ' Допустимые значения (имя/часть имени пользователя или похожее этому имени значение): любое
                Parametr2 = Arg            ' Параметр: логиин пользователя (Если после параметра стоит двоеточие и e-mail пользователя, то требуется отправка отчёта на данный e-mail)
                Parametr = True
            End If
        Next
        Dvoetochie = InStr(Parametr2, ":")
        If Dvoetochie Then
            Parametr4 = Mid(Parametr2, Dvoetochie + 1)
            Parametr2 = Left(Parametr2, Dvoetochie - 1)
        End If
        Set objScriptExec = WshShell.Exec("qUser.exe")
        Do Until objScriptExec.StdOut.AtEndOfStream
            Line = DosToAnsi(objScriptExec.StdOut.ReadLine)
        'Разщипляем строку на составляющие
        If Instr(Line, "отсутствует") Then Sdvig = 2 Else Sdvig = 0 ' Данная хня появилась в 2019 серваке
        User = LCase(Trim(Mid(Line, 2, 22)))
        Rdp = LCase(Trim(Mid(Line, 24, 16)))
        Id = LCase(Trim(Mid(Line, 40, 6)))
        Status = LCase(Trim(Mid(Line, 47, 8)))  'Если нужно, то раскоментировать!
        OffLine = LCase(Trim(Mid(Line, 55, 11 + Sdvig)))
        TDate = LCase(Trim(Mid(Line, 66 + Sdvig, 11)))  'Если нужно, то раскоментировать!
        TTime = LCase(Trim(Mid(Line, 77 + Sdvig, 6)))   'Если нужно, то раскоментировать!

            a = 0
            If Parametr Then
                If Parametr0 = "not" then
                    If Parametr1 = "include" Then
                        If Not InStr(User, Parametr2) > 0 Then a = a + 1
                    End If
                    If Parametr1 = "equal" Then
                        If Not(User = Parametr2) Then a = a + 1
                    End If
                Else
                    If Parametr1 = "include" Then
                        If InStr(User, Parametr2) > 0 Then a = a + 1
                    End If
                    If Parametr1 = "equal" Then
                        If (User = Parametr2) Then a = a + 1
                    End If
                End If
            End If
            If a > 0 then
                kId = -1
                For ik = 0 To kApt
                    If Apt(2, ik) = Id Then
                        kId = ik
                        Exit For
                    End If
                Next
                If kId < 0 Then
                    kApt = kApt + 1
                    Apt(0, kApt) = User
                    Apt(1, kApt) = RDP
                    Apt(2, kApt) = Id
                    Apt(3, kApt) = Status
                    Apt(4, kApt) = OffLine
                    Apt(5, kApt) = TDate
                    Apt(6, kApt) = TTime
                    Apt(7, kApt) = 1
                Else
                    Apt(7, kId) = Apt(7, kId) + 1
                End If
            End If
        Loop
    Wend
    TS.Close
    File.Delete
    set TS = nothing
    For ik = 0 To kApt
        Msg2 = ""
        User = Apt(0, ik)
        RDP = Apt(1, ik)
        Id = Apt(2, ik)
        Status = Apt(3, ik)
        OffLine = Apt(4, ik)
        TDate = Apt(5, ik)
        TTime = Apt(6, ik)
        kId = Apt(7, ik)
        Reset = Parametr3 + " " & Id & " /v"
        MsgBox(Reset)
        'Set objScriptExec = WshShell.Exec(Reset)
        Msg = Msg + "Отключен пользователь: " + User & vbCrLf
        Msg = Msg + "Значения параметров команды QUser для данного пользователя: " & vbCrLf
        Msg = Msg + "    Сеанс:     " + Rdp & vbCrLf
        Msg = Msg + "    ID:        " + Id & vbCrLf
        Msg = Msg + "    Статус:        " + Status & vbCrLf
        Msg = Msg + "    Бездействие: " + Offline & vbCrLf
        Msg = Msg + "    Время входа: " + TDate + "/" + TTime & vbCrLf & vbCrLf
        Do Until objScriptExec.StdOut.AtEndOfStream
            Line = DosToAnsi(objScriptExec.StdOut.ReadLine)
            'msgbox (Line)
            Msg2 = Msg2 + Line & vbCrLf
        Loop
        If Msg2 <> "" Then
            Msg = Msg + "Ответ команды Logoff " + Id + " для пользователя " + User + ":" & vbCrLf
            Msg = Msg + Msg2 + vbCrLf & vbCrLf
            k3 = k3 + 1
        End If
        k2 = k2 + 1
        WScript.Sleep 3000 'Это время (в млсек) ждёт скрипт, пока будет исполнена команда Logoff.
    Next

    If k2 > 0 Then
            Msg = Msg + "Итоги: " + String(41, "-") & vbCrLf
            MSG = MSG + "Всего отключено пользователей: " + CStr(k2) & vbCrLf & vbCrLf
            Msg = Msg + String(48, "*") & vbCrLf & vbCrLf

            Dim objEmail
            MSG = MSG + "Время/дата отработки скрипта: " + CStr(Time) + "/" + CStr(Date) & vbCrLf & vbCrLf

        Const EmailFrom = "script@myfirma.ru"     ' от кого будет отправляться e-mail
        Const EmailPassword = "SuperPuperPassword"       ' пароль от e-mail
        Const strSmtpServer = "smtp.myfirma.ru" ' smtp сервер
        Const EmailTo = "admin@myfirma.ru"    ' Кому будет отправляться e-mail
        Set objEmail = CreateObject("CDO.Message")
        objEmail.From = EmailFrom
        If Parametr4 Then
            objEmail.CC = Parametr4
            objEmail.To = EmailTo
        Else
            objEmail.To = EmailTo
        End If
        objEmail.Subject = CMPName + ": Отчёт по работе скрипта RDP_Reset_Command"  'Тема письма
        objEmail.Textbody = MSG
        objEmail.Bodypart.Charset = "windows-1251"
        objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
        objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
        objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusername") = EmailFrom
        objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendpassword") = EmailPassword
        objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSmtpServer
        objEmail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
        objEmail.Configuration.Fields.Update
        objEmail.Send
        Set objEmail = Nothing
    End If

End If

Места, где необходимо внести в скрипт свои изменения, помечены красным.

Ну и чтобы не было претедентов нечаянных я в папку Input на терминальном сервере положил текстовик с названием "СРОЧНО ПРОЧТИ!!!", внутрит которого я поместил вот такую напоминалку:

В этой папке появляется файл ResetSession с содержанием типа:
reset session equal ipetrov
или
reset session equal ipetrov:ipetrov@myfirma.ru
когда кто-либо отправляет команду сброса сессии на терминальный сервер.
Эта папка расшарена, её удалять нельзя!

Вот где-то так получается c кучей костылей вполне себе рабочий минипроект.

Жизнь админа должна быть проще...

Категория: Active Directory | Добавил: isz (27.04.2022)
Просмотров: 540 | Теги: RDP, терминаальная сессия, сброс сессии | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Категории раздела
Active Directory [12]
DHCP [1]
Windows [13]
Wins [1]
Групповая политика [3]
Программы [2]
Резервное копирование [6]
Сеть [5]
Скрипты [31]
Терминальный сервер [7]
Почта [7]
Реестр [2]
Реестр Windows
Командная строка [7]
CMD: Командная строка Windows
Поиск
Форма входа
Наш опрос
Оцените мой сайт
Всего ответов: 149
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика