Часто в организациях возникает ситуация, когда для экономии лицензий или упрощения администрирования создается одна общая учетная запись 1С (например, «Просмотрщик» или «Терминал»), под которой в базу заходят десятки реальных сотрудников через удаленный рабочий стол (RDP). В стандартной консоли администрирования 1С в таком случае все сеансы выглядят одинаково, что делает невозможным оперативный аудит или поиск виновника блокировки таблицы.
В данной статье мы разберем, как программно «вычислить» реального пользователя Windows, его IP-адрес и имя компьютера, с которого было выполнено подключение, даже если в 1С все авторизованы под одним именем.
Это классический и наиболее надежный способ получения системных данных Windows в среде 1С. Мы воспользуемся библиотеками WScript.Shell для чтения переменных окружения и WScript.Network для получения базовых свойств сети. Проанализируем пример кода, который можно разместить в модуле управляемого приложения.
Рассмотрим процедуру, которая получает данные о текущем пользователе ОС и клиентской машине:
Функция ПолучитьДанныеТерминальногоКлиента() Экспорт
Результат = Новый Структура("ИмяПользователяОС, ИмяКомпьютераКлиента, Сервер");
Попытка
// Создаем объект для работы с сетью
Network = Новый COMОбъект("WScript.Network");
Результат.ИмяПользователяОС = Network.UserName;
Результат.Сервер = Network.ComputerName;
// Создаем объект для работы с оболочкой (shell)
WshShell = Новый COMОбъект("WScript.Shell");
// Переменная CLIENTNAME содержит имя физического ПК, с которого зашли по RDP
ИмяКлиента = WshShell.ExpandEnvironmentStrings("%CLIENTNAME%");
// Если зашли не по RDP, переменная может вернуть строку "%CLIENTNAME%"
Если ИмяКлиента = "%CLIENTNAME%" Тогда
ИмяКлиента = "Локальный вход";
КонецЕсли;
Результат.ИмяКомпьютераКлиента = ИмяКлиента;
Исключение
Результат.ИмяПользователяОС = "Не определено";
Результат.ИмяКомпьютераКлиента = "Ошибка COM";
КонецПопытки;
Возврат Результат;
КонецФункции
В этом примере важно обратить внимание на переменную %CLIENTNAME%. В отличие от стандартного ComputerName, который в терминальной сессии всегда возвращает имя сервера, %CLIENTNAME% покажет имя реального системного блока, стоящего на столе у сотрудника.
Если ваша конфигурация работает на современных версиях платформы (8.3.10 и выше), мы можем обойтись без внешних COM-объектов, что повышает стабильность системы и избавляет от проблем с правами доступа к системным компонентам. Разберем использование функции ИмяПользователяОС().
Несмотря на то что в 1С авторизация прошла под общим пользователем, функция ИмяПользователяОС() на стороне клиента вернет именно ту учетную запись Windows, под которой запущена сессия RDP. Проанализируем, как это можно использовать при старте системы:
Процедура ПриНачалеРаботыСистемы()
// Получаем реальное имя Windows-юзера
ТекПользовательОС = ИмяПользователяОС();
// Получаем имя физического ПК через переменную окружения
ИмяКлиентскогоПК = ПолучитьПеременнуюОкружения("CLIENTNAME");
// Записываем данные в лог или регистр
ЗафиксироватьВходПользователя(ТекПользовательОС, ИмяКлиентскогоПК);
КонецПроцедуры
Метод ПолучитьПеременнуюОкружения() является более «чистым» аналогом работы с WScript.Shell, так как он встроен непосредственно в ядро 1С. Мы рекомендуем использовать именно его для кроссплатформенной совместимости (хотя для Windows-терминалов это не так критично).
Иногда требуется получить список всех активных пользователей терминала программно со стороны сервера. Для этого можно использовать системную команду quser. Этот метод полезен, если нужно сопоставить идентификаторы сессий.
Разберем пример реализации через запуск командной строки и парсинг текстового файла:
tFile = ПолучитьИмяВременногоФайла("txt");
Sh = Новый COMОбъект("WScript.Shell");
// Вызываем команду quser и перенаправляем вывод в файл
Sh.Run("cmd /c chcp 1251 & quser > """ + tFile + """", 0, Истина);
// Далее читаем файл
ТекстовыйДок = Новый ТекстовыйДокумент;
ТекстовыйДок.Прочитать(tFile, КодировкаТекста.ANSI);
Для НомерСтроки = 1 По ТекстовыйДок.КоличествоСтрок() Цикл
СтрокаДанных = ТекстовыйДок.ПолучитьСтроку(НомерСтроки);
// Здесь реализуем логику парсинга строки для выделения USERNAME и SESSIONNAME
КонецЦикла;
Обратите внимание: использование команды chcp 1251 необходимо для корректного отображения кириллицы в именах пользователей, если Windows имеет русскую локализацию.
Просто получить имя недостаточно, его нужно где-то хранить. Мы рекомендуем создать в конфигурации Регистр сведений под названием ТекущиеСессииWindows со следующей структурой:
НомерСеанса (Тип: Число) — сюда записываем НомерСеансаИнформационнойБазы().Пользователь1С (Тип: СправочникСсылка.Пользователи).WindowsЛогин (Тип: Строка).ИмяКомпьютера (Тип: Строка).ВремяВхода (Тип: Дата).Запись в этот регистр должна производиться в процедуре ПриНачалеРаботыСистемы. Таким образом, открыв этот регистр, администратор в любой момент увидит: «Сеанс №45, пользователь 1С: Просмотрщик, но фактически за компьютером ИВАНОВ-ПК сидит пользователь Windows ivanov_ia».
Дополнительно можно использовать объект СеансИнформационнойБазы. Рассмотрим, как получить данные о сеансах программно на сервере:
Сеансы = ПолучитьСеансыИнформационнойБазы();
Для Каждого ТекущийСеанс Из Сеансы Цикл
// Свойство ИмяПользователяОС доступно в объекте сеанса
ЛогинОС = ТекущийСеанс.ИмяПользователяОС;
ИмяКомпа = ТекущийСеанс.ИмяКомпьютера;
// Анализируем данные...
КонецЦикла;
Для решения задачи идентификации Windows-пользователей в среде RDP мы рекомендуем придерживаться следующей стратегии:
ИмяПользователяОС() и ПолучитьПеременнуюОкружения("CLIENTNAME").WScript будет более чем достаточно.Выяснив причину анонимности пользователей, мы превращаем «общую учетку» в прозрачный инструмент с возможностью четкого контроля действий каждого сотрудника в системе 1С.