Всем привет! Часто ли вы как администратор сталкиваетесь с установкой обновлений на операбельные части вашего промышленного программного комплекса? Если да, то эта статья для вас! В ней я представлю свои собственные наработки по автоматизации установки обновлений, которые не требуют «суперпупергипер» крутых знаний данного языка. Поехали!!!
PowerShell — Автоматизация установки обновлений (скрипт)
PowerShell как предмет для изучения
Не буду ходить вокруг да около, скажу лишь то что автоматизация установки обновлений через PowerShell было моей рабочей задачей, но прежде я не работал с этим языком, поэтому мое изучение началось с самого нуля. Тем не менее я достаточно быстро стал вливаться в изучение и мне не было тяжело, к тому же я приобрел неимоверный интерес в рамках этой задачи.
Разбираем скрипт
Итак, давайте начинать, я буду разбивать скрипт на блоки и объяснять, что он из себя представляет, и за что отвечает каждая строка, таким образом вы сможете понять как работает скрипт, а может даже узнаете, что то новое для себя. Внимание! В этой статье будет представлена первая версия скрипта, вторую версию я пока дописываю, но обязательно про нее расскажу позднее. Поехали.
С самого начала у меня есть строка:
1 |
Add-Type -Assembly Microsoft.VisualBasic |
Она означает, что я добавляю тип используемых библиотек Vusial Basic для выполнения скрипта, таким образом я могу использовать функционал Visual Basic-a в моем скрипте.
Далее необходимо с чего-то начать, а начать я решил с того, что буду удалять старые файлы обновления из временной папки и закачивать в нее новые, соответственно мне необходимо указать учетные данные, чтобы авторизоваться на 10-ти серверах, но предварительно мне эти 10 серверов нужно откуда-то получить, а получать я их буду из файла вот этой строкой:
1 |
$c = Get-Content C:\Users\trsadmin\Desktop\Partners\partservers_test.txt |
Далее мне нужно получить учетные данные, но я хотел чтобы они вводились всего один раз и использовались на протяжении всего обновления. К тому же я хочу, чтобы мне выводилась подсказка о том, какую учетную запись мне ввести:
1 |
$d = Get-Credential -Message 'Подключение к серверам партнеров. Требуется единая учетная запись' |
Плюс ко всему для удобства, мне необходимо выводить лог работы, т.к. я хочу видеть, на каком этапе находится мое обновление, для этого я добавил следующую строку:
1 |
Write-Host "Удаление старых файлов обновления в папках c:\update…" -Foreground "Magenta"; |
Сразу после этого я начинаю проводить операцию, о которой только что сообщил:
1 2 |
Invoke-Command -Credential $d -ComputerName $c -ScriptBlock {Remove-Item c:\update\* -Recurse Write-Host "Удаление завершено на $env:computername" -Foreground "Yellow"} -Authentication CredSSP |
Этими строчками скрипт удалил все содержимое папки C:\update и написал на каком сервере он провел данную операцию. Теперь можно переходить к загрузке файлов обновления. Так как разработчики, работающие в нашей компании присылают ссылку на скачивание обновления, я поступил следующим образом:
1 |
$upddistr = [Microsoft.VisualBasic.Interaction]::InputBox("Введите расположение файлов обновления (напр. \\fs22v\Monitors\MailDispatcher\1.0.1.9\*):") |
Соответственно далее хочу видеть лог:
1 2 3 |
Write-Host "Загрузка файлов обновления…" -Foreground "Magenta" Write-Host "Скачиваем дистрибутив из:" $upddistr -Foreground "Magenta" Write-Host "Локальная папка загрузки:" C:\Partners -Foreground "Green" |
Далее, чтобы не возникло конфликта на промежуточном мосте (я так называю сервер, с которого веду установку обновления и куда локально скачиваю файлы обновления) мне так же необходимо сначала удалить содержимое рабочей папки, поэтому далее я написал строку:
1 |
Remove-Item C:\Partners\* -Recurse -Force |
Параметр -force использую для того, чтобы избежать подтверждения обновления и параметр -Recurse для удаления всех дочерних и вложенных элементов. После этого копирую и вывожу на экран полученные файлы, после чего вывожу на экран подтверждение загрузки:
1 2 3 |
Copy-Item $upddistr -Destination C:\Partners -Recurse Get-ChildItem C:\Partners Write-Host "Дистрибутив загружен." -Foreground "Green" |
После этого я подумал, что было бы не плохо заранее загрузить дистрибутив полученной сборки на нужные мне сервера, но мне нужен был выбор, например если обновление специфичное и требует каких-то дополнительных манипуляций, надо ли мне загружать его на все сервера или нет, поэтому я решил вывести форму Yes,No используя Visual Basic:
1 2 3 |
if (([Microsoft.VisualBasic.Interaction]::MsgBox('Загрузить дистрибутив на партнерские сервера?', 'YesNo', 'Обновление')) -eq 'Yes') { Invoke-Command -Credential $d -ComputerName $c -ScriptBlock {Copy-Item \\gsasql29v\Partners\* -Destination c:\update\ -Recurse Write-Host "Загрузили сборку на $env:computername в c:\update\" -Foreground "green";} -Authentication CredSSP;} |
Соответственно, если я выберу «Yes», то выполнятся действия указанные в фигурных {} скобках. Теперь начинается самое интересное…
PowerShell — Выбор обновляемого элемента (switch)
Так как на серверах находится много элементов, которые могут быть обновлены, я сделал выбор обновляемых элементов и реализовал форму выбора через Visual Basic, записывая вводимое администратором значения в переменную, т.к. switch включает определенные функции по совпадениям в переменной:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ex = [Microsoft.VisualBasic.Interaction]::InputBox("Выберите компонент для обновления (только цифру): 1. MonitorService FNS 2. MonitorService FSS 3. MonitorService RPN 4. MonitorService STAT 5. Служба monfns (MonitorFNS v.4.0) 6. Служба AsyncProcessorFSS (MonitorFSS v.4.0) 7. Служба AsyncProcessorStat (MonitorStat v.4.0) 8. Служба FSS Service Handler (Работа с порталом ФСС) 8. Mail Dispatcher FNS 9. Mail Dispatcher FSS 10. Mail Dispatcher STAT") |
Таким образом мы сможем обновлять конкретный элемент в зависимости от присланного обновления. Далее начинаем работать с самим switch-ем:
1 2 3 4 5 6 7 8 9 |
switch ($ex) { #---------------------------------- #Обновление монитора ФНС #под цифрой 1 #---------------------------------- "1" |
Здесь мы определяем, что под цифрой «1» (если именно она указана в переменной) следуют следующие строки:
1 2 3 |
{$c = Get-Content D:\updatepart\partservers_test.txt; Write-Host "Начало обновления монитора ФНС" -Foreground "Magenta"; Write-Host "Шаг 1. Останавливаем процесс MonitorService.exe…" -Foreground "Yellow"; |
Первый шаг простой, остановка службы, но нам нужно определить какой экземпляр останавливать, используем в коде фильтр пути:
1 |
Invoke-Command -Credential $d -ComputerName $c -ScriptBlock {$stpmonfns = get-process MonitorService | ? {$_.Path -eq 'D:\MonitorService\MonitorService.exe'}; stop-process -inputobject $stpmonfns -Force} -Authentication CredSSP; |
Получаем службы с названием MonitorService после чего задаем фильтр пути $_.Path -eq ‘D:\MonitorService\MonitorService.exe’, таким образом остановится процесс, который запущен по этому пути. Далее пишем лог работы и следующий шаг:
1 2 |
Write-Host "Процесс остановлен." -Foreground "Green"; Write-Host "Шаг 2. Создаем бэкап…" -Foreground "Yellow"; |
Бэкап это вообще отдельная и сложная тема, но давайте по порядку.
Получаем дату строкой:
1 |
Invoke-Command -Credential $d -ComputerName $c -ScriptBlock{$dt = (Get-Date).ToString('dd.MM.yyyy'); |
Т.к. на обновляемых серверах старая серверная ОСь необходимо загрузить на нее библиотеки сжатия System.IO.Compression.FileSystem.dll и указать добавление типа:
1 |
Add-Type -Path "C:\Windows\system32\System.IO.Compression.FileSystem.dll"; |
После этого создаем рабочую структуру для создания резервной копии:
1 2 |
$destFolder = 'C:\tmp\services_backup'; $oldArchive = 'C:\Backups\MonitorFNS_*'; |
Далее удаляем предыдущий бэкап для экономии места:
1 |
Remove-Item $oldArchive; |
И пишем об этом лог на каком сервере совершилось действие:
1 |
Write-Host "Удалили старый бэкап на $env:computername…" -Foreground "DarkYellow"; |
Далее тестируем доступность пути из переменной $destFolder и удаляем его содержимое:
1 |
if (Test-Path $destFolder) { Remove-Item $destFolder -Recurse -Force }; |
После этого указываем откуда мы будем получать данные и конечный адрес, куда будет происходить копирование, а так же укажем исключения для файлов, которые на не нужны:
1 2 3 |
$source = 'D:\MonitorService'; $dest = "$destFolder\MonitorFNS"; $exclude = @('*.txt', '*.log', '*.msg', 'log', 'backup*', '*.rar', '*.zip', '*.lic', '*.info', '*.xml'); |
Потом получим все файлы, в том числе и вложенные, которые удовлетворяют нашим условиям, и скопируем их в путь указанный в переменной $dest с названием новой папки из переменной $sourse:
1 |
Get-ChildItem $source -Exclude $exclude | Copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)}; |
Дальше необходимо указать имя файла, но я хотел, чтобы он был с названием обновляемого элемента + сегодняшняя дата и соответственно формат резервной копии .zip. Выглядит это так:
1 |
$archiveName = 'C:\Backups\MonitorFNS_' + [DateTime]::Now.ToString('yyyy_MM_dd') + '.zip'; |
И сжимаем:
1 |
[System.IO.Compression.ZipFile]::CreateFromDirectory($destFolder, $archiveName);} -Authentication CredSSP; |
Проверку создания бэкапа я реализовал в следующей версии скрипта, которую опишу в следующей статье, поэтому здесь после проделанных powershell-ом операций я просто пишу лог:
1 |
Write-Host "Создание бэкапа службы AsyncProcessorFSS завершено" -Foreground "Green" |
После этого я просто копирую файлы с локального сервера на все обновляемые сервера:
1 2 |
Write-Host "Шаг 3. Обновляем файлы…" -Foreground "Yellow" Invoke-Command -Credential $d -ComputerName $c -ScriptBlock {Copy-Item c:\update\* -Destination D:\MonitorService\MonitorService.exe -Recurse} -Authentication CredSSP; |
И последнее что нам осталось это обратно запустить приложение и сделать об этом запись:
1 2 3 4 5 |
Write-Host "Шаг 4. Запускаем MonitorServiceFns.exe…" -Foreground "Yellow"; Invoke-Command -Credential $d -ComputerName $c -ScriptBlock{C:\Distr\RunMonitorServiceFns.bat} -Authentication CredSSP; Write-Host "Monitor service - ГПР запущен" -Foreground "green" Write-Host "Обновление MonitorService FNS завершено, для выхода нажмите Enter" -Foreground "green" } |
На этом все! Самая простая и первая версия автоматизации установки обновлений через PowerShell! Ниже представлено видео с первым боевым тестированием 🙂
Не забывайте про наш канал!