В процессе разработки и администрирования систем на платформе 1С:Предприятие часто возникает задача определения контекста безопасности, в котором выполняется программный код. Особенно это актуально для серверных вызовов. Когда мы пишем код, работающий на стороне сервера (например, в фоновом задании или серверном модуле), он выполняется от имени учетной записи Windows, под которой запущена служба rphost.exe или ragent.exe в некоторых случаях. Знание этой учетной записи критически важно для диагностики проблем с доступом к сетевым папкам, внешним файлам, COM-объектам или реестру, а также при таких задачах, как установка комьюнити-лицензии на сервер 1С.
Разберем ситуацию: стандартная функция ПользователиИнформационнойБазы.ТекущийПользователь() возвращает имя пользователя внутри системы 1С, но ничего не говорит о правах в самой операционной системе. В данной статье мы проанализируем несколько эффективных способов получения имени системного пользователя Windows программными средствами 1С.
Проанализируем наиболее технологичный способ — обращение к инструментарию управления Windows (WMI). Этот метод позволяет получить информацию о владельце конкретного процесса напрямую из операционной системы. Для реализации нам понадобится доступ к объекту Win32_Process.
Рассмотрим подробнее алгоритм действий. Нам нужно найти процесс текущего сеанса и вызвать его метод GetOwner. Посмотрим на пример реализации этой задачи:
Функция ПолучитьИмяПользователяОС_WMI() Экспорт
// Подключаемся к службе WMI
Локатор = Новый COMОбъект("WbemScripting.SWbemLocator");
СлужбаWMI = Локатор.ConnectServer(".", "root\cimv2");
// Получаем ID текущего процесса (rphost для сервера)
ИдентификаторПроцесса = НомерПотокаПроцессора(); // Или другой способ получения PID
// Формируем запрос к процессам
Запрос = "SELECT * FROM Win32_Process WHERE ProcessId = " + Формат(ИдентификаторПроцесса, "ЧГ=0");
СписокПроцессов = СлужбаWMI.ExecQuery(Запрос);
Для Каждого Процесс Из СписокПроцессов Цикл
Пользователь = "";
Домен = "";
// Вызываем метод получения владельца
Результат = Процесс.GetOwner(Пользователь, Домен);
Если Результат = 0 Тогда
Возврат Домен + "\" + Пользователь;
КонецЕсли;
КонецЦикла;
Возврат "Не удалось определить";
КонецФункции
В данном коде мы используем объект SWbemLocator для подключения к локальному пространству имен root\cimv2. Метод GetOwner возвращает через параметры имя пользователя и домен. Это самый надежный способ, так как он работает непосредственно с дескриптором процесса в ядре ОС.
Если работа с WMI кажется избыточной или ограничена политиками безопасности, рассмотрим более простой, "консольный" метод. Мы можем выполнить стандартную команду Windows whoami и прочитать её вывод. Выясним причину популярности этого метода: он прост в реализации и не требует сложных манипуляций с объектной моделью WMI.
Разберем по шагам, как это реализовать в коде 1С, используя временный файл для перенаправления вывода:
Функция ПолучитьИмяПользователяЧерезShell() Экспорт
ИмяФайлаРезультата = ПолучитьИмяВременногоФайла("txt");
Команда = "cmd /c whoami > """ + ИмяФайлаРезультата + """";
// Создаем оболочку Shell
Оболочка = Новый COMОбъект("WScript.Shell");
// Выполняем команду в скрытом окне, ожидая завершения
Оболочка.Run(Команда, 0, Истина);
// Читаем результат из файла
ТекстРезультата = Новый ТекстовыйДокумент;
ТекстРезультата.Прочитать(ИмяФайлаРезультата, КодировкаТекста.OEM);
ИмяПользователя = СокрЛП(ТекстРезультата.ПолучитьТекст());
// Удаляем временный файл
Попытка
УдалитьФайлы(ИмяФайлаРезультата);
Исключение
КонецПопытки;
Возврат ИмяПользователя;
КонецФункции
В этом примере мы используем метод Run объекта WScript.Shell. Обратите внимание на второй параметр 0, который скрывает окно консоли, и третий параметр Истина, который заставляет систему дождаться окончания выполнения команды перед тем, как переходить к чтению файла. Это критически важно, чтобы избежать ошибки пустого файла.
Проанализируем ситуацию, когда нам достаточно получить имя пользователя из переменных окружения операционной системы. У каждого процесса Windows есть набор переменных, таких как USERNAME и USERDOMAIN. Посмотрим на пример, как быстро извлечь эти данные:
Функция ПолучитьПользователяИзОкружения() Экспорт
Оболочка = Новый COMОбъект("WScript.Shell");
ПроцессОкружения = Оболочка.Environment("Process");
ИмяПользователя = ПроцессОкружения.Item("USERNAME");
ДоменПользователя = ПроцессОкружения.Item("USERDOMAIN");
Если ЗначениеЗаполнено(ИмяПользователя) Тогда
Возврат ДоменПользователя + "\" + ИмяПользователя;
КонецЕсли;
Возврат "Не определено";
КонецФункции
Важный нюанс: переменные окружения типа Process предоставляют данные именно того процесса, в котором выполняется код 1С. Если код запущен на сервере, вы получите данные учетной записи службы 1С:Предприятие.
Рассмотрим подробнее сценарии применения этих знаний. Часто разработчики сталкиваются с ошибкой "Доступ запрещен" при попытке записи файла на сетевой ресурс. Проблема заключается в том, что системная учетная запись (например, USR1CV8 или LocalService) не имеет прав доступа к этому ресурсу, хотя у самого программиста под его личной учеткой все работает отлично.
Используя приведенные выше методы, мы можем:
Administrator.Важное замечание: При работе в кластере 1С помните, что код может выполняться на разных рабочих серверах. Если служба на сервере А запущена под одной учетной записью, а на сервере Б под другой — это может привести к плавающим ошибкам. Использование WScript.Shell и WMI поможет быстро локализовать такие расхождения в конфигурации фермы серверов.
Таким образом, мы проанализировали три основных подхода к получению имени пользователя ОС. Выбор конкретного метода зависит от ваших предпочтений и ограничений среды исполнения. Метод с WMI является наиболее профессиональным и точным, в то время как использование WScript.Shell и whoami — самым простым в отладке.