При разработке и администрировании систем на базе 1С:Предприятие часто возникает задача взаимодействия программных модулей с операционной системой Windows. Одной из классических проблем является запуск внешних консольных утилит или исполняемых файлов, требующих повышенных привилегий (прав администратора), в то время как сама сессия 1С или служба сервера 1С (USR1CV8) выполняется под учетной записью с жестко ограниченными правами.
Типичный пример такой задачи — необходимость отправить срочное оповещение пользователям терминального сервера (RDP) с помощью системной утилиты msg.exe. Если запустить команду msg * /server:ИмяСервера "Текст сообщения" через стандартный метод 1С ЗапуститьПриложение() из-под обычной учетной записи, операционная система вернет ошибку «Отказано в доступе». В рамках этой статьи мы подробно разберем, почему стандартные подходы не всегда работают, и рассмотрим пять эффективных практических способов решения данной проблемы.
Проанализируем базовые варианты, которые первыми приходят на ум системным администраторам и разработчикам, и выясним их ключевые недостатки:
runas /user:Administrator program.exe имеет критическое ограничение — она не умеет принимать пароль в качестве параметра командной строки из соображений безопасности. Система в любом случае потребует интерактивного ввода пароля в консоли. Использование ключа /savecred (сохранение учетных данных) работает локально и небезопасно в многопользовательской среде терминального сервера, так как любой пользователь сможет запустить любой процесс от имени сохраненного администратора.USR1CV8 прав локального или доменного администратора создает огромную брешь в безопасности всей корпоративной сети. В случае уязвимости в коде или выполнения произвольного кода через внешние обработки злоумышленник получит полный контроль над сервером.Ниже мы подробно разберем по шагам изящные, безопасные и проверенные на практике альтернативные методы запуска приложений с повышенными правами.
---
Выясним истинную причину проблемы. Почему утилита msg.exe выдает ошибку «Отказано в доступе» при вызове из-под системной учетной записи службы 1С? Дело вовсе не в отсутствии у пользователя прав локального администратора компьютера, а в отсутствии конкретного разрешения на отправку сообщений в настройках RDP-подключения (системный объект RDP-Tcp).
Windows позволяет точечно делегировать права на отправку системных сообщений обычным пользователям или группам без включения их в группу администраторов. Рассмотрим, как это настроить.
Администратору сервера достаточно один раз выполнить команду в консоли PowerShell от имени администратора:
wmic /namespace:\\root\CIMV2\TerminalServices PATH WIN32_TSAccount.TerminalName="RDP-TCP" call ModifyPermissions "BUILTIN\Remote Desktop Users", 7
Разберем параметры этой команды:
ModifyPermissions — метод изменения разрешений для подключений к удаленному рабочему столу.BUILTIN\Remote Desktop Users — имя группы пользователей (вы можете указать конкретного сервисного пользователя, например, USR1CV8).7 — битовая маска разрешений. Значение 7 (в некоторых версиях Windows требуется передавать 1) активирует право WINSTATION_MSG (SendMessage), разрешающее отправку сообщений пользователям сессий.После выполнения этой настройки на стороне операционной системы, вам больше не понадобятся ухищрения с паролями в коде 1С. Вызов команды в коде будет выглядеть стандартно и безопасно:
ПараметрыЗапуска = "* /server:LOCAL_SERVER ""Уважаемые пользователи, сервер перезагрузится через 10 минут!""";
ЗапуститьПриложение("msg.exe " + ПараметрыЗапуска);
---
Если особенности инфраструктуры не позволяют изменять права доступа RDP, мы можем использовать встроенный Планировщик задач Windows (Task Scheduler) в качестве безопасного посредника. Этот подход полностью исключает необходимость хранения пароля администратора в кодовой базе 1С.
Рассмотрим алгоритм настройки этого механизма по шагам:
Шаг 1. Создание задачи в Планировщике Windows:
taskschd.msc) на сервере.RunMsgSender.C:\1C_Scripts\send_msg.bat.Содержимое бат-файла send_msg.bat должно считывать параметры (текст сообщения) из заранее определенного временного текстового файла:
@echo off
set /p Message=<C:\1C_Scripts\temp_message.txt
msg * /server:localhost %Message%
Шаг 2. Вызов задачи из кода 1С:
В коде 1С перед запуском задачи мы сначала записываем текст сообщения во временный файл, а затем инициируем выполнение задачи планировщика через системную утилиту schtasks. Для запуска уже существующей задачи пользователю 1С не требуются административные права.
// Записываем текст сообщения во временный файл
Текст = Новый ЗаписьТекста("C:\1C_Scripts\temp_message.txt", КодировкаТекста.OEM);
Текст.ЗаписатьСтроку("Внимание! Технические работы.");
Текст.Закрыть();
// Запускаем задачу планировщика
ИмяЗадачи = "RunMsgSender";
КомандаЗапуска = "schtasks /run /tn """ + ИмяЗадачи + """";
ЗапуститьПриложение(КомандаЗапуска, , Истина); // Ждем завершения выполнения
Этот способ абсолютно безопасен, так как пароль администратора хранится в зашифрованном системном хранилище самого Планировщика задач, а не в коде конфигурации.
---
Инструментарий управления Windows (WMI) предоставляет мощные возможности для удаленного и локального администрирования. С его помощью мы можем программно запустить любой процесс от имени другого пользователя. Для этого в 1С используется работа с COM-объектом WbemScripting.SWbemLocator.
Посмотрим на пример реализации данного метода:
Локатор = Новый COMОбъект("WbemScripting.SWbemLocator");
// Подключаемся к пространству имен WMI локального компьютера с явным указанием учетных данных администратора
Попытка
СлужбаWMI = Локатор.ConnectServer(".", "root\cimv2", "ИмяАдминистратора", "ПарольАдминистратора");
СлужбаWMI.Security_.ImpersonationLevel = 3; // Уровень имитации Impersonate
Исключение
ЗаписьЖурналаРегистрации("ВнешнийЗапуск", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось подключиться к WMI под учетной записью администратора.";
КонецПопытки;
// Получаем доступ к классу Win32_Process для создания процессов
КлассПроцесс = СлужбаWMI.Get("Win32_Process");
ИдентификаторПроцесса = 0;
КомандаДляЗапуска = "msg * /server:localhost ""Сообщение отправлено через WMI!""";
// Метод Create запускает процесс в контексте безопасности указанного при подключении пользователя
Результат = КлассПроцесс.Create(КомандаДляЗапуска, Неопределено, Неопределено, ИдентификаторПроцесса);
Если Результат <> 0 Тогда
ЗаписьЖурналаРегистрации("ВнешнийЗапуск", УровеньЖурналаРегистрации.Предупреждение, , ,
"Ошибка создания процесса. Код возврата WMI: " + Строка(Результат));
Иначе
ЗаписьЖурналаРегистрации("ВнешнийЗапуск", УровеньЖурналаРегистрации.Информация, , ,
"Процесс успешно запущен. ID процесса: " + Строка(ИдентификаторПроцесса));
КонецЕсли;
Важное примечание: При использовании этого метода логин и пароль администратора передаются в открытом виде. Рекомендуется хранить эти учетные данные в защищенных параметрах информационной базы (например, в закрытых константах с ограничением прав доступа на чтение) и шифровать их встроенными средствами 1С перед сохранением.
---
Если стороннее программное обеспечение разрешено к использованию на сервере, отличным решением станет применение специализированных утилит шифрования параметров запуска, таких как RunAsSpc или CPAU. Эти утилиты заменяют стандартный runas, позволяя передавать пароль в зашифрованном виде.
Проанализируем процесс работы с утилитой RunAsSpc:
.spc (например, credential.spc). Пароль внутри этого файла надежно зашифрован ключом, привязанным к конкретному серверу.
ИмяУтилиты = """C:\Program Files\RunAsSpc\runasspc.exe""";
ПутьКФайлуШифра = """C:\1C_Scripts\credential.spc""";
ПолнаяКоманда = ИмяУтилиты + " /cryptfile:" + ПутьКФайлуШифра;
ЗапуститьПриложение(ПолнаяКоманда, , Истина);
Этот способ объединяет в себе простоту вызова из кода 1С и высокий уровень безопасности хранения учетных данных администратора.
---
Разберем самый простой «обходной» вариант запуска без использования стороннего софта и изменения настроек WMI. Он заключается в динамическом создании временного скрипта на языке VBScript, который эмулирует ручной ввод пароля в консольное окно runas.
Этот способ отлично подходит для некритичных разовых задач, однако его не рекомендуется использовать для высоконагруженных систем, так как задержки выполнения (таймауты) зависят от текущей загрузки процессора сервера.
Посмотрим на пример формирования и запуска такого скрипта из кода 1С:
// Определяем пути к временным файлам
ИмяФайлаСкрипта = КаталогВременныхФайлов() + "runas_helper.vbs";
// Формируем текст скрипта VBScript
ЗаписьVBS = Новый ЗаписьТекста(ИмяФайлаСкрипта, КодировкаТекста.ANSI);
ЗаписьVBS.ЗаписатьСтроку("Set WshShell = CreateObject(""WScript.Shell"")");
// Запускаем runas
ЗаписьVBS.ЗаписатьСтроку("WshShell.Run ""runas /user:Administrator """"msg * /server:localhost Срочное сообщение для всех!""""""");
// Ожидаем 500 миллисекунд, пока откроется окно консоли для ввода пароля
ЗаписьVBS.ЗаписатьСтроку("WScript.Sleep 500");
// Отправляем символы пароля в активное окно
ЗаписьVBS.ЗаписатьСтроку("WshShell.SendKeys ""СуперПарольАдминистратора""");
// Нажимаем клавишу Enter
ЗаписьVBS.ЗаписатьСтроку("WshShell.SendKeys ""{ENTER}""");
ЗаписьVBS.Закрыть();
// Запускаем полученный скрипт
ЗапуститьПриложение("wscript.exe """ + ИмяФайлаСкрипта + """", , Истина);
// Удаляем временный файл после выполнения, чтобы не оставлять пароль на диске
Попытка
УдалитьФайлы(ИмяФайлаСкрипта);
Исключение
// Обработка возможных исключений удаления файла
КонецПопытки;
Внимание: Используйте данный метод с осторожностью. Если во время выполнения скрипта пользователь случайно переключит фокус на другое окно (например, на окно блокнота или браузера), метод SendKeys отправит символы пароля в это активное окно, что приведет к компрометации пароля.
---
Мы подробно проанализировали пять различных подходов к решению задачи запуска процессов от имени другого пользователя в 1С. Подведем итоги и выберем оптимальный вариант: