Bat-файл из кода 1С: ожидание, скрытое окно, права и лог

· 10 мин

Содержание

Запустить 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;

КонецФункции

Что здесь сделано:

  1. > файл 2>&1 пишет в один файл и обычный вывод, и сообщения об ошибках.
  2. Попытка ловит сбой самого запуска (например, неверный путь к cmd.exe или запрет запуска приложений).
  3. Вывод вместе с кодом возврата сохраняется в журнал регистрации — его потом видно в Администрирование → Обслуживание → Журнал регистрации по событию «Запуск 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 прочитает неверно, и кириллические пути «сломаются».

Диагностика: выберите симптом

Запуск 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С, например дату?
Параметром командной строки: в bat оно доступно как %1. Дату предварительно преобразуйте в строку через Формат(Дата, "ДФ=yyyyMMdd"), чтобы не было пробелов и точек.
Как запустить bat из 1С и сразу продолжить работу, не дожидаясь его?
Передайте ДождатьсяЗавершения = Ложь или не указывайте третий параметр. Код возврата в этом случае получить нельзя, результат придётся проверять по файлу.
Почему из регламентного задания bat не видит сетевую папку?
Регламентное задание работает под учётной записью службы сервера 1С. Ей нужно дать права на общую папку, а путь указать в UNC-формате.
Можно ли вместо bat запустить PowerShell-скрипт тем же способом?
Да. Команда будет вида powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\task.ps1", код возврата задаётся в скрипте через exit N.