Как определить IP-адрес клиента RDP в 1С программно

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе в терминальном режиме (RDP) часто возникает задача идентификации конкретного физического устройства, с которого подключился пользователь. Это может быть необходимо для привязки кассового оборудования, настройки принтеров или в целях безопасности. В этой статье мы подробно разберем, как получить IP-адрес клиента, используя стандартные средства Windows и возможности платформы 1С:Предприятие, не прибегая к установке сторонних компонент.

Метод 1: Использование переменной окружения CLIENTNAME и WMI

Самый простой и распространенный способ основан на том, что Windows при создании RDP-сессии сохраняет имя клиентского компьютера в переменной окружения CLIENTNAME. Зная имя компьютера, мы можем попытаться разрешить его в IP-адрес с помощью WMI-запроса к классу Win32_PingStatus.

Рассмотрим реализацию этого метода на языке 1С:


&НаКлиенте
Процедура ОпределитьIPПоИмениКлиента()
    // Получаем доступ к оболочке Windows
    WshShell = Новый COMОбъект("WScript.Shell");
    WshSysEnv = WshShell.Environment("Process");
    
    // Извлекаем имя клиентского ПК из переменной окружения
    ИмяКомпьютераКлиента = WshSysEnv.Item("CLIENTNAME");
    
    Если ЗначениеЗаполнено(ИмяКомпьютераКлиента) Тогда
        IPАдрес = ПолучитьIpАдресПКПоИмениХоста(ИмяКомпьютераКлиента);
        Сообщить("IP-адрес клиента: " + IPАдрес);
    Иначе
        Сообщить("Не удалось определить CLIENTNAME. Возможно, сеанс запущен не через RDP.");
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Функция ПолучитьIpАдресПКПоИмениХоста(АдресХоста)
    Результат = "0.0.0.0";
    Попытка
        oLoc = Новый COMОбъект("WbemScripting.SWbemLocator");
        oSrv = oLoc.ConnectServer(0, "/root/cimv2");
        // Выполняем WMI запрос для пинга хоста и получения его адреса
        ePng = oSrv.ExecQuery("SELECT * FROM Win32_PingStatus WHERE Address = '" + АдресХоста + "'");
        Для Каждого СтатусХоста из ePng Цикл
            Если СтатусХоста.StatusCode = 0 Тогда
                Результат = СтатусХоста.ProtocolAddress;
            КонецЕсли;
        КонецЦикла;
    Исключение
        Сообщить("Ошибка WMI: " + ОписаниеОшибки());
    КонецПопытки;
    Возврат Результат;
КонецФункции

Важное примечание: Этот метод имеет ограничения. Он будет эффективно работать только в том случае, если сервер 1С может "достучаться" до клиентского ПК по его имени (через DNS или NetBIOS). Если клиент находится за NAT или в другой подсети без настроенного разрешения имен, метод может вернуть ошибку или неверный адрес.

Метод 2: Чтение данных из ветки реестра Volatile Environment

Более надежный способ, который часто игнорируется, — это обращение к динамической ветке реестра текущего пользователя. При входе через RDP Windows создает раздел Volatile Environment, в котором хранятся параметры текущей сессии.

Проанализируем шаги для получения данных через реестр:

  1. Обращаемся к ветке HKEY_CURRENT_USER\Volatile Environment.
  2. Если сессий несколько, они могут быть пронумерованы (например, подраздел "1", "2").
  3. Ищем ключ RDP_CLIENT_ADDRESS.

Этот метод хорош тем, что не требует прав администратора и работает быстрее, чем WMI-запросы. Реализовать чтение можно через WScript.Shell и метод RegRead.

Метод 3: Использование системных утилит через макеты 1С

Если стандартные методы через COM-объекты не подходят, мы можем использовать проверенные временем системные утилиты, такие как GETTSCIP.exe. Чтобы не заставлять системных администраторов устанавливать дополнительные файлы на каждый сервер, применим небольшую хитрость: загрузим исполняемый файл прямо в конфигурацию 1С.

Разберем алгоритм реализации:

  1. Создаем в конфигурации Макет с типом "Двоичные данные".
  2. Загружаем в него необходимую утилиту (например, GETTSCIP.exe).
  3. В программном коде проверяем наличие файла во временном каталоге пользователя.
  4. Если файла нет — извлекаем его из макета.
  5. Запускаем файл, перехватываем поток вывода (StdOut) и парсим результат.

Пример кода для извлечения и запуска:


ПутьКФайлу = КаталогВременныхФайлов() + "getip.exe";
ФайлНаДиске = Новый Файл(ПутьКФайлу);

Если Не ФайлНаДиске.Существует() Тогда
    МакетПрограммы = УправлениеКлиентами.ПолучитьМакет("GETTSCIP");
    МакетПрограммы.Записать(ПутьКФайлу);
КонецЕсли;

// Запуск и получение результата
WshShell = Новый COMОбъект("WScript.Shell");
Команда = """" + ПутьКФайлу + """";
// Далее читаем StdOut как показано в примерах обсуждения

Метод 4: Анализ сетевых соединений через netstat

В ситуациях, когда права доступа сильно ограничены, можно проанализировать активные соединения сервера. Мы знаем, что RDP обычно работает на порту 3389. Проанализируем ситуацию: если мы выполним команду netstat -n, мы увидим список всех установленных соединений.

Алгоритм действий:

  1. Выполнить команду netstat -n -o (флаг -o добавит PID процесса).
  2. Найти соединения, где локальный адрес содержит порт 3389.
  3. Сопоставить PID процесса с текущим сеансом пользователя (например, через процесс rdpclip.exe, который уникален для каждой RDP-сессии).

Хотя этот метод кажется сложным в реализации из-за необходимости парсинга текстовых строк, он является "неубиваемым", так как опирается на реальные сетевые факты, а не на переменные, которые могут быть не заполнены.

Выводы и рекомендации

Подводя итог, можно сказать, что универсального метода "одной кнопкой" не существует, так как многое зависит от настроек сетевой безопасности предприятия. Наиболее профессиональным подходом для разработчика 1С будет комбинирование методов:

Использование COMОбъект("MSScriptControl.ScriptControl"), как упоминалось в обсуждении, сейчас считается устаревшим (особенно в 64-битных системах), поэтому рекомендуем ориентироваться на прямую работу с WScript.Shell или использование PowerShell-скриптов, которые можно запускать аналогичным образом.

← На главную