Приветствую Вас ГостьСреда, 18.09.2019, 17:10

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


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

Главная » Статьи » Windows » Скрипты

Скрипт автоматически выкидывающий пользователей из терминальной сессии. Финальная версия.

Это финальное продолжение моей давней разработки скрипта, автоматического выкидывания пользователей на терминальном сервере. Больше этот скрипт переделывать не собираюсь, так как на мой взгляд он достиг совершенства!

Что нового:

  1. Исправлен страшный косяк, связанный с нечаянным отключением терминальных сессий. Дело в том, что в процессе работы было выявлено, что по вине провайдеров иногда бывают кратковременные провалы интернета и скрипт просто-напросто выкидывал сессии пользователей без разбора. В новой финальной версии я научил скрипт проверять достоверность обрыва сессии повторными проверками (у меня их 10) и в случае, если все эти проверки показывают, что связь разорвана, то только в этом случае происходит отключение сессии.
  2. По просьбам трудящихся была добавлена возможность править некоторые параметры работы скрипта, изменяя закомментированные переменные в начале скрипта.

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

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

On Error Resume Next
Dim WshShell, objScriptExec, CMPName
Set WshShell = CreateObject("Wscript.Shell")
Dim Apt(7, 50) ' задаем размер массива(максимально возможное число пользователей, например 50)
Dim User, Rdp, Id, Status, OffLine, TDate, TTime
Dim Line, Line2
Dim a, c, t, p, i, Reset
Dim Msg, k1, k2
Dim Pause, Kol, MaxHour
Dim ind, kApt, kId
Dim AdminovNeTrogaem, Zolushka

CMPName = WshShell.ExpandEnvironmentStrings("%computername%")

Msg = "ПРОТОКОЛ РАБОТЫ СКРИПТА, АВТОМАТИЧЕСКИ ВЫКИДЫВАЮЩЕГО ПОЛЬЗОВАТЕЛЕЙ ИЗ ТЕРМИНАЛЬНЫХ СЕССИЙ НА ТЕРМИНАЛЬНОМ СЕРВАКЕ 1С:" & vbCrLf
Msg = Msg + "Имя сервера: " + CMPName & vbCrLf & vbCrLf
k1 = 0
k2 = 0
kApt = -1
Pause = 10    ' Размер паузы в секундах между повторными проверками
Kol = 10    ' Количество проверок в разах
MaxHour = 8    ' Максимальное количество часов неактивности сесиии, если < 1 то не будет проверки.

AdminovNeTrogaem = True    ' Учётки админов не трогаем (true - админов не трогаем/false - админов трогаем).
Zolushka = True            ' В полночь закрываем все сессии, даже администраторские (true - выкидываем всех/false - не выкидываем). Этот параметр стоит выше параметра AdminovNeTrogaem и на него не обращает внимания!

Msg = Msg + "Количество проверок скрипта (в разах): " + CStr(Kol) & vbCrLf
Msg = Msg + "Длительность паузы между проверками (в секундах): " + CStr(Pause)  & vbCrLf & vbCrLf
Msg = Msg + String(48, "*") & vbCrLf & vbCrLf

h = Hour(Now)

For ind = 1 To Kol
    Set objScriptExec = WshShell.Exec("qUser.exe")
    Do Until objScriptExec.StdOut.AtEndOfStream
        Line = objScriptExec.StdOut.ReadLine
        Line2 = ""
        'Производим перекодировку текста из Dos в ANSI:
        For i = 1 to Len(Line)
            a = Asc(Mid(Line,i,1))
            If a < 128 then Line2 = Line2 + chr(a)
            If a > 127 and a < 176 then Line2 = Line2 + chr(a + 64)
            If a > 175 and a < 224 then Line2 = Line2 + chr(a)
            If a > 223 and a < 240 then Line2 = Line2 + chr(a + 16)
            If a = 240 then Line2 = Line2 + chr(168)
            If a = 241 then Line2 = Line2 + chr(184)
            If a > 241 then Line2 = Line2 + chr(a)
        Next
        Line = Line2
        
        'Разщипляем строку на составляющие
        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)))
        TDate = LCase(Trim(Mid(Line, 66, 11)))  'Если нужно, то раскоментировать!
        TTime = LCase(Trim(Mid(Line, 77, 6)))   'Если нужно, то раскоментировать!

        'Первая строка нас не интересует!
        'Переменная Rdp может принимать следующие значения:
        'rdp-tcp#xxx   - стандартный клиент RDP
        'console       - консоль, например из DameWare
        'пустая строка - пользователь отключился некорректно
        If Rdp <> "сеанс" Then 'Те пользователи, кто в сеансе, их не трогаем! Остальных проверяем по логину....

            a = 0
            If AdminovNeTrogaem Then
                ' Список администраторов, которых трогать не нужно выкидывать из сессий.
                ' Список может содержать любое количество записей и даже отсутствовать!
                    a = a + InStr(User,"admin1") 'Эту учётку трогать низя!
                    a = a + InStr(User,"admin2") 'Эту учётку трогать низя!
                    a = a + InStr(User,"admin3") 'Эту учётку трогать низя!
                    a = a + InStr(User,"admin4") 'Эту учётку трогать низя!
            End If
            'Остальные учётки проверяем дальше...    
            If h = 0 And Zolushka Then a = 0 'В период времени с 0:00 до 0:59 будут отключены абсолютно все учётные записи, даже администраторские!
            If a = 0 then 'Если логин не в списке исключений, то проверяем показатели учётки...

                c = 0
                t = 0
                p = 0
                If Rdp <> "" then 'Исключительно для 2012 сервака проверка, так как по параметру OffLine нельзя в нём определить некорректное отключение от сессии!
                    If OffLine = "отсутствует" then
                        c = c + 1 'Если была закрыта сессия просто крестиком или по какой-либо причине не произошёл выход из системы, то сразу необходимо выкинуть пользователя из сессии!
                    Else
                        If OffLine = "." Then OffLine = "0:00"
                        p = InStr(OffLine,  ":")
                        If p = 0 Then OffLine = "0:" + OffLine
                    End If
                    p = InStr(OffLine,  ":")
                    If p > 0 then
                        'Проверяем количество времени простоя
                        d = InStr(OffLine, "+")
                        t = CDbl(Left(OffLine, p - 1)) + 24 * CDbl(Left(OffLine, d - 1))
                        If t > MaxHour then c = c + 1 'Если время сессии больше заданной переменной MaxHour, то выкидываем из сессии!
                    End If
                Else
                    c = c + 1 ' В 2012 серваке параметр Rdp будет пустым в случае некоректного отключения пользователя от сессии!
                End If
                If c > 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
            End If
        End If
    Loop
    WScript.Sleep (Pause * 1000) ' Выдерживаем паузу между опросами, дабы выявить нестабильные каналы связи
Next

For ik = 0 To kApt
    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)
    If kId = Kol Then
        Reset = "logoff " & Id 'Команду LogOff можно заменить на Reset Session. Кому что больше подходит.
        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
        k2 = k2 + 1
        WScript.Sleep 3000 'Это время (в млсек) ждёт скрипт, пока будет исполнена команда Logoff.
    End If
    If kId > 0 And kId < Kol Then
        k1 = k1 + 1
    End If
Next

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

If k1 > 0 Then
    Msg = Msg + "Обнаружены нестабильные сесиии!" & vbCrLf
    MSG = MSG + "Список нестабильных сессий:" & vbCrLf
    Msg = Msg + String(48, "-") & vbCrLf & vbCrLf
End If
k1 = 0

For ik = 0 To kApt
    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)
    If kId > 0 And kId < Kol Then
        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
        k1 = k1 + 1
    End If
Next

If k1 > 0 Then
    Msg = Msg + "Итоги: " + String(41, "-") & vbCrLf
    MSG = MSG + "Всего нестабильных сессий пользователей: " + CStr(k1) & vbCrLf & vbCrLf
    Msg = Msg + String(48, "*") & vbCrLf & vbCrLf
    MSG = MSG + "Стоит обратить внимание на тот факт, что есть нестабильные сессии!" & vbCrLf
    MSG = MSG + "Это может быть связано с несколькими причинами." & vbCrLf
    MSG = MSG + "Например:" & vbCrLf
    MSG = MSG + "    1. Где-то глючат каналы связи у промежуточных провайдеров;" & vbCrLf
    MSG = MSG + "    2. Не хватает полосы пропускания у Вашего провайдера для одновременного доступа такого количества одновременных сессий;" & vbCrLf
    MSG = MSG + "        (советуется проверить доступность удалённых узлов с помощью утилит командной строки: ping, tracert, nslookup и pathping);" & vbCrLf
    MSG = MSG + "    3. У Вашего сервера не хватает ресурсов для терминального доступа такого количества пользователей." & vbCrLf
    MSG = MSG + "        (советуется проверить ресурсы терминального сервера с помощью монитора ресурсов);" & vbCrLf & vbCrLf
End If
    
Set objScriptExec = Nothing
Set WshShell = Nothing

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

    Const EmailFrom = "bot@firma.ru"        ' от кого будет отправляться e-mail
    Const EmailPassword = "SuperPassword"    ' пароль от e-mail
    Const strSmtpServer = "smtp.firma.ru"    ' smtp сервер
    Const EmailTo = "admin@firma.ru"        ' Кому будет отправляться e-mail
    Set objEmail = CreateObject("CDO.Message")
    
    objEmail.From = EmailFrom
    objEmail.To = EmailTo
    objEmail.Subject = CMPName + ": Отчёт по работе скрипта RDP_Reset"  'Тема письма
    objEmail.Textbody = MSG
    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

Некоторые выводы, сделанные мною в процессе использования финальной версии скрипта:

  1. На моё удивление, скрипт стал работать примерно в два раза быстрее!
  2. Жалобы, связанные с внезапным отключением терминальных сессий прекратились от сотрудников!

Берите, правьте, пользуйтесь на здоровье!

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

Категория: Скрипты | Добавил: isz (24.03.2017)
Просмотров: 1405 | Комментарии: 10 | Теги: терминальная сессия, пользователь, Скрипт, терминал, терминальный сервер, vbscript, vbs | Рейтинг: 0.0/0
Всего комментариев: 10
0
9 korsar1992  
Здравствуйте! Как тут вообще разобраться? практически весь текст - это есть команда bat-файла? Поясните пожалуйста! smile

0
10 isz  
Это не bat-файл. Делайте расширение VBS
Просто скопируйте весь скрипт и вставьте в блокнот, а лучше в Notepad++, потом сохраните, а затем смените расширение с txt на vbs

0
8 isz  
Исправлен баг с администраторскими учётками. Их всё равно выбрасывало. Помечено другим цветом место исправления.
Скрипт исправлен.
Старый кусок кода:
a = 0
If h > 0 And Zolushka Then 'В период времени с 0:00 до
0:59 будут отключены абсолютно все учтные записи, даже
администраторские!
If AdminovNeTrogaem Then
' Список администраторов, которых трогать не нужно выкидывать из сессий.
' Список может содержать любое количество записей и даже отсутствовать!
a = a + InStr(User,"admin1") 'Эту учётку трогать низя!
a = a + InStr(User,"admin2") 'Эту учётку трогать низя!
a = a + InStr(User,"admin3") 'Эту учётку трогать низя!
a = a + InStr(User,"admin4") 'Эту учётку трогать низя!
End If
'Остальные учётки проверяем дальше...
End If
If a = 0 then 'Если логин не в списке исключений, то проверяем показатели учётки...
Новый код исправленный:
a = 0
If AdminovNeTrogaem Then
' Список администраторов, которых трогать не нужно выкидывать из сессий.
' Список может содержать любое количество записей и даже отсутствовать!
a = a + InStr(User,"admin1") 'Эту учётку трогать низя!
a = a + InStr(User,"admin2") 'Эту учётку трогать низя!
a = a + InStr(User,"admin3") 'Эту учётку трогать низя!
a = a + InStr(User,"admin4") 'Эту учётку трогать низя!
End If
'Остальные учётки проверяем дальше...
If h = 0 And Zolushka Then a = 0 'В период времени с 0:00 до 0:59 будут отключены абсолютно все учётные записи, даже администраторские!
If a = 0 then 'Если логин не в списке исключений, то проверяем показатели учётки...
Все, кто брал себе скрипт до 13.10.2017 могут обновиться...

6 XageBy  
А в какой кодировке должен быть сохранен скрипт?

0
7 isz  
Очень хороший и правильный вопрос! Отвечаю Вам и тем, кто будет ещё пытаться этот или любой другой с моего сайта использовать скрипт. Откройте скрипт обычным блокнотом и сохраните с кодировкой ANSI.

4 XageBy  
Доброго времени суток. Спасибо за ответ. Учетка администратора - локальная. Может подскажите чего подкрутить в локальной политике безопасности что бы отчеты уходили?

0
5 isz  
Попробуйте подправить конфигурацию усиленной безопасности Internet Explorer. + В брэндмауэре 25 порт для smtp нужно открыть.

1 XageBy  
Доброго времени суток. Решил воспользоваться Вашим скриптом. К сожалению в 00:00 никакие пользователи не отключаются от сервера и отчет на почту не уходит. Подскажите как его правильно запускать. Система Windows Server 2008 R2.
Спасибо.

0
2 isz  
У меня этот скрипт успешно работает и на 2008 R2 и на 2012. Я и сам на первых парах наступал на эти грабли. Дело в том, что по мнению мелкомягких администратор домена - это "не админ". Мой скрипт работает правильно только от локального администратора. Вы это и сами можете легко проверить: в командной строке от вашей учётки и от локального администратора испытайте команду reset session.

0
3 isz  
По поводу почты - это отдельный разговор. По умолчанию локальная политика безопасности 2008 R2 блокирует любые соединения c интернетом.

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Категории раздела
Active Directory [10]
DHCP [1]
Windows [12]
Wins [1]
Групповая политика [2]
Программы [2]
Резервное копирование [5]
Сеть [5]
Скрипты [25]
Терминальный сервер [6]
Почта [5]
Реестр [1]
Реестр Windows
Командная строка [6]
CMD: Командная строка Windows
Поиск
Форма входа
Наш опрос
Оцените мой сайт
Всего ответов: 108
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика