[Из песочницы] Автоматическое обновление и резервное копирование 1С при помощи powershell
Всем доброго дня.
Суть рассматриваемого вопроса изложена в заголовке, повествование разобьем на три части. Отдельно внизу будут приведены тексты скриптов.
1) Предисловие
Вопрос необходимости резервного копирования в автоматическом режиме не подлежит сомнению ни у корифеев, ни у новичков. В статье рассмотрим резервное копирование средствами 1С (что имеет ряд преимуществ перед копированием средствами СУБД). При этом будут применены средства пакетного запуска платформы 1С, powershell и планировщик задач Windows.
Задачи обновления информационных давно автоматизированы, но только для типовых конфигураций, либо тех, что используют библиотеку стандартных подсистем. В моем случае мы работаем со старенькой Альфа-Авто редакции 4, которая распространяется на 12 серверов. Изменения вносятся примерно два раза в неделю, поэтому выгода от автоматизации налицо.
В обоих случаях мы имеем следующие исходные данные:
- Операционная система Windows Server (версии от 2008 до 2012);
- Клиент-серверный вариант платформы 1С 8.3 (с обязательно установленным компонентом COM-соединение).
Разумеется, у нас есть учетные данные ОС и 1С с административными правами.
Для обновления конфигурации так же понадобится ftp-сервер.
Чтобы не раздувать статью, рекомендую прочесть про powershell и про планировщик Windows отдельно.
2) Резервное копирование
После прочтения указанных ссылок мы уже знаем, что надо сделать, чтобы запустить скрипт powershell, поэтому сразу перейду к делу.
Сделать резервную копию информационной базы в пакетном режиме очень просто, надо только «выгнать» всех пользователей. Делать мы это будем, подключившись COM-объектом к базе данных. Это в нашем примере делает функция ExitAll. В тело функции зашито, что она вызывается на том сервере, на котором, собственно, установлен кластер серверов 1С. Вызовите эту функция безо всяких параметров в своем скрипте на сервере — и ВСЕ пользователи из ВСЕХ баз кластера вылетят.
Приношу свои извинения человеку, чьим кодом я воспользовался при написании этой процедуры — авторство восстановить не удалось.
После этого следует вызвать функцию BackUpBase с параметром — имя информационной базы. У меня во всех ИБ есть служебный администратор с одинаковыми учетными данными, поэтому я их просто захардкодил. При необходимости можно их параметризовать, либо обойтись аутентификацией ОС.
Итоговый скрипт сохраняем в файл.
В планировщике задач создаем «Простую задачу», имя, разумеется, на ваше усмотрение.
У меня работает ежедневно, но и тут хозяин — барин. Запускать лучше всего ночью, когда никто не работает, например, в 3:00. Действие для задачи — «Запустить программу». Сама программа у нас «powershell.exe». А вот ее аргументы —
-File "D:\1C_automatization\ExitAllUsersAndBackup.ps1" -ExecutionPolicy RemoteSigned
где ExitAllUsersAndBackup.ps1 — как раз наш сохраненный скрипт.
-ExecutionPolicy RemoteSigned — ключ, который разрешает выполнение пакетных скриптов powershell, если в системе они глобально не разрешены. Работает через раз (возможно, не хватает компетенции чтобы разобраться, но закономерности не нашёл). В случаях, когда не работает с этим ключом, приходится разрешать выполнение скриптов для всего сервера.
Для этого Win+R, powershell.exe,
Set-ExecutionPolicy RemoteSigned
и подтверждаем действие.
Время работы с данными скриптами — более трех месяцев. Перебои были, но связаны с отключением электричества и прочими внешними факторами.
3) Обновление конфигурации
После того, как все пользователи вышли (или выгнаны, как в предыдущем случае), можно обновлять конфигурацию. Наличие регламентных заданий может помешать обновлению, так как с момента отключения всех пользователей и открытия конфигуратора для загрузки конфигурации вполне может начать работу какое-то задание. Поэтому расписание следует обдумать.
Конфигурацию мы храним на ftp-сервере, на который помещаем ее вручную. Файл конфигурации называется GK.cf, в приведенном примере обновляется одна единственная конфигурация. Потенциально можно так же обновлять и несколько различных конфигураций.
На ftp рядом с GK.cf помещаем файл с названием flag.txt. Наличие этого файла сигнализирует о том, что обновляться надо. Можно проверять наличие самого фйла GK.cf, но мы используем флаг так же для других целей.
Скрипт работает следующим образом:
- Удаляет GK.cf и flag.txt, если таковые есть в рабочем каталоге (у пользователя, от имени которого будет запускаться планировщик, должно быть право на запись в этот каталог);
- Предпринимается попытка скачать файл флага;
- Если такой файл скачать получилось — скачиваем .cf;
- Собственно, обновление функцией UpdateCf.
В отличии от предыдущего случая, параметры запуска 1С переданы не массивом, а в привычном по командной строке режиме.
Надежность этого скрипта чуть меньше. Обновление проходит до конца на 100% в тех случаях, когда меняется структура метаданных. В других случаях бывает, как я предупреждал ранее, появление активного пользователя. В результате конфигурация загружена в базу, но конфигурация базы данных не обновлена (снова прошу прощения за подобную кривоватую терминологию перед людьми, не связанными с 1С). В остальном — полет нормальный.
Скрипт резервного копирования
# параметры общие ++
$BAKUPDIR="D:\1C_automatization\BACKUP\"
$CEXE="C:\Program Files (x86)\1cv8\common\1cestart.exe"
# параметры общие --
function ExitAll{
# Сценарий разрывает все сессии пользователей во всех ИБ на выбранном кластере сервера приложений 1С
# Если часть сессий остается активными после этого, то он останавливает все рабочие процессы кластера
# Параметры запуска сценария: адрес сервера, основной порт кластера
#$SrvAddr = "tcp://y001-ap-01:1640"
$SrvAddr = "tcp://127.0.0.1"
########################################
$V83Com = New-Object -COMObject "V83.COMConnector"
# Подключение к агенту сервера
$ServerAgent = $V83Com.ConnectAgent($SrvAddr)
$ClusterFound = $FALSE
#Получим массив кластеров сервера
$Clasters = $ServerAgent.GetClusters()
foreach ($Claster in $Clasters){
# Аутентификация к выбранному кластеру
# если у пользователя, под которым будет выполняться сценарий нет прав на кластер,
# можно прописать ниже имя пользователя и пароль администратора кластера
$ServerAgent.Authenticate($Claster,"","")
#получаем список сессий кластера и прерываем их
$Sessions = $ServerAgent.GetSessions($Claster)
write-host "Разрывается" $Sessions.Count "сессий..."
foreach ($Session in $Sessions){
$ServerAgent.TerminateSession($Claster,$Session)}
if (($Sessions.Count -eq 0)){
continue}
# Если часть сессий осталась активной можно остановить рабочие процессы
# Они перезапустятся автоматически главным менеджером кластера, но без "зависших" сессий
# Получаем список рабочих процессов кластера
$WorkingProcesses = $ServerAgent.GetWorkingProcesses($Claster)
foreach ($WorkingProcess in $WorkingProcesses){
if ($WorkingProcess.Running -eq 1){
write-host "Останавливаем процесс с PID =" $WorkingProcess.PID
#!!!здесь хорошо бы проверить что компьютер с которого запущен сценарий это выбранный в параметрах запуска сервер приложений 1С
Stop-Process $WorkingProcess.PID -Force}}
}
$V83Com = ""
}
function BackUpBase($IbName){
#Сформируем текущие дату и время
$NOWDATETIME = Get-Date -UFormat "%Y_%m_%d_%H-%M"
#Укажем, куда копировать (можно так же параметризовать, чтобы разные базы копировались в разные каталоги)
$TARGETDIR = $BAKUPDIR
#Сформируем имя файла резервной копии
$BAKFN=$TARGETDIR + $IbName + "_" + $NOWDATETIME + ".dt"
#Сформируем массив параметров
$PARAMS = ("DESIGNER","/UseHwLicenses+","/S","127.0.0.1\$IbName","/N","ИМЯАДМИНА1С","/P","ПАРОЛЬАДМИНА1С","/DumpIB",$BAKFN)
#Собственно, поехали
&$CEXE $PARAMS
}
#Выгонем всех
ExitAll
#Вот эти базы будут скопированы
BackUpBase RingAlpha
BackUpBase MazdaAlpha
BackUpBase RingAcc
BackUpBase RingZup
BackUpBase MazdaHRM
BackUpBase MazdaAcc
BackUpBase RingAcc48
BackUpBase RingHRM48
BackUpBase RingAccNorth
BackUpBase RingHRMNorth
Скрипт обновления конфигурации
function Download_File ($si_UserName, $si_Password, $si_Source_Path, $si_Target_Path){
$oi_Credentials = New-Object System.Net.NetworkCredential($si_UserName,$si_Password)
$oi_Web_Client = New-Object System.Net.WebClient
$oi_Web_Client.Credentials = $oi_Credentials
$oi_Web_Client.DownloadFile($si_Source_Path, $si_Target_Path)
while($oi_Web_Client.IsBusy){}
}
Clear-Host;
$curDir = $MyInvocation.MyCommand.Definition | split-path -parent
$curDir = $curDir + "\"
$server = "111.222.33.4" #FTP сайт
$flagfoldername = "/1C/flag.txt" #удаленная папка с флаг-файлом
$flagurl = "ftp://$server$flagfoldername" #url для закачки флага
$cffoldername = "/1C/GK.cf" #удаленная папка с файлом кофигурации
$cfurl = "ftp://$server$cffoldername" #url для закачки файла конфигурации
$login = "MYFTPUSER" #ftp-логин
$password = "MYFTPPWD" #ftp-пароль
$flagfile = $curDir + "flag.txt"
$cffile = $curDir + "GK.cf" #файл с конфигурацией на локальном диске
$SERVERNAME="127.0.0.1"
$CEXE="C:\Program Files (x86)\1cv8\common\1cestart.exe"
$ADMINNAME="1CUSER"
$ADMINPASS="1CPWD"
function UpdateCf($IBNameLocal){
&$CEXE 'DESIGNER' '/S' $SERVERNAME'\'$IBNameLocal '/N' $ADMINNAME '/P' $ADMINPASS '/LoadCfg' $cffile '/UpdateDBCfg' '-Server'
}
function FileExist($fpath){
$isfile = Test-Path $fpath
return ($isfile -eq "True")
}
#собственно, начало выполнения скрипта
if (FileExist $flagfile){
Remove-Item $flagfile
}
if (FileExist $cffile){
Remove-Item $cffile
}
Download_File $login $password $flagurl $flagfile
if (FileExist $flagfile){
Download_File $login $password $cfurl $cffile
if (FileExist $cffile){#стартуем обновление
UpdateCf "MazdaAlpha"
UpdateCf "RingAlpha"
}
}
Благодарю за внимание. Готов к конструктивной критике.