Bat-файл из кода 1С: ожидание, скрытое окно, права и лог
Содержание
Запустить bat-файл из 1С проще всего методом глобального контекста ЗапуститьПриложение("cmd.exe /c ""C:\Scripts\backup.bat""", , Истина, КодВозврата). Третий параметр заставляет 1С дождаться конца работы скрипта, а в переменную КодВозврата попадёт число, которое bat вернул командой exit /b.
Дальше начинаются нюансы, на которых спотыкаются чаще всего: пути с пробелами, чёрное окно консоли, права администратора, кракозябры в логе и код, который на сервере ведёт себя иначе, чем на клиенте. Ниже — рабочие примеры для каждого случая на платформе 8.3.
Базовый запуск bat-файла через ЗапуститьПриложение
Метод ЗапуститьПриложение есть в тонком и толстом клиенте и на сервере. В веб-клиенте он недоступен — там работают только асинхронные варианты из следующего раздела.
Параметры метода:
| Параметр | Что передать | Пример |
|---|---|---|
| СтрокаКоманды | Командная строка целиком | "cmd.exe /c ""C:\Scripts\run.bat""" |
| ТекущийКаталог | Рабочая папка скрипта | "C:\Scripts" |
| ДождатьсяЗавершения | Ждать ли окончания | Истина / Ложь |
| КодВозврата | Переменная для кода выхода | КодВозврата |
Минимальный пример без ожидания:
&НаКлиенте
Процедура ЗапуститьСкрипт(Команда)
ЗапуститьПриложение("cmd.exe /c ""C:\Scripts\run.bat""", "C:\Scripts");
КонецПроцедуры
Почему лучше вызывать через cmd.exe /c
Bat-файл можно передать в СтрокаКоманды и напрямую, без cmd.exe. Но явный вызов интерпретатора даёт три преимущества:
- ✅ предсказуемый код возврата из
exit /b N; - ✅ можно добавить перенаправление вывода
> log.txt 2>&1; - ✅ одинаковое поведение на разных машинах, независимо от ассоциаций файлов.
Пути с пробелами и параметры
Главная ловушка — кавычки. В строке 1С кавычка внутри литерала удваивается, а cmd /c ещё и снимает внешнюю пару кавычек. Поэтому команду с пробелами в пути оборачивают в дополнительные кавычки целиком:
Скрипт = "C:\Program Files\Обмен\выгрузка.bat";
Параметр1 = "D:\Выгрузки\2024";
Команда = "cmd.exe /c """"" + Скрипт + """ """ + Параметр1 + """""";
// В итоге cmd получит: ""C:\Program Files\Обмен\выгрузка.bat" "D:\Выгрузки\2024""
ЗапуститьПриложение(Команда, , Истина, КодВозврата);
Внутри bat параметры читаются как %1, %2 и т. д., а %~1 убирает кавычки вокруг значения.
Чтобы не мучиться с кавычками, собирайте команду через СтрШаблон: СтрШаблон("cmd.exe /c """"%1"" ""%2""""", Скрипт, Параметр1). Строку команды перед запуском выведите через Сообщить() — ошибки в кавычках сразу видны.
Как дождаться завершения bat и получить код возврата
Если после скрипта 1С должна прочитать результат (файл выгрузки, лог), запуск обязан быть синхронным. Иначе код пойдёт дальше раньше, чем bat создаст файл.
Синхронный вариант
КодВозврата = 0;
ЗапуститьПриложение("cmd.exe /c ""C:\Scripts\export.bat""", "C:\Scripts", Истина, КодВозврата);
Если КодВозврата <> 0 Тогда
ВызватьИсключение СтрШаблон("Скрипт завершился с кодом %1", Формат(КодВозврата, "ЧН=0; ЧГ=0"));
КонецЕсли;
КодВозврата заполняется только при ДождатьсяЗавершения = Истина. Без ожидания переменная останется такой, какой была до вызова.
Чтобы код был осмысленным, bat должен его возвращать:
@echo off
xcopy "C:\Data\*.xml" "\\fileserver\exchange\" /Y
if errorlevel 1 exit /b 2
exit /b 0
Не используйте в такой схеме start. Команда cmd /c start ... возвращает управление сразу, и 1С не будет ждать реальной работы скрипта.
Асинхронный вариант на клиенте
Синхронное ожидание замораживает интерфейс: пока bat работает, пользователь видит «зависшую» программу. В конфигурациях, где отключены синхронные вызовы, и в веб-клиенте используют асинхронные методы.
Через описание оповещения:
&НаКлиенте
Процедура Выгрузить(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеЗавершенияСкрипта", ЭтотОбъект);
НачатьЗапускПриложения(Оповещение, "cmd.exe /c ""C:\Scripts\export.bat""", "C:\Scripts", Истина);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗавершенияСкрипта(КодВозврата, ДополнительныеПараметры) Экспорт
Если КодВозврата = 0 Тогда
Сообщить("Выгрузка завершена");
Иначе
Сообщить("Ошибка, код " + Формат(КодВозврата, "ЧН=0; ЧГ=0"));
КонецЕсли;
КонецПроцедуры
На платформе с номером не ниже 8.3.18 удобнее Асинх/Ждать:
&НаКлиенте
Асинх Процедура Выгрузить(Команда)
КодВозврата = Ждать ЗапуститьПриложениеАсинх("cmd.exe /c ""C:\Scripts\export.bat""", "C:\Scripts", Истина);
Сообщить("Код возврата: " + Формат(КодВозврата, "ЧН=0; ЧГ=0"));
КонецПроцедуры
В веб-клиенте запуск внешних программ требует установленного расширения для работы с 1С:Предприятием в браузере.
Запуск bat без окна консоли через WScript.Shell
ЗапуститьПриложение всегда показывает чёрное окно cmd. Для фоновых операций оно мешает и пугает пользователей. На Windows окно прячут через COM-объект WScript.Shell и его метод Run:
Shell = Новый COMОбъект("WScript.Shell");
// 0 — скрытое окно, Истина — ждать завершения
КодВозврата = Shell.Run("cmd.exe /c ""C:\Scripts\export.bat""", 0, Истина);
Второй параметр Run — стиль окна: 0 прячет окно, 1 показывает обычным, 7 — свёрнутым. Третий параметр включает ожидание, и тогда метод возвращает код выхода.
У WScript.Shell есть и метод Exec, который даёт доступ к потокам StdOut и StdErr. Но окно консоли он не прячет, поэтому для «тихого» запуска с логом надёжнее связка Run + перенаправление в файл (см. раздел про логирование).
COM работает только в Windows и только там, где разрешено создание COM-объектов: в толстом и тонком клиенте под Windows и на сервере 1С под Windows.
Права администратора и UAC при запуске bat-файла
Ни ЗапуститьПриложение, ни WScript.Shell.Run не умеют повышать права. Скрипт стартует с правами того пользователя Windows, под которым работает процесс 1С. Если bat останавливает службу, пишет в C:\Windows или правит реестр в ветке HKLM, он упадёт с «Отказано в доступе».
На клиенте: запрос UAC через Shell.Application
У объекта Shell.Application метод ShellExecute принимает «глагол» runas, который вызывает окно UAC:
Shell = Новый COMОбъект("Shell.Application");
Shell.ShellExecute("cmd.exe", "/c ""C:\Scripts\admin_task.bat""", "C:\Scripts", "runas", 1);
Ограничения способа:
- ⚠️ пользователь должен подтвердить окно UAC, а при обычной учётке — ввести пароль администратора;
- ⚠️
ShellExecuteне ждёт завершения и не возвращает код выхода; - ⚠️ на сервере 1С окно UAC показать некому, способ там бесполезен.
Без диалога: задание планировщика Windows
Рабочий приём администраторов: создать в планировщике заданий Windows задачу с галкой «Выполнить с наивысшими правами», а из 1С только запускать её:
ЗапуститьПриложение("schtasks /run /tn ""1C_AdminTask""", , Истина, КодВозврата);
Так bat получает нужные права, пароль администратора не хранится ни в коде, ни в скрипте, а пользователь 1С может только запустить готовое задание. Учтите: schtasks /run лишь ставит задачу на запуск и возвращает управление, не дожидаясь конца её работы. Результат скрипт должен оставить в файле, который 1С потом прочитает.
Обработка ошибок и запись вывода bat в лог
Без лога любой сбой скрипта выглядит одинаково: «ничего не произошло». Минимальный набор: ловить исключение при запуске, проверять код возврата и сохранять вывод консоли.
Перенаправление вывода в файл
&НаСервере
Функция ВыполнитьСкрипт(ПутьКСкрипту)
ФайлЛога = ПолучитьИмяВременногоФайла("txt");
Команда = СтрШаблон("cmd.exe /c """"%1"" > ""%2"" 2>&1""", ПутьКСкрипту, ФайлЛога);
КодВозврата = -1;
Попытка
ЗапуститьПриложение(Команда, , Истина, КодВозврата);
Исключение
ЗаписьЖурналаРегистрации("Запуск bat", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
ТекстЛога = "";
Если Новый Файл(ФайлЛога).Существует() Тогда
Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(ФайлЛога, КодировкаТекста.OEM);
ТекстЛога = Текст.ПолучитьТекст();
УдалитьФайлы(ФайлЛога);
КонецЕсли;
Уровень = ?(КодВозврата = 0, УровеньЖурналаРегистрации.Информация, УровеньЖурналаРегистрации.Ошибка);
ЗаписьЖурналаРегистрации("Запуск bat", Уровень, , ,
СтрШаблон("Код %1. Вывод:%2%3", Формат(КодВозврата, "ЧН=0; ЧГ=0"), Символы.ПС, ТекстЛога));
Возврат КодВозврата = 0;
КонецФункции
Что здесь сделано:
> файл 2>&1пишет в один файл и обычный вывод, и сообщения об ошибках.Попыткаловит сбой самого запуска (например, неверный путь кcmd.exeили запрет запуска приложений).- Вывод вместе с кодом возврата сохраняется в журнал регистрации — его потом видно в
Администрирование → Обслуживание → Журнал регистрациипо событию «Запуск bat».
Кодировка: откуда берутся кракозябры
Консоль Windows по умолчанию пишет вывод в OEM-кодировке (кодовая страница 866 для русской локали). Поэтому лог читают с КодировкаТекста.OEM. Если в начале bat стоит chcp 65001, вывод идёт в UTF-8, и читать его нужно уже с КодировкаТекста.UTF8.
Та же история с самим bat-файлом. Если 1С формирует скрипт на лету и в нём есть кириллица (пути к папкам, имена файлов), записывайте его в OEM:
Скрипт = Новый ТекстовыйДокумент;
Скрипт.ДобавитьСтроку("@echo off");
Скрипт.ДобавитьСтроку("copy ""D:\Выгрузка\*.xml"" ""\\server\Обмен\"" /Y");
Скрипт.ДобавитьСтроку("exit /b %errorlevel%");
Скрипт.Записать("C:\Scripts\copy_xml.bat", КодировкаТекста.OEM);
Скрипт, сохранённый в UTF-8, cmd прочитает неверно, и кириллические пути «сломаются».
exit /b с кодом ошибки, или 1С запущена без ожидания. Добавьте проверку if errorlevel 1 exit /b 1 и передайте ДождатьсяЗавершения = Истина.pause в конец bat и запустите вручную.КодировкаТекста.OEM, после chcp 65001 — UTF8.ТекущийКаталог и проверьте, где выполняется код: на клиенте или на сервере.Запуск bat-файла на сервере 1С в клиент-серверном варианте
В файловой базе почти весь код выполняется на компьютере пользователя, и путаницы мало. В клиент-серверной базе важна директива компиляции процедуры:
| Где код | Где запустится bat | Под каким пользователем Windows |
|---|---|---|
&НаКлиенте | На компьютере пользователя | Учётная запись пользователя |
&НаСервере, общий модуль сервера | На рабочем сервере кластера 1С | Учётная запись службы сервера 1С |
| Регламентное или фоновое задание | На рабочем сервере кластера 1С | Учётная запись службы сервера 1С |
Отсюда типичные проблемы серверного запуска:
- 🔹 Пути.
C:\Scripts\run.batищется на диске сервера, а не у пользователя. Скрипт должен лежать на сервере. - 🔹 Сетевые диски. У службы нет подключённых дисков вроде
Z:. Используйте UNC-пути\\fileserver\share\. - 🔹 Права. Служба часто работает под отдельной учётной записью (при установке по умолчанию создаётся
USR1CV8). Ей нужны права на папку скрипта, на сетевые ресурсы и на всё, что делает bat. - 🔹 Окна. Служба не имеет рабочего стола:
pause, вопросыset /pи диалоги повиснут навсегда, а вместе с ними и сеанс 1С, ждущий завершения. - 🔹 Linux. Если сервер 1С работает на Linux, bat не выполнится. Там нужен shell-скрипт, а
cmd.exeв команде заменяется на/bin/shили/bin/bash.
Любая команда, которая ждёт ввода, на сервере подвесит сеанс. Добавляйте ключи без подтверждения (/Y, /Q) и убирайте pause из серверных скриптов.
Долгие скрипты — в фоновое задание
Если bat работает минуты (архивация, выгрузка большой базы), запускайте серверную функцию в фоновом задании через ФоновыеЗадания.Выполнить. Пользователь не ждёт с замороженной формой, а результат попадёт в журнал регистрации. Для запуска по расписанию — регламентное задание с вызовом той же функции.
Другие способы запуска и безопасность
Кроме ЗапуститьПриложение, есть ещё несколько путей. Выбор зависит от того, нужно ли ждать, прятать окно и повышать права.
| Способ | Ждёт и даёт код | Прячет окно | Права админа | Где работает |
|---|---|---|---|---|
ЗапуститьПриложение | Да | Нет | Нет | Клиент, сервер |
НачатьЗапускПриложения, ЗапуститьПриложениеАсинх | Да | Нет | Нет | Клиент, включая веб |
WScript.Shell.Run | Да | Да | Нет | Windows: клиент, сервер |
Shell.Application.ShellExecute с runas | Нет | Нет | Да, через UAC | Клиент Windows |
schtasks /run | Нет | Да | Да, без диалога | Где создана задача |
Функция ЗапуститьПрограмму из БСП
В типовых конфигурациях на Библиотеке стандартных подсистем есть общие модули ФайловаяСистема и ФайловаяСистемаКлиент с процедурой ЗапуститьПрограмму. Она принимает структуру параметров из функции ПараметрыЗапускаПрограммы, умеет ждать завершения и забирать вывод потоков. Перед использованием откройте модуль в Конфигураторе и прочитайте комментарий к функции: набор параметров зависит от версии БСП.
Для доработок типовых баз это предпочтительный путь: код поддерживается разработчиками библиотеки и учитывает разные ОС и типы клиентов.
Безопасность запуска внешних программ
Запуск bat — это выполнение произвольных команд от имени пользователя или службы сервера. Несколько правил, которые защищают базу и сервер:
- 🔒 Не склеивайте команду из пользовательского ввода. Строка из поля формы вроде
x & del /q C:\*превратит выгрузку в удаление. Если параметр всё же нужен, проверяйте его: допустимые символы, существование пути. - 🔒 Храните скрипты в папке, куда пишет только администратор. Иначе любой пользователь подменит bat, и сервер 1С выполнит чужой код с правами своей службы.
- 🔒 Не храните пароли в bat-файлах. Для повышенных прав используйте задание планировщика, для сетевых ресурсов — права учётной записи.
- 🔒 Ограничивайте внешние обработки. Обработки из файлов в типовых конфигурациях выполняются в безопасном режиме, где запуск приложений и создание COM-объектов запрещены. Отключать этот режим ради одного скрипта — плохая идея; лучше встроить код в конфигурацию или расширение.
- 🔒 Профили безопасности. Если для базы в кластере назначен профиль безопасности, запуск внешних приложений и создание COM-объектов должны быть явно разрешены в его свойствах.
Частые вопросы
Можно ли запустить bat-файл из 1С, если он лежит на компьютере пользователя, а код серверный?
&НаКлиенте или положите скрипт на сервер.Как передать в bat значение из 1С, например дату?
%1. Дату предварительно преобразуйте в строку через Формат(Дата, "ДФ=yyyyMMdd"), чтобы не было пробелов и точек.Как запустить bat из 1С и сразу продолжить работу, не дожидаясь его?
ДождатьсяЗавершения = Ложь или не указывайте третий параметр. Код возврата в этом случае получить нельзя, результат придётся проверять по файлу.Почему из регламентного задания bat не видит сетевую папку?
Можно ли вместо bat запустить PowerShell-скрипт тем же способом?
powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\task.ps1", код возврата задаётся в скрипте через exit N.