Регламентное задание для обработки 1С нужно, когда обработку надо выполнять автоматически: ночью провести документы, к утру положить отчет в общую папку. Конфигурацию для этого менять не обязательно. Ниже два пути: дополнительная обработка БСП с командой «Вызов серверного метода», расписание которой задают прямо в карточке, и прием из нашей практики — запуск внешней обработки с ключом /Execute из Планировщика заданий Windows или задания SQL Server Agent.
Имена БСП сверены с УТ 11.4 (БСП 3.1.5) и КА 2.5 (БСП 3.1.10). Если конфигурацию дорабатывать можно, удобнее свое регламентное задание.
| Дополнительная обработка БСП | Запуск с ключом /Execute | |
|---|---|---|
| Конфигурация | На БСП: УТ 11, КА 2, БП 3.0 и другие | Любая |
| Где выполняется | Фоновое задание на сервере 1С | Сеанс клиента, открытый по расписанию |
| Лицензия | По практике фоновый сеанс клиентскую лицензию не занимает | Занимает, пока сеанс открыт |
| Пользователь | Не задан: пользователь по умолчанию с административными правами | Тот, под кем выполнен вход |
| Файлы, интернет, COM | По умолчанию безопасный режим; файлы и COM — через разрешения или БезопасныйРежим = Ложь в сведениях | Без ограничений у администратора |
| Файловая база | Задания идут, только пока открыт сеанс | Сеанс запускается сам |
| Где итог | Журнал регистрации, список заданий | Файл итога, журнал, история задания |
Расписание дополнительной обработке задают без конфигуратора. На каждую команду с расписанием БСП создает экземпляр регламентного задания «Запуск дополнительных обработок» с параметрами «ссылка на обработку, идентификатор команды». Задание вызывает ДополнительныеОтчетыИОбработки.ВыполнитьОбработкуПоРегламентномуЗаданию, а она — ВыполнитьКоманду модуля объекта. Условия: вид «Дополнительная обработка», команда «Вызов серверного метода», публикация не «Отключена». Подключение и права разобраны в статье о дополнительных обработках.
Пример проводит документы прошлого дня, сохраненные без проведения; ошибки с причинами — в журнал регистрации.
// Модуль объекта внешней обработки «Проведение отложенных документов».
// Дополнительная обработка БСП: серверная команда, которую ставят на расписание.
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ПрограммныйИнтерфейс
Функция СведенияОВнешнейОбработке() Экспорт
// Версия БСП не ниже 1.2.1.4, иначе ВыполнитьКоманду вызовут без ПараметрыВыполнения.
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Версия = "1.0";
ПараметрыРегистрации.Информация = НСтр("ru = 'Проводит документы прошлого дня, сохраненные без проведения'");
Команда = ПараметрыРегистрации.Команды.Добавить();
Команда.Представление = НСтр("ru = 'Провести отложенные документы'");
Команда.Идентификатор = "ПровестиОтложенные";
// Расписание БСП дает только командам «Вызов серверного метода» и «Сценарий в безопасном режиме».
Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
Команда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
// По расписанию в ПараметрыВыполнения только ДополнительнаяОбработкаСсылка,
// ИдентификаторКоманды и РезультатВыполнения: ни формы, ни выбранных объектов.
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды <> "ПровестиОтложенные" Тогда
ВызватьИсключение СтрШаблон(НСтр("ru = 'Неизвестная команда: %1'"), ИдентификаторКоманды);
КонецЕсли;
Итог = ПровестиОтложенныеДокументы();
Комментарий = СтрШаблон(НСтр("ru = 'Запуск %1. Проведено: %2, с ошибками: %3'"),
?(ЭтоЗапускПоРасписанию(), НСтр("ru = 'по расписанию'"), НСтр("ru = 'вручную'")),
Итог.Проведено, Итог.Ошибки);
ЗаписьЖурналаРегистрации(ИмяСобытия(), УровеньЖурналаРегистрации.Информация, ,
ПараметрыВыполнения.ДополнительнаяОбработкаСсылка, Комментарий);
ПараметрыВыполнения.РезультатВыполнения.Вставить("Проведено", Итог.Проведено);
// Исключение делает запуск аварийным: это видно в списке заданий,
// а с БСП 3.1.10 платформа еще и повторит задание.
Если Итог.Ошибки > 0 Тогда
ВызватьИсключение Комментарий;
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ПровестиОтложенныеДокументы()
Итог = Новый Структура("Проведено, Ошибки", 0, 0);
КонецПериода = НачалоДня(ТекущаяДатаСеанса()) - 1; // вчера, 23:59:59
НачалоПериода = НачалоДня(КонецПериода);
Для Каждого ИмяДокумента Из ВидыДокументов() Цикл
// Документа может не быть в конфигурации, непроводимые тоже пропускаем.
МетаДокумент = Метаданные.Документы.Найти(ИмяДокумента);
Если МетаДокумент = Неопределено
Или МетаДокумент.Проведение <> Метаданные.СвойстваОбъектов.Проведение.Разрешить Тогда
Продолжить;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = СтрШаблон(
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.%1 КАК Док
|ГДЕ
| Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И НЕ Док.Проведен
| И НЕ Док.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Док.Дата", МетаДокумент.Имя);
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ПровестиДокумент(Выборка.Ссылка, Итог);
КонецЦикла;
КонецЦикла;
Возврат Итог;
КонецФункции
Процедура ПровестиДокумент(Ссылка, Итог)
ПолучитьСообщенияПользователю(Истина); // убрать чужие сообщения
Попытка
ДокументОбъект = Ссылка.ПолучитьОбъект();
Если ДокументОбъект = Неопределено Тогда
Возврат; // документ уже удалили
КонецЕсли;
// Документ правят в форме - блокировка не пройдет, возьмем его повторным запуском в тот же день.
ДокументОбъект.Заблокировать();
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
Итог.Проведено = Итог.Проведено + 1;
Исключение
Причины = Новый Массив;
Причины.Добавить(КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
// Тексты проверки заполнения приходят сообщениями, а не в исключении.
Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Истина) Цикл
Причины.Добавить(Сообщение.Текст);
КонецЦикла;
ЗаписьЖурналаРегистрации(ИмяСобытия(), УровеньЖурналаРегистрации.Ошибка,
Ссылка.Метаданные(), Ссылка, СтрСоединить(Причины, Символы.ПС));
Итог.Ошибки = Итог.Ошибки + 1;
КонецПопытки;
КонецПроцедуры
// Фоновое задание, запущенное регламентным, ссылается на него;
// у ручного запуска из раздела такой ссылки нет.
Функция ЭтоЗапускПоРасписанию()
Попытка
ФоновоеЗадание = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание();
Возврат ФоновоеЗадание <> Неопределено И ФоновоеЗадание.РегламентноеЗадание <> Неопределено;
Исключение
Возврат Ложь; // сведения о сеансе недоступны - считаем запуск ручным
КонецПопытки;
КонецФункции
// Какие документы проводить. Имена из УТ 11.4, отсутствующие в базе будут пропущены.
Функция ВидыДокументов()
Возврат СтрРазделить("ЗаказКлиента,РеализацияТоваровУслуг,ПеремещениеТоваров", ",");
КонецФункции
Функция ИмяСобытия()
Возврат НСтр("ru = 'Проведение отложенных документов'");
КонецФункции
#КонецОбласти
#КонецЕсли
СведенияОВнешнейОбработке("2.2.2.1") — с версией БСП ниже 1.2.1.4 ВыполнитьКоманду вызовут с одним параметром.ПараметрыВыполнения по расписанию — только ссылка на обработку, идентификатор команды и пустая РезультатВыполнения. Ни формы, ни выделенных документов, ни параметров от формы: значения по умолчанию задайте в коде.ПолучитьСообщенияПользователю(Истина). Причины из проверки заполнения приходят сообщениями, в фоне их никто не видит — код пишет их в журнал.Заблокировать(). Документ, который сейчас правят в форме, заблокировать не выйдет. Запрос берет непроведенные документы только за вчера, так что такой документ подхватит повторный запуск в тот же день: задайте в расписании повтор, например раз в час ночью.ЭтоЗапускПоРасписанию(). У фонового задания, запущенного регламентным, заполнено свойство РегламентноеЗадание.ВызватьИсключение в конце. В КА 2.5 (БСП 3.1.10) задание завершится аварийно с текстом «Команда ПровестиОтложенные не выполнена по причине: …», и платформа его повторит: в метаданных задания три повтора с интервалом 10 секунд. В УТ 11.4 (БСП 3.1.5) библиотека перехватит исключение и запишет в журнал «Команда ПровестиОтложенные: Ошибка выполнения: …», а задание будет выглядеть успешным. Повторы не нужны — уберите исключение.Запрос из примера можно проверить в консоли запросов, подставив имя документа вместо %1.
В журнал регистрации БСП пишет событие «Дополнительные отчеты и обработки»: «Команда ПровестиОтложенные: Запуск.» и «…: Завершение.».
От чьего имени. БСП создает задание без пользователя. По справке платформы его выполняет пользователь по умолчанию с административными правами, а БСП считает текущим служебного «<Не указан>». Права не ограничены, лишнего обработка делать не должна.
Связь карточки и задания — реквизит РегламентноеЗаданиеGUID табличной части «Команды». Функция собирает сводку по всем обработкам с расписанием. Выполняйте ее на сервере под администратором.
// Сводка по расписаниям дополнительных обработок БСП: включено ли задание,
// расписание и последний запуск. Локальная база (не модель сервиса), сервер, права администратора.
Функция СводкаРасписанийДополнительныхОбработок() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Команды.Ссылка КАК Обработка,
| Команды.Представление КАК Команда,
| Команды.РегламентноеЗаданиеGUID КАК ИдентификаторЗадания
|ИЗ
| Справочник.ДополнительныеОтчетыИОбработки.Команды КАК Команды
|ГДЕ
| Команды.РегламентноеЗаданиеGUID <> &ПустойИдентификатор
| И НЕ Команды.Ссылка.ПометкаУдаления";
Запрос.УстановитьПараметр("ПустойИдентификатор",
Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000"));
Строки = Новый Массив;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Заголовок = СтрШаблон("%1 / %2", Выборка.Обработка, Выборка.Команда);
Задание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(Выборка.ИдентификаторЗадания);
Если Задание = Неопределено Тогда
Строки.Добавить(Заголовок + ": задание не найдено, проверьте расписание в карточке");
Продолжить;
КонецЕсли;
Последнее = Задание.ПоследнееЗадание;
Если Последнее = Неопределено Тогда
ПоследнийЗапуск = "еще не запускалось";
Иначе
ПоследнийЗапуск = СтрШаблон("%1, %2", Последнее.Начало, Последнее.Состояние);
Если Последнее.ИнформацияОбОшибке <> Неопределено Тогда
ПоследнийЗапуск = ПоследнийЗапуск + ": " + КраткоеПредставлениеОшибки(Последнее.ИнформацияОбОшибке);
КонецЕсли;
КонецЕсли;
Строки.Добавить(СтрШаблон("%1: %2; расписание: %3; последний запуск: %4", Заголовок,
?(Задание.Использование, "включено", "выключено"), Задание.Расписание, ПоследнийЗапуск));
КонецЦикла;
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
Прием выручает в трех случаях: база не на БСП; обработке нужны файлы или COM без безопасного режима; база файловая, и ночью в ней никого нет. Ключ /Execute открывает внешнюю обработку сразу после старта 1С:Предприятия, обработка делает работу и закрывает сеанс. Из практики: мы запускали ее заданием SQL Server через xp_cmdshell.
-- Из практики: обработка 1С из задания SQL Server через xp_cmdshell.
-- Рабочий вариант, но сегодня лучше иначе (разбор ниже).
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
EXEC xp_cmdshell 'cmd.exe /c "C:\Program Files (x86)\1cv8\8.3.18.1208\bin\1cv8.exe" enterprise /S srv01/trade /N Администратор /P <пароль> /EXECUTE C:\Scripts\ОтправкаОтчетов.epf';
Схема рабочая, но:
xp_cmdshell включается на весь сервер. Microsoft держит его выключенным по умолчанию: через него повышают привилегии.msdb.dbo.sysjobsteps.srv01\trade.Нужна внешняя обработка с основной формой и макетом «СхемаОтчета» — схемой компоновки со своим запросом и параметрами НачалоПериода, КонецПериода. Форма читает /C, вызывает сервер и закрывает 1С, работа и итог — в модуле объекта. Как создать файл и макет, рассказано в статье о внешней обработке.
// Модуль основной формы внешней обработки night-task.epf.
// Запуск: 1cv8.exe ENTERPRISE ... /Execute night-task.epf /C "Task=SalesReport;Days=1".
// В свойствах формы назначьте обработчик события ПриОткрытии.
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Без /C обработка ничего не делает: файл можно открыть и посмотреть.
Если РазобратьПараметрЗапуска(ПараметрЗапуска).Получить("Task") = Неопределено Тогда
Возврат;
КонецЕсли;
// Даем приложению закончить запуск, работа - в обработчике ожидания.
ПодключитьОбработчикОжидания("ВыполнитьИЗавершить", 1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьИЗавершить()
НастройкиЗапуска = РазобратьПараметрЗапуска(ПараметрЗапуска);
Попытка
ВыполнитьНаСервере(НастройкиЗапуска);
Исключение
// Сюда попадают сбои вне задачи, например обрыв связи с сервером.
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
Попытка
ЗаписатьСбойНаСервере(НастройкиЗапуска.Получить("Task"), ТекстОшибки);
Исключение
// Итога не будет: обертка увидит это по отсутствию файла.
КонецПопытки;
КонецПопытки;
// Ложь - выйти без вопросов и без обработчиков закрытия.
ЗавершитьРаботуСистемы(Ложь);
КонецПроцедуры
&НаСервере
Процедура ВыполнитьНаСервере(НастройкиЗапуска)
РеквизитФормыВЗначение("Объект").ВыполнитьЗадачу(НастройкиЗапуска);
КонецПроцедуры
&НаСервере
Процедура ЗаписатьСбойНаСервере(Задача, ТекстОшибки)
РеквизитФормыВЗначение("Объект").ЗаписатьИтог(Задача, Ложь, ТекстОшибки);
КонецПроцедуры
// "Task=SalesReport;Days=1" -> соответствие "Task" -> "SalesReport", "Days" -> "1".
&НаКлиентеНаСервереБезКонтекста
Функция РазобратьПараметрЗапуска(Знач СтрокаПараметров)
Результат = Новый Соответствие;
Для Каждого Часть Из СтрРазделить(СтрокаПараметров, ";", Ложь) Цикл
Позиция = СтрНайти(Часть, "=");
Если Позиция > 0 Тогда
Результат.Вставить(СокрЛП(Лев(Часть, Позиция - 1)), СокрЛП(Сред(Часть, Позиция + 1)));
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Модуль объекта внешней обработки night-task.epf.
// Задача SalesReport: отчет по схеме компоновки из макета «СхемаОтчета» сохраняется в XLSX.
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
// Выполняет задачу из /C. Исключение не выбрасывает: пишет итог и возвращает Ложь.
Функция ВыполнитьЗадачу(НастройкиЗапуска) Экспорт
Задача = Строка(НастройкиЗапуска.Получить("Task"));
Попытка
Если Задача = "SalesReport" Тогда
Дней = НастройкиЗапуска.Получить("Days");
ИмяФайла = СохранитьОтчет(?(Дней = Неопределено, 1, Число(Дней)));
ЗаписатьИтог(Задача, Истина, "Сохранен файл " + ИмяФайла);
Иначе
ВызватьИсключение СтрШаблон("Неизвестная задача в параметре /C: %1", Задача);
КонецЕсли;
Исключение
ЗаписатьИтог(Задача, Ложь, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат Ложь;
КонецПопытки;
Возврат Истина;
КонецФункции
// Итог - в журнал регистрации и в файл для скрипта-обертки: первая строка OK или ERROR.
Процедура ЗаписатьИтог(Задача, Успех, Текст) Экспорт
ЗаписьЖурналаРегистрации("ЗапускПоРасписанию." + Задача,
?(Успех, УровеньЖурналаРегистрации.Информация, УровеньЖурналаРегистрации.Ошибка), , , Текст);
Файл = Новый ЗаписьТекста(КаталогВыгрузки() + "result-" + Задача + ".txt", КодировкаТекста.UTF8);
Файл.ЗаписатьСтроку(?(Успех, "OK", "ERROR"));
Файл.ЗаписатьСтроку(Формат(ТекущаяДатаСеанса(), "ДФ='yyyy-MM-dd HH:mm:ss'"));
Файл.ЗаписатьСтроку(Текст);
Файл.Закрыть();
КонецПроцедуры
// Отчет за Дней дней по вчерашний день включительно.
// В схеме из макета нужны параметры НачалоПериода и КонецПериода.
Функция СохранитьОтчет(Знач Дней)
Дней = Макс(Дней, 1);
КонецПериода = НачалоДня(ТекущаяДатаСеанса()) - 1;
НачалоПериода = НачалоДня(КонецПериода) - (Дней - 1) * 86400;
Схема = ПолучитьМакет("СхемаОтчета");
Настройки = Схема.НастройкиПоУмолчанию;
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", НачалоПериода);
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода", КонецПериода);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки);
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКомпоновки);
Документ = Новый ТабличныйДокумент;
Вывод = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
Вывод.УстановитьДокумент(Документ);
Вывод.Вывести(Процессор);
ИмяФайла = КаталогВыгрузки() + "sales-" + Формат(КонецПериода, "ДФ=yyyyMMdd") + ".xlsx";
Документ.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
Возврат ИмяФайла;
КонецФункции
// Общий каталог: пишет служба сервера 1С, читает учетная запись задания.
Функция КаталогВыгрузки()
Возврат "\\srv01\1c-tasks\out\";
КонецФункции
#КонецЕсли
/C форма ничего не делает, так что открыть файл для проверки безопасно.ЗавершитьРаботуСистемы(Ложь) закрывает 1С без обработчиков закрытия и вопросов.ПараметрЗапуска есть только на клиенте, а ЗаписьЖурналаРегистрации в тонком клиенте нет: отсюда разделение на форму и модуль объекта./C берите свои: БСП ищет в параметре запуска подстроки «ЗавершитьРаботуПользователей», «ВыполнитьОбновлениеИЗавершитьРаботу», «ОтключитьЛогикуНачалаРаботыСистемы».OK или ERROR, по ней скрипт вернет код планировщику."C:\Program Files (x86)\1cv8\8.3.18.1208\bin\1cv8.exe" ENTERPRISE /S "srv01\trade" /DisableStartupDialogs /DisableStartupMessages /Execute "C:\1c-tasks\night-task.epf" /C "Task=SalesReport;Days=1" /Out "C:\1c-tasks\logs\startup.log"
/DisableStartupDialogs убирает окна выбора базы и входа. До конца ПередНачаломРаботыСистемы клиент в пакетном режиме: окна не открываются, ошибка запуска завершает 1С с кодом 1 и пишется в файл /Out./DisableStartupMessages гасит вопрос «Конфигурация базы данных не соответствует сохраненной конфигурации. Продолжить?»./N и /P действует аутентификация ОС (/WA+ по умолчанию): привяжите пользователя 1С к учетной записи Windows задания, и пароля в задании не будет.1С не вернет планировщику код ошибки обработки, поэтому нужен скрипт: запустить клиент, дождаться с таймаутом, снять зависший процесс и превратить файл итога в код возврата.
# run-1c.ps1 - запуск обработки 1С с ключом /Execute и проверка итога.
# Код возврата: 0 - OK, 1 - обработка сообщила об ошибке, 2 - 1С зависла, 3 - итога нет.
# Сохраните файл в UTF-8 с BOM, иначе Windows PowerShell 5.1 исказит русский текст.
param(
[string]$Task = 'SalesReport',
[int]$Days = 1,
[int]$TimeoutMinutes = 60
)
$Ver = '8.3.18.1208' # версия клиента = версия сервера 1С
$Exe = "C:\Program Files (x86)\1cv8\$Ver\bin\1cv8.exe"
$Epf = 'C:\1c-tasks\night-task.epf'
$OutDir = '\\srv01\1c-tasks\out' # сюда пишет итог серверная часть обработки
$LogDir = 'C:\1c-tasks\logs'
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null # каталог для /Out должен существовать
$OutLog = Join-Path $LogDir ("startup-$Task-" + (Get-Date -Format 'yyyyMMdd-HHmmss') + '.log')
$Result = Join-Path $OutDir "result-$Task.txt"
Remove-Item -Path $Result -ErrorAction SilentlyContinue
# Пароля нет: вход по аутентификации ОС от учетной записи задания.
$ArgList = @(
'ENTERPRISE',
'/S "srv01\trade"',
'/DisableStartupDialogs',
'/DisableStartupMessages',
"/Execute `"$Epf`"",
"/C `"Task=$Task;Days=$Days`"",
"/Out `"$OutLog`""
)
$Proc = Start-Process -FilePath $Exe -ArgumentList $ArgList -PassThru
if (-not $Proc.WaitForExit($TimeoutMinutes * 60 * 1000)) {
$Proc.Kill()
Write-Output "1С не завершилась за $TimeoutMinutes мин., процесс снят"
exit 2
}
if (-not (Test-Path -Path $Result)) {
Write-Output "Нет файла итога $Result. Журнал запуска:"
if (Test-Path -Path $OutLog) { Get-Content -Path $OutLog -Encoding UTF8 }
exit 3
}
$Lines = @(Get-Content -Path $Result -Encoding UTF8) # @() - даже если строка одна
$Lines | Write-Output
if ($Lines[0] -ne 'OK') { exit 1 }
exit 0
Итог пишет рабочий процесс сервера 1С. Если планировщик работает на другом компьютере, нужен общий каталог: сервер 1С в него пишет, учетная запись задания читает.
Шаг «Операционная система (CmdExec)» делает то же без xp_cmdshell: работает от прокси с отдельной учетной записью Windows, ненулевой код возврата помечает шаг ошибкой, вывод пишется в файл, оператору Агент напишет через Database Mail. А шаги идут по порядку: сначала резервная копия, потом 1С.
-- Задание SQL Server Agent: шаг CmdExec от прокси-учетной записи вместо xp_cmdshell.
USE msdb;
GO
-- Учетная запись Windows для шага. Ее же привяжите к пользователю 1С (аутентификация ОС).
CREATE CREDENTIAL [cred_1c_tasks] WITH IDENTITY = N'DOMAIN\svc-1c-tasks', SECRET = N'<пароль>';
GO
EXEC dbo.sp_add_proxy @proxy_name = N'proxy_1c_tasks', @credential_name = N'cred_1c_tasks', @enabled = 1;
EXEC dbo.sp_grant_proxy_to_subsystem @proxy_name = N'proxy_1c_tasks', @subsystem_name = N'CmdExec';
GO
EXEC dbo.sp_add_job @job_name = N'1C SalesReport', @description = N'Отчет 1С по расписанию через /Execute';
EXEC dbo.sp_add_jobstep
@job_name = N'1C SalesReport',
@step_name = N'run-1c.ps1',
@subsystem = N'CmdExec',
@command = N'powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\1c-tasks\run-1c.ps1" -Task SalesReport -Days 1',
@cmdexec_success_code = 0, -- любой другой код возврата = ошибка шага
@proxy_name = N'proxy_1c_tasks',
@output_file_name = N'C:\1c-tasks\logs\agent-SalesReport.log',
@flags = 2; -- дописывать в файл вывода
EXEC dbo.sp_add_schedule
@schedule_name = N'Daily 03:00',
@freq_type = 4, -- ежедневно
@freq_interval = 1,
@freq_subday_type = 1, -- один раз в указанное время
@active_start_time = 30000; -- 03:00:00, формат HHMMSS
EXEC dbo.sp_attach_schedule @job_name = N'1C SalesReport', @schedule_name = N'Daily 03:00';
EXEC dbo.sp_add_jobserver @job_name = N'1C SalesReport', @server_name = N'(local)';
GO
Учетной записи прокси по документации Microsoft нужно право «Доступ к компьютеру из сети» на сервере SQL, а также доступ к скрипту и каталогам; по практике ей дают и «Вход в качестве пакетного задания». Когда новое задание отработало, выключите xp_cmdshell, но сначала проверьте, кто еще им пользуется: такие задания и процедуры начнут падать.
-- 1. Кто еще вызывает xp_cmdshell: шаги заданий Агента.
SELECT j.name AS job_name, s.step_id, s.step_name
FROM msdb.dbo.sysjobs AS j
JOIN msdb.dbo.sysjobsteps AS s ON s.job_id = j.job_id
WHERE s.command LIKE N'%xp_cmdshell%';
-- 2. То же в процедурах и функциях: выполнить в каждой своей базе.
SELECT OBJECT_SCHEMA_NAME(object_id) AS schema_name, OBJECT_NAME(object_id) AS object_name
FROM sys.sql_modules
WHERE definition LIKE N'%xp_cmdshell%';
-- 3. Если пусто - выключить. Параметр меняется только при show advanced options = 1.
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 0;
RECONFIGURE;
EXEC sp_configure 'show advanced options', 0; -- если раньше было 0
RECONFIGURE;
SELECT name, value_in_use FROM sys.configurations
WHERE name IN (N'xp_cmdshell', N'show advanced options');
Без SQL Server тот же скрипт ставят в Планировщик, из PowerShell от имени администратора:
# Задача Планировщика: каждый день в 03:00, не дольше двух часов, без параллельных запусков.
$Action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\1c-tasks\run-1c.ps1" -Task SalesReport -Days 1'
$Trigger = New-ScheduledTaskTrigger -Daily -At '03:00'
$Settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) -MultipleInstances IgnoreNew -StartWhenAvailable
# С паролем задача работает и без входа пользователя в систему.
Register-ScheduledTask -TaskName '1C SalesReport' -Action $Action -Trigger $Trigger -Settings $Settings -User 'DOMAIN\svc-1c-tasks' -Password '<пароль>'
Право «Вход в качестве пакетного задания» Планировщик выдает учетной записи сам, если его не задает доменная политика. -ExecutionTimeLimit — вторая страховка от зависания, IgnoreNew не запустит второй экземпляр.
СообщитьПользователю в регламентном задании никто не увидит, пишите итог в журнал — см. запись в журнал регистрации.Напрямую никак: приходят только ссылка на обработку и идентификатор команды. Храните настройки в карточке (реквизит ХранилищеНастроек) или заведите несколько команд, у каждой свое расписание.
Для отчетов из базы сначала посмотрите подсистему БСП «Рассылки отчетов» (справочник есть в УТ 11 и КА 2): расписание и получатели без кода. Свой отчет обработка сохранит в файл, а как отправить его письмом, рассказано в статье об отправке почты из 1С.
Запустите команду вручную из раздела: код тот же. Отладчик к регламентному заданию подключают по статье об отладке на сервере. Строку с /Execute сначала проверьте в обычном сеансе Windows.
Если разбираться с БСП, правами и учетными записями некогда, отдайте задачу программисту: он соберет обработку, поставит расписание и проверит на копии базы. Подробнее — на странице отчеты и обработки 1С. Задачу можно разместить бесплатно: оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.