Предисловие
Как-то поставили на проекте задачу по запросу аналитиков обновлять из хранилища три базы КА. Буквально после первого рутинного обновления возникло желание его автоматизировать. Да так, чтобы использовать новый инструмент на любом проекте, не зависеть от сторонних решений и с минимальной подготовкой. Покупать готовую обработку желания не было, а скрипты для этого дела на дистанции показались не слишком практичными. Так родилась данная обработка.
Автоматическое обновление базы из хранилища я разделил на несколько шагов: установка блокировки сеансов, завершение активных сеансов, обновление основной конфигурации из хранилища, обновление расширения из хранилища и снятие блокировки сеансов пользователей.
Каждый шаг реализован по отдельности, а последовательность шагов объединена в "сценарии" для автоматического запуска.
Данная публикация содержит информацию, которой мне не хватало для реализации данной обработки и которая может пригодиться другим разработчикам для написания своего собственного решения, никаких секретов.
Пару слов об обработке
Весь ключевой функционал описан в публикации, обработка лишь обертка для представленных фишек.
Настройки для работы обработки заполняются на отдельной странице

Реализована возможность сохранения и загрузки настроек через файл json, чтобы каждый раз не заполнять их при запуске.
Список информационных баз используется в дальнейшем в реализованных инструментах, например, в настройке сценариев или при просмотре активных пользователей


Параметры сценария при этом заполняются на вкладке с сценариями, но сохраняются вместе со всеми настройками на первой странице. Параметры зависят от того, какие шаги выбраны в сценарии.
Основные функции обработки
1. Управление сеансами пользователей

Чтобы управлять сеансами пользователей, используется общий модуль АдминистрированиеСервера базовой функциональности БСП. Данный модуль содержит программный интерфейс по работе с сеансами и используется в обработках БСП "Активные пользователи" и "Блокировка работы пользователей". Я был приятно удивлен, когда осознал, что он подходит не только для администрирования текущей базы.
Для вывода информации о пользователях необходимо передать параметры администрирования кластера, параметры администрирования информационной базы и фильтр, при необходимости.
Конструкторы структур параметров:
// Параметры подключения к администрируемому кластеру серверов.
//
// Возвращаемое значение:
// Структура:
// * ТипПодключения - Строка - возможные значения:
// "COM" - при подключении к агенту сервера с использованием COM-объекта V8*.ComConnector;
// "RAS" - при подключении к серверу администрирования (ras) с использованием консольного
// клиента сервера администрирования (rac);
// * АдресАгентаСервера - Строка - сетевой адрес агента сервера (только при ТипПодключения = "COM");
// * ПортАгентаСервера - Число - сетевой порт агента сервера (только при ТипПодключения = "COM"),
// типичное значение 1540;
// * АдресСервераАдминистрирования - Строка - сетевой адрес сервера администрирования ras (только.
// При ТипПодключения = "RAS");
// * ПортСервераАдминистрирования - Число - сетевой порт сервера администрирования ras (только при.
// ТипПодключения = "RAS"), типичное значение 1545;
// * ПортКластера - Число - сетевой порт менеджера администрируемого кластера, типичное значение 1541;
// * ИмяАдминистратораКластера - Строка - имя учетной записи администратора кластера (если для кластера
// не задан список администраторов - используется пустая строка);
// * ПарольАдминистратораКластера - Строка - пароль учетной записи администратора кластера (если
// для кластера не задан список администраторов или для учетной записи не установлен пароль -
// используется пустая строка).
//
Функция ПараметрыАдминистрированияКластера() Экспорт
Результат = Новый Структура();
Результат.Вставить("ТипПодключения", "COM"); // "COM" или "RAS"
// Только для "COM"
Результат.Вставить("АдресАгентаСервера", "");
Результат.Вставить("ПортАгентаСервера", 1540);
// Только для "RAS"
Результат.Вставить("АдресСервераАдминистрирования", "");
Результат.Вставить("ПортСервераАдминистрирования", 1545);
Результат.Вставить("ПортКластера", 1541);
Результат.Вставить("ИмяАдминистратораКластера", "");
Результат.Вставить("ПарольАдминистратораКластера", "");
Возврат Результат;
КонецФункции
// Параметры подключения к администрируемой информационной базе кластера.
//
// Возвращаемое значение:
// Структура:
// * ИмяВКластере - Строка - имя администрируемой информационной базы в кластере серверов,
// * ИмяАдминистратораИнформационнойБазы - Строка - имя пользователя информационной базы с правами
// администратора (если для информационной базы не задан список пользователей ИБ - используется
// пустая строка),
// * ПарольАдминистратораИнформационнойБазы - Строка - пароль пользователя информационной базы
// с правами администратора (если для информационной базы не задан список пользователей ИБ или
// для пользователя ИБ не установлен пароль - используется пустая строка).
//
Функция ПараметрыАдминистрированияИнформационнойБазыКластера() Экспорт
Результат = Новый Структура();
Результат.Вставить("ИмяВКластере", "");
Результат.Вставить("ИмяАдминистратораИнформационнойБазы", "");
Результат.Вставить("ПарольАдминистратораИнформационнойБазы", "");
Возврат Результат;
КонецФункции
Обновление списка сеансов, при необходимости можно указать фильтр, в данном случае по типу клиентского приложения:
ОбновитьСписокСеансовНаСервере()
Процедура ОбновитьСписокСеансовНаСервере()
СписокПользователей.Очистить();
ПараметрыАдминистрирования = ПараметрыАдминистрирования(ЭтотОбъект);
ПараметрыАдминистрированияИБ =
ПараметрыАдминистрированияИнформационнойБазыПоИмени(ЭтотОбъект, АктивныеПользователиИмяБазы);
Фильтр = Неопределено;
Если ЗначениеЗаполнено(ОтборИмяПриложения) Тогда
Фильтр = АдминистрированиеКластера.ФильтрСеансов();
Фильтр.Свойство = "ИдентификаторКлиентскогоПриложения";
Фильтр.ВидСравнения = ВидСравнения.Равно;
Фильтр.Значение = ОтборИмяПриложения;
Фильтр = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Фильтр);
КонецЕсли;
СеансыИнформационнойБазы = АдминистрированиеКластера.СеансыИнформационнойБазы(
ПараметрыАдминистрирования, ПараметрыАдминистрированияИБ, Фильтр);
Для Каждого СеансИБ Из СеансыИнформационнойБазы Цикл
СтрокаПользователь = СписокПользователей.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаПользователь, СеансИБ);
СтрокаПользователь.Приложение = ПредставлениеПриложения(СтрокаПользователь.ИдентификаторКлиентскогоПриложения);
Если СеансИБ.РабочийПроцесс = Неопределено Тогда
Элементы.СписокПользователейГруппаПроцесс.Видимость = Ложь;
Иначе
СтрокаПользователь.РабочийПроцессЗанятоПамяти = СеансИБ.РабочийПроцесс.ЗанятоПамяти;
СтрокаПользователь.РабочийПроцессИдентификатор = СеансИБ.РабочийПроцесс.ЗанятоПамяти;
СтрокаПользователь.РабочийПроцессМоментЗапуска = СеансИБ.РабочийПроцесс.МоментЗапуска;
СтрокаПользователь.РабочийПроцессСоединений = СеансИБ.РабочийПроцесс.Соединений;
Элементы.СписокПользователейГруппаПроцесс.Видимость = Истина;
КонецЕсли;
Если СеансИБ.Номер = НомерСеансаИнформационнойБазы И АктивныеПользователиИмяБазы = ИмяТекущейИнформационнойБазы Тогда
СтрокаПользователь.НомерРисункаПользователя = 0;
Иначе
СтрокаПользователь.НомерРисункаПользователя = 1;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Завершение сеансов запускается схожим образом: инициализируются параметры кластера и информационной базы и фильтр для завершения сеансов. Для завершения всех сеансов фильтр не требуется. Для выборочного завершения можно использовать фильтр по номерам сеансов:
&НаКлиенте
Процедура ЗавершитьСеанс(Команда)
КоличествоВыделенныхСтрок = Элементы.СписокПользователей.ВыделенныеСтроки.Количество();
Если КоличествоВыделенныхСтрок = 0 Тогда
ПоказатьПредупреждение(,НСтр("ru = 'Не выбраны пользователи для завершения сеансов.'"));
Возврат;
ИначеЕсли КоличествоВыделенныхСтрок = 1 Тогда
Если Элементы.СписокПользователей.ТекущиеДанные.НомерРисункаПользователя = 0 Тогда // Текущий сеанс
ПоказатьПредупреждение(,НСтр("ru = 'Невозможно завершить текущий сеанс. Для выхода из приложения можно закрыть главное окно приложения.'"));
Возврат;
КонецЕсли;
КонецЕсли;
НомераСеансов = Новый Массив;
Для Каждого ИдентификаторСтроки Из Элементы.СписокПользователей.ВыделенныеСтроки Цикл
СтрокаПользователь = СписокПользователей.НайтиПоИдентификатору(ИдентификаторСтроки);
НомерСеанса = СтрокаПользователь.Номер;
Если СтрокаПользователь.НомерРисункаПользователя = 0 Тогда // Текущий сеанс
Продолжить;
КонецЕсли;
НомераСеансов.Добавить(НомерСеанса);
КонецЦикла;
ПараметрыАдминистрированияИБ = ПараметрыАдминистрированияИнформационнойБазыПоИмени(ЭтотОбъект, АктивныеПользователиИмяБазы);
ДопПараметры = Новый Структура();
ДопПараметры.Вставить("МассивСеансов", НомераСеансов);
ДопПараметры.Вставить("ПараметрыАдминистрированияИБ", ПараметрыАдминистрированияИБ);
Если ЗапрашиватьПараметрыАдминистрированияИБ() Тогда
ОписаниеОповещения = Новый ОписаниеОповещения("ЗавершитьСеансПродолжение", ЭтотОбъект, ДопПараметры);
ПоказатьПараметрыАдминистрирования(ОписаниеОповещения);
Иначе
ЗавершитьСеансПродолжение(ПараметрыАдминистрирования(ЭтотОбъект), ДопПараметры);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ЗавершитьСеансПродолжение(ПараметрыАдминистрирования, ДопПараметры) Экспорт
Если ПараметрыАдминистрирования = Неопределено Тогда
Возврат;
КонецЕсли;
МассивСеансов = ДопПараметры.МассивСеансов;
ПараметрыАдминистрированияИБ = ДопПараметры.ПараметрыАдминистрированияИБ;
СтруктураСеанса = Новый Структура;
СтруктураСеанса.Вставить("Свойство", "Номер");
СтруктураСеанса.Вставить("ВидСравнения", ВидСравнения.ВСписке);
СтруктураСеанса.Вставить("Значение", МассивСеансов);
Фильтр = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СтруктураСеанса);
УдалитьСеансыИнформационнойБазыНаСервере(ПараметрыАдминистрирования, ПараметрыАдминистрированияИБ, Фильтр);
ПослеЗавершенияСеанса(МассивСеансов);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура УдалитьСеансыИнформационнойБазыНаСервере(Знач ПараметрыАдминистрирования, Знач ПараметрыАдминистрированияИБ, Знач Фильтр = Неопределено)
АдминистрированиеКластера.УдалитьСеансыИнформационнойБазы(
ПараметрыАдминистрирования, ПараметрыАдминистрированияИБ, Фильтр);
КонецПроцедуры

Для установки и снятия блокировки сеансов используется единый метод модуля администрирования, также этот метод изменяет состояние блокировки регламентных заданий, поэтому перед установкой/снятием блокировки, необходимо получить текущее состояние блокировки.
Установка/Снятие блокировки
&НаСервере
Процедура УстановитьБлокировкуСеансовНаСервере(
ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, ПараметрыБлокировки, БлокировкаРегламентныхЗаданий)
СвойстваБлокировкиРегЗаданий =
АдминистрированиеКластера.СвойстваБлокировкиСеансовИРегламентныхЗаданий();
ЗаполнитьЗначенияСвойств(СвойстваБлокировкиРегЗаданий, ПараметрыБлокировки);
СвойстваБлокировкиРегЗаданий.БлокировкаСеансов = Истина;
СвойстваБлокировкиРегЗаданий.БлокировкаРегламентныхЗаданий = БлокировкаРегламентныхЗаданий;
АдминистрированиеКластера.УстановитьБлокировкуСеансовИЗаданийИнформационнойБазы(
ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, СвойстваБлокировкиРегЗаданий);
ОбновитьДанныеБлокировкиИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
КонецПроцедуры
&НаСервере
Процедура СнятьБлокировкуСеансовНаСервере(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, БлокировкаРегламентныхЗаданий)
СвойстваБлокировки = АдминистрированиеКластера.СвойстваБлокировкиСеансовИРегламентныхЗаданий();
СвойстваБлокировки.БлокировкаСеансов = Ложь;
СвойстваБлокировки.ДатаС = Неопределено;
СвойстваБлокировки.ДатаПо = Неопределено;
СвойстваБлокировки.Сообщение = "";
СвойстваБлокировки.КодРазрешения = "";
СвойстваБлокировки.БлокировкаРегламентныхЗаданий = БлокировкаРегламентныхЗаданий;
АдминистрированиеКластера.УстановитьБлокировкуСеансовИЗаданийИнформационнойБазы(
ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, СвойстваБлокировки);
ОбновитьДанныеБлокировкиИнформационнойБазы(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
КонецПроцедуры
3. Обновление конфигурации

Обновление конфигурации из хранилища реализовано через системные команды на стороне клиента.
Для того, чтобы красиво вызывать данные команды, используется метод БСП "ФайловаяСистемаКлиент.ЗапуститьПрограмму". Благо примеров использования в библиотеке достаточно.
Для начала реализован единый метод выполнения действия в конфигураторе:
ВыполнитьДействиеВКонфигуратореЧерезКоманднуюСтроку()
&НаКлиенте
Процедура ВыполнитьДействиеВКонфигуратореЧерезКоманднуюСтроку(
ПараметрыАдминистрированияКластера,
ПараметрыАдминистрированияИБ,
КомандаВыполняемоеДействие,
ДанныеБлокировкиБазы = Неопределено,
ОповещениеОЗавершении = Неопределено)
Если КонфигураторОткрыт(ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ) Тогда
ТекстСообщения = НСтр("ru = 'Действие не выполнено, т.к. открыт конфигуратор.'");
ВызватьИсключение ТекстСообщения;
КонецЕсли;
Если ДанныеБлокировкиБазы = Неопределено Тогда
ДанныеБлокировкиБазы = ДанныеБлокировокИнформационнойБазы(
ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ);
КонецЕсли;
РабочийКаталог = КаталогВременныхФайлов();
ИмяФайлаОшибок = РабочийКаталог + "OutUpload.txt";
СтрокаСоединенияИнформационнойБазы = СтрШаблон("Srvr=""%1:%2"";Ref=""%3"";",
ПараметрыАдминистрированияКластера.АдресАгентаСервера,
Формат(ПараметрыАдминистрированияКластера.ПортКластера, "ЧГ=0"),
ПараметрыАдминистрированияИБ.ИмяВКластере);
КомандаЗапуска = Новый Массив;
КомандаЗапуска.Добавить(КаталогПрограммы() + "\1cv8.exe");
КомандаЗапуска.Добавить("DESIGNER");
КомандаЗапуска.Добавить("/IBConnectionString");
КомандаЗапуска.Добавить(СтрокаСоединенияИнформационнойБазы);
Если ДанныеБлокировкиБазы.БлокировкаСеансов Тогда
КомандаЗапуска.Добавить("/UC");
КомандаЗапуска.Добавить(ДанныеБлокировкиБазы.КодРазрешения);
КонецЕсли;
Если Не ПустаяСтрока(ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы) Тогда
КомандаЗапуска.Добавить("/N");
КомандаЗапуска.Добавить(ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы);
КомандаЗапуска.Добавить("/P");
КомандаЗапуска.Добавить(ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы);
КонецЕсли;
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(КомандаЗапуска, КомандаВыполняемоеДействие);
КомандаЗапуска.Добавить("/Out");
КомандаЗапуска.Добавить(ИмяФайлаОшибок);
КомандаЗапуска.Добавить("/DisableStartupMessages");
КомандаЗапуска.Добавить("/DisableStartupDialogs");
АдресФайлаРучнойЗагрузки = РабочийКаталог + "load.cmd";
ЗаписьТекста = Новый ЗаписьТекста(АдресФайлаРучнойЗагрузки, КодировкаТекста.OEM);
ЗаписьТекста.Записать(ОбщегоНазначенияСлужебныйКлиентСервер.БезопаснаяСтрокаКоманды(КомандаЗапуска));
ЗаписьТекста.Закрыть();
Если НЕ ОповещениеОЗавершении = Неопределено Тогда
ОповещениеОЗавершении.ДополнительныеПараметры.Вставить("ИмяФайлаОшибок", ИмяФайлаОшибок);
КонецЕсли;
ПараметрыЗапускаПрограммы = ФайловаяСистемаКлиент.ПараметрыЗапускаПрограммы();
ПараметрыЗапускаПрограммы.ДождатьсяЗавершения = Истина;
ПараметрыЗапускаПрограммы.ПолучитьПотокВывода = Истина;
ПараметрыЗапускаПрограммы.Оповещение = ОповещениеОЗавершении;
ФайловаяСистемаКлиент.ЗапуститьПрограмму(КомандаЗапуска, ПараметрыЗапускаПрограммы);
КонецПроцедуры
Далее остается лишь использовать готовый метод. Возможностей для применений достаточно.
Обновление конфигурации из хранилища
&НаКлиентеНаСервереБезКонтекста
// Параметры подключения к администрируемому кластеру серверов.
//
// Возвращаемое значение:
// Структура:
// * ИмяВКластере - Строка - Имя базы в кластере
// * Расширение - Булево - признак хранилище расширения или основной конфигурации
// * ИмяРасширения - Строка - Имя расширения если это хранилище расширения
// * Путь - Число - Расположение хранилища
// * Пользователь - Строка - Пользователь хранилища
// * Пароль - Строка - Пароль от пользователя хранилища
//
Функция НовыйПараметрыХранилищаИнформационнойБазы()
Результат = Новый Структура();
Результат.Вставить("ИмяБазыВКластере", "");
Результат.Вставить("Расширение", "");
Результат.Вставить("ИмяРасширения", "");
Результат.Вставить("Путь", "");
Результат.Вставить("Пользователь", "");
Результат.Вставить("Пароль", "");
Возврат Результат;
КонецФункции
&НаКлиенте
Процедура ОбновитьКонфигурациюИзХранилища(
ПараметрыАдминистрированияКластера,
ПараметрыАдминистрированияИБ,
ПараметрыХранилищаИнформационнойБазы,
ОповещениеЗавершения = Неопределено,
ОбновлятьБД = Истина)
КомандаОбновления = Новый Массив();
КомандаОбновления.Добавить("/ConfigurationRepositoryF");
КомандаОбновления.Добавить(ПараметрыХранилищаИнформационнойБазы.Путь);
КомандаОбновления.Добавить("/ConfigurationRepositoryN");
КомандаОбновления.Добавить(ПараметрыХранилищаИнформационнойБазы.Пользователь);
КомандаОбновления.Добавить("/ConfigurationRepositoryP");
КомандаОбновления.Добавить(ПараметрыХранилищаИнформационнойБазы.Пароль);
КомандаОбновления.Добавить("/ConfigurationRepositoryUpdateCfg");
Если ПараметрыХранилищаИнформационнойБазы.Расширение Тогда
КомандаОбновления.Добавить("-Extension");
КомандаОбновления.Добавить(ПараметрыХранилищаИнформационнойБазы.ИмяРасширения);
КонецЕсли;
Если ОбновлятьБД Тогда
КомандаОбновления.Добавить("/UpdateDBCfg");
КомандаОбновления.Добавить("-Server");
КонецЕсли;
КомандаОбновления.Добавить("-force");
КомандаОбновления.Добавить("-revised");
ДопПараметры = Новый Структура();
ДопПараметры.Вставить("ПараметрыАдминистрированияКластера", ПараметрыАдминистрированияКластера);
ДопПараметры.Вставить("ПараметрыАдминистрированияИБ", ПараметрыАдминистрированияИБ);
ДопПараметры.Вставить("ОповещениеЗавершения", ОповещениеЗавершения);
Оповещение = Новый ОписаниеОповещения(
"ОбновитьКонфигурациюИзХранилищаПослеЗапускаПрограммы", ЭтотОбъект, ДопПараметры);
УстановитьСостояниеОбновленияИнформационнойБазы(
ПараметрыАдминистрированияИБ, НСтр("ru='Обновление конфигурации из хранилища'"), Истина);
Попытка
ВыполнитьДействиеВКонфигуратореЧерезКоманднуюСтроку(
ПараметрыАдминистрированияКластера, ПараметрыАдминистрированияИБ, КомандаОбновления,, Оповещение);
Исключение
УстановитьСостояниеОбновленияИнформационнойБазы(
ПараметрыАдминистрированияИБ,
НСтр("ru='Ошибка обновления конфигурации из хранилища'"));
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьКонфигурациюИзХранилищаПослеЗапускаПрограммы(Результат, ПараметрыОбработкиРезультата) Экспорт
ПараметрыАдминистрированияИБ = ПараметрыОбработкиРезультата.ПараметрыАдминистрированияИБ;
Попытка
ПрочитатьРезультатВыполненияПрограммы(Результат, ПараметрыОбработкиРезультата);
Исключение
УстановитьСостояниеОбновленияИнформационнойБазы(
ПараметрыАдминистрированияИБ, НСтр("ru='Ошибка обновления конфигурации из хранилища'"));
ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
Если Не ПараметрыОбработкиРезультата.ОповещениеЗавершения = Неопределено Тогда
ПараметрыОбработкиРезультата.ОповещениеЗавершения.ДополнительныеПараметры.Вставить("ТекстОшибки", ТекстОшибки);
ВыполнитьОбработкуОповещения(ПараметрыОбработкиРезультата.ОповещениеЗавершения, Ложь);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
УстановитьСостояниеОбновленияИнформационнойБазы(ПараметрыАдминистрированияИБ, НСтр("ru='Конфигурация обновлена из хранилища'"));
Если Не ПараметрыОбработкиРезультата.ОповещениеЗавершения = Неопределено Тогда
ВыполнитьОбработкуОповещения(ПараметрыОбработкиРезультата.ОповещениеЗавершения, Истина);
КонецЕсли;
КонецПроцедуры
В качестве бонуса реализовал создание резервной копии. Для этого нужно передать следующие параметры запуска:
КомандаОбновления = Новый Массив();
КомандаОбновления.Добавить("/DumpIB");
КомандаОбновления.Добавить(ПутьВыгрузки);
О всех возможностях можно почитать на ИТС.
4. Автоматизация сценариев

Под сценарием подразумевается последовательность шагов. Сценарии описываются в отдельных методах. Список сценариев легко расширять используя ранее реализованные шаги
&НаСервере
Процедура ЗаполнитьСписокСценариев()
СписокВыбора = Элементы.ЗарегистрированныеСценарииСценарий.СписокВыбора;
СписокВыбора.Добавить("Обновление из хранилища", НСтр("ru='Обновление из хранилища (полный цикл)'"));
СписокВыбора.Добавить("Снятие резервной копии", НСтр("ru='Снятие резервной копии (полный цикл)'"));
КонецПроцедуры
&НаКлиентеНаСервереБезКонтекста
Функция ШагиСценария(Сценарий)
Результат = Новый Массив();
Если Сценарий = "Обновление из хранилища" Тогда
Результат.Добавить("УстановкаБлокировкиСеансов");
Результат.Добавить("ЗавершениеСеансовПользователей");
Результат.Добавить("ОбновлениеКонфигурацииИзХранилища");
Результат.Добавить("ОбновлениеРасширенийИзХранилища");
Результат.Добавить("СнятиеБлокировкиСеансов");
ИначеЕсли Сценарий = "Снятие резервной копии" Тогда
Результат.Добавить("УстановкаБлокировкиСеансов");
Результат.Добавить("ЗавершениеСеансовПользователей");
Результат.Добавить("СнятиеРезервнойКопии");
Результат.Добавить("СнятиеБлокировкиСеансов");
КонецЕсли;
Возврат Результат;
КонецФункции
При запуске сценария инициализируются параметры выполнения сценария, список шагов и текущий шаг в списке. После выполнения шага идет переход на выполнение следующего шага. Если шагов больше нет, то сценарий считается выполненным.
Также следует учесть что шаги должны выполнять последовательно, а некоторые шаги выполняются в фоне.
&НаКлиенте
Процедура ВыполнитьСценарий(ПараметрыВыполненияСценария, ДопПарамеры = Неопределено) Экспорт
ПараметрыАдминистрированияКластера = ПараметрыАдминистрирования(ЭтотОбъект);
ПараметрыАдминистрированияИБ =
ПараметрыАдминистрированияИнформационнойБазыПоИмени(ЭтотОбъект, ПараметрыВыполненияСценария.ИмяБазыВКластере);
ПараметрыУстановкиБлокировки = Неопределено;
ШагиСценария = ШагиСценария(ПараметрыВыполненияСценария.Сценарий);
ПараметрыВыполненияСценария.Вставить("ШагиСценария", ШагиСценария);
ПараметрыВыполненияСценария.Вставить("ТекущийШаг", 0);
ПараметрыВыполненияСценария.Вставить("КоличествоШагов", ШагиСценария.Количество());
ПараметрыВыполненияСценария.Вставить("ПараметрыАдминистрированияКластера", ПараметрыАдминистрированияКластера);
ПараметрыВыполненияСценария.Вставить("ПараметрыАдминистрированияИБ", ПараметрыАдминистрированияИБ);
ПараметрыВыполненияСценария.Вставить("ПараметрыУстановкиБлокировки", );
ОбщегоНазначенияКлиент.СообщитьПользователю(НСтр("ru='Запуск сценария: '") + ТекущаяДата());
ВыполнитьШаг(ПараметрыВыполненияСценария);
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьШаг(ПараметрыВыполненияСценария, ДопПараметры = Неопределено) Экспорт
Если ПараметрыВыполненияСценария.ТекущийШаг >= ПараметрыВыполненияСценария.КоличествоШагов Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Сценарий выполнен.'"));
ОбщегоНазначенияКлиент.СообщитьПользователю(НСтр("ru='Окончание сценария: '") + ТекущаяДата());
Возврат;
КонецЕсли;
ПараметрыВыполненияСценария.Вставить("ПараметрыУстановкиБлокировки");
ШагСценария = ПараметрыВыполненияСценария.ШагиСценария[ПараметрыВыполненияСценария.ТекущийШаг];
Попытка
Если ШагСценария = "УстановкаБлокировкиСеансов" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Установка блокировки сеансов.'"));
ШагУстановкаБлокировкиСеансов(ПараметрыВыполненияСценария);
ИначеЕсли ШагСценария = "ЗавершениеСеансовПользователей" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Завершение сеансов.'"));
ШагЗавершениеСеансовПользователей(ПараметрыВыполненияСценария);
ИначеЕсли ШагСценария = "ОбновлениеКонфигурацииИзХранилища" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Обновление конфигурации из хранилища.'"));
ДопПараметры = Новый Структура("ПараметрыВыполненияСценария", ПараметрыВыполненияСценария);
ОповещениеЗавершения = Новый ОписаниеОповещения("ПослеВыполненияШага", ЭтотОбъект, ДопПараметры);
ШагОбновлениеКонфигурацииИзХранилища(ПараметрыВыполненияСценария, ОповещениеЗавершения);
Возврат;
ИначеЕсли ШагСценария = "ОбновлениеРасширенийИзХранилища" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Обновление расширений из хранилища.'"));
ДопПараметры = Новый Структура("ПараметрыВыполненияСценария", ПараметрыВыполненияСценария);
ОповещениеЗавершения = Новый ОписаниеОповещения("ПослеВыполненияШага", ЭтотОбъект, ДопПараметры);
ШагОбновлениеРасширенийИзХранилища(ПараметрыВыполненияСценария, ОповещениеЗавершения);
Возврат;
ИначеЕсли ШагСценария = "ОбновлениеКонфигурацииБазыДанных" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Обновление конфигурации базы данных.'"));
ДопПараметры = Новый Структура("ПараметрыВыполненияСценария", ПараметрыВыполненияСценария);
ОповещениеЗавершения = Новый ОписаниеОповещения("ПослеВыполненияШага", ЭтотОбъект, ДопПараметры);
ШагОбновлениеКонфигурацииБазыДанных(ПараметрыВыполненияСценария, ОповещениеЗавершения);
Возврат;
ИначеЕсли ШагСценария = "СнятиеРезервнойКопии" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Снятие резервной копии.'"));
ДопПараметры = Новый Структура("ПараметрыВыполненияСценария", ПараметрыВыполненияСценария);
ОповещениеЗавершения = Новый ОписаниеОповещения("ПослеВыполненияШага", ЭтотОбъект, ДопПараметры);
ШагСнятиеРезервнойКопии(ПараметрыВыполненияСценария, ОповещениеЗавершения);
Возврат;
ИначеЕсли ШагСценария = "СнятиеБлокировкиСеансов" Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Снятие блокировки сеансов.'"));
ШагСнятиеБлокировкиСеансов(ПараметрыВыполненияСценария);
Иначе
ВызватьИсключение НСтр("ru='Неизвестный шаг сценария'");
КонецЕсли;
Исключение
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Ошибка выполнения сценария.'"));
ВызватьИсключение;
КонецПопытки;
ПараметрыВыполненияСценария.ТекущийШаг = ПараметрыВыполненияСценария.ТекущийШаг + 1;
ВыполнитьШаг(ПараметрыВыполненияСценария);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыполненияШага(Результат, ДопПараметры) Экспорт
ПараметрыВыполненияСценария = ДопПараметры.ПараметрыВыполненияСценария;
Если НЕ Результат Тогда
УстановитьСостояниеВыполненияСценария(
ПараметрыВыполненияСценария.Идентификатор,
НСтр("ru='Ошибка выполнения сценария.'"));
Возврат;
КонецЕсли;
ПараметрыВыполненияСценария.ТекущийШаг = ПараметрыВыполненияСценария.ТекущийШаг + 1;
ВыполнитьШаг(ПараметрыВыполненияСценария);
КонецПроцедуры
Методы с префиксом "Шаг" это методы, которые вызывают ранее реализованный функционал с использованием переданных параметров сценария. Самый сложный пример это обновление расширений из хранилища - шаг один, но несколько фоновых операций.
Для этого в начале шага формируется список расширений к обновлению и данные текущего расширения к обновлению, выполняется обновление расширения, при успешном обновлении список к обновлению уменьшается и выбирается следующее расширение к обновлению, после того как все расширения будут обновлены, требуется вызвать обработку оповещения для продолжения выполнения шагов.
Шаг выполнения обновления расширений из хранилища
&НаКлиенте
Процедура ШагОбновлениеРасширенийИзХранилища(ПараметрыВыполненияСценария, ОповещениеЗавершения)
ПараметрыАдминистрированияКластера = ПараметрыВыполненияСценария.ПараметрыАдминистрированияКластера;
ПараметрыАдминистрированияИБ = ПараметрыВыполненияСценария.ПараметрыАдминистрированияИБ;
Отбор = Новый Структура();
Отбор.Вставить("ИмяБазыВКластере", ПараметрыВыполненияСценария.ИмяБазыВКластере);
Отбор.Вставить("Расширение", Истина);
мДанныеХранилища = ХранилищаИнформационныхБаз.НайтиСтроки(Отбор);
Если мДанныеХранилища.Количество() = 0 Тогда
ВыполнитьОбработкуОповещения(ОповещениеЗавершения, Истина);
Возврат;
КонецЕсли;
// Последовательное обновление расширений
ДанныеХранилища = мДанныеХранилища[0];
ДопПараметры = Новый Структура();
ДопПараметры.Вставить("ПараметрыАдминистрированияКластера", ПараметрыВыполненияСценария.ПараметрыАдминистрированияКластера);
ДопПараметры.Вставить("ПараметрыАдминистрированияИБ", ПараметрыВыполненияСценария.ПараметрыАдминистрированияИБ);
ДопПараметры.Вставить("ОповещениеЗавершения", ОповещениеЗавершения);
ДопПараметры.Вставить("ХранилищаРасширенийКОбновлению", мДанныеХранилища);
ДопПараметры.Вставить("ДанныеХранилища", ДанныеХранилища);
Оповещение = Новый ОписаниеОповещения("ПослеОбновленияРасширенияИзСписка", ЭтотОбъект, ДопПараметры);
ОбновитьКонфигурациюИзХранилища(
ПараметрыАдминистрированияКластера,
ПараметрыАдминистрированияИБ,
ДанныеХранилища,
Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОбновленияРасширенияИзСписка(Результат, ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
ВыполнитьОбработкуОповещения(ДополнительныеПараметры.ОповещениеЗавершения, Ложь);
Возврат;
КонецЕсли;
ДополнительныеПараметры.ХранилищаРасширенийКОбновлению.Удалить(
ДополнительныеПараметры.ХранилищаРасширенийКОбновлению.Найти(ДополнительныеПараметры.ДанныеХранилища));
Если ДополнительныеПараметры.ХранилищаРасширенийКОбновлению.Количество() = 0 Тогда
ВыполнитьОбработкуОповещения(ДополнительныеПараметры.ОповещениеЗавершения, Истина);
Возврат;
КонецЕсли;
Оповещение = Новый ОписаниеОповещения("ПослеОбновленияРасширенияИзСписка", ЭтотОбъект, ДополнительныеПараметры);
ОбновитьКонфигурациюИзХранилища(
ДополнительныеПараметры.ПараметрыАдминистрированияКластера,
ДополнительныеПараметры.ПараметрыАдминистрированияИБ,
ДополнительныеПараметры.ДанныеХранилища,
Оповещение);
КонецПроцедуры
Для каждого шага может потребоваться свой набор параметров, их хранение я решил реализовать в виде структуры в табличной части со сценариями.
Для каждого шага реализована отдельная страница с параметрами шага. При выборе сценария проверяются его шаги и устанавливается видимость для необходимых страниц с параметрами.

Методы работы с параметрами сценариев
&НаКлиенте
Процедура ОткрытьПараметрыСценария(ТекущиеДанные)
// Сброс видимости всех параметров
Элементы.СохранитьПараметрыСценария.Видимость = Ложь;
Элементы.ГруппаСценарииПараметрыБлокировки.Видимость = Ложь;
Элементы.ГруппаСценарииПараметрыСозданияКопии.Видимость = Ложь;
Если ТекущиеДанные = Неопределено ИЛИ ПустаяСтрока(ТекущиеДанные.Сценарий) Тогда
Возврат;
КонецЕсли;
ШагиСценария = ШагиСценария(ТекущиеДанные.Сценарий);
Если ШагиСценария.Найти("УстановкаБлокировкиСеансов") <> Неопределено Тогда
Элементы.ГруппаСценарииПараметрыБлокировки.Видимость = Истина;
КонецЕсли;
Если ШагиСценария.Найти("СнятиеРезервнойКопии") <> Неопределено Тогда
Элементы.ГруппаСценарииПараметрыСозданияКопии.Видимость = Истина;
КонецЕсли;
ЗагрузитьПараметрыСценария(ТекущиеДанные.Сценарий, ТекущиеДанные.ПараметрыСценария);
КонецПроцедуры
&НаКлиенте
Процедура ЗагрузитьПараметрыСценария(Сценарий, ПараметрыСценария)
Если ПараметрыСценария = Неопределено Тогда
// Значения параметров по умолчанию
ПараметрСценарияБлокировкаМинут = 60;
ПараметрСценарияБлокировкаКодРазрешения = "123";
ПриИзмененииПараметровСценария();
Возврат;
КонецЕсли;
ШагиСценария = ШагиСценария(Сценарий);
Если ШагиСценария.Найти("УстановкаБлокировкиСеансов") <> Неопределено Тогда
ПараметрСценарияБлокировкаМинут = ПараметрыСценария.ПараметрыБлокировки.КоличествоМинут;
ПараметрСценарияБлокировкаКодРазрешения = ПараметрыСценария.ПараметрыБлокировки.КодРазрешения;
КонецЕсли;
Если ШагиСценария.Найти("СнятиеРезервнойКопии") <> Неопределено Тогда
ПараметрСценарияПутьВыгрузкиРезервнойКопии = ПараметрыСценария.ПараметрыСозданияРезервнойКопии.Путь;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура СохранитьПараметрыСценария(ТекущиеДанные)
ПараметрыСценария = Новый Структура();
ШагиСценария = ШагиСценария(ТекущиеДанные.Сценарий);
Если ШагиСценария.Найти("УстановкаБлокировкиСеансов") <> Неопределено Тогда
ПараметрыБлокировки = Новый Структура();
ПараметрыБлокировки.Вставить("КоличествоМинут", ПараметрСценарияБлокировкаМинут);
ПараметрыБлокировки.Вставить("КодРазрешения", ПараметрСценарияБлокировкаКодРазрешения);
ПараметрыСценария.Вставить("ПараметрыБлокировки", ПараметрыБлокировки);
КонецЕсли;
Если ШагиСценария.Найти("СнятиеРезервнойКопии") <> Неопределено Тогда
ПараметрыСозданияРезервнойКопии = Новый Структура();
ПараметрыСозданияРезервнойКопии.Вставить("Путь", ПараметрСценарияПутьВыгрузкиРезервнойКопии);
ПараметрыСценария.Вставить("ПараметрыСозданияРезервнойКопии", ПараметрыСозданияРезервнойКопии);
КонецЕсли;
ТекущиеДанные.ПараметрыСценария = ПараметрыСценария;
Элементы.СохранитьПараметрыСценария.Видимость = Ложь;
КонецПроцедуры
&НаКлиенте
Процедура ПриИзмененииПараметровСценария()
Элементы.СохранитьПараметрыСценария.Видимость = Истина;
КонецПроцедуры
Как итог моей работы, обновление базы стало занимать у меня в среднем в три раза меньше времени, а главное, отрабатывает по нажатию одной кнопки.
Технические особенности
Спасибо за внимание, всем добра!