Массовая установка (обновление) агента Zabbix

Появилась необходимость автоматизировать установку агента Zabbix на сервера. Написал небольшой скрипт (не без помощи ИИ конечно же), который делает это. Кроме скрипта необходима небольшая обвязка вокруг него: утилита PsExec (та что от Sysinternal), а также ещё несколько файлов. Вот вся структура каталога, которая должна быть с содержимым файлов:

Файл zabbix_agent2.conf в который прописана вся необходимая информация для подключения к серверу администрирования и его работы, кроме имени клиента, которое будет автоматически подставляться в процессе работы скрипта (берите его от своих администраторов мониторинга)

Файл PsExec.exe

Файл computers.csv в котором будут прописаны в столбец только FQDN-серверов, на которые требуется установка (название столбца указывать не надо)

Файл скрипта set_zabbix_mass.bat. Вот его содержимое:
@echo off
chcp 65001
cd %~dp0
for /f "usebackq tokens=1 delims=;" %%a in ("computers.csv") do (
xcopy zabbix_agent2.conf .\install /I /Y /Q
set Hostname=%%a
set Hostname >> ".\install\zabbix_agent2.conf"
xcopy .\install \%%a\C$\Zabbix /I /S /Y /Q
PsExec.exe \%%a "C:\Zabbix\install_agent_silent.bat" -accepteula
if %errorlevel%==0 (
echo Success on %%a>> install-agent.log
) else (
echo Error on %%a>> install-agent.log
)
rmdir /S /Q \%%a\C$\Zabbix
set Hostname=
)
pause

Каталог install в котором содержится 2 файла:

Файл zabbix_agent2-7.4.11-windows-amd64-openssl.msi — то что требуется поставить на сервера. В вашем случае может быть другая версия. Тогда надо поправить название файла в скрипте install_agent_silent.bat

Файл скрипта install_agent_silent.bat со следующим содержимым:
msiexec /l*v C:\install-zabbix.log /i C:\Zabbix\zabbix_agent2-7.4.11-windows-amd64-openssl.msi /qn^
SERVER=192.168.77.85,192.168.77.86,192.168.77.63,192.168.77.77
setlocal enabledelayedexpansion
set "SERVICE=Zabbix Agent 2"
set "MAX_TRIES=3"
set "TRY=0"
:check
set /a TRY+=1
echo Attempt !TRY! of %MAX_TRIES%...
sc query "%SERVICE%" | find "RUNNING" >nul
if %errorlevel%==0 (
xcopy C:\Zabbix\zabbix_agent2.conf "C:\Program Files\Zabbix Agent 2\zabbix_agent2.conf" /I /Y
net stop "Zabbix Agent 2" && net start "Zabbix Agent 2"
goto :success
)
if !TRY! lss %MAX_TRIES% (
rem Wait 5 sec...
ping -n 6 127.0.0.1 >nul
goto :check
)
rem === Check status service failed ===
echo [%date% %time%] Service "%SERVICE%" not started after %MAX_TRIES% checks
goto :eof
:success
echo Installation completed successfully.
goto :eof

Создайте всю необходимую структуру, как я описал, и после можно запускать скрипт set_zabbix_mass.bat, просто кликнув на него 2 раза мышкой. Учетка, под которой вы это делаете, должна иметь права администратора на удаленных серверах. Естественно нужны все сетевые доступы для такого вида установки, а также уверенность, что установку не остановит политики безопасности.

Создание новой роли в Veeam Backup для проверки резервных копий

Veeam backup roles
При необходимости частого восстановления и проверки бекапов серверов в СРК Veeam Backup and Replication, наверняка у вас появятся необходимость создания новой роли, с помощью которой можно проверить развернутую виртуальную машину. В моем случае например мне понадобилось, чтобы на почту приходило сообщение о имени виртуальной машины и ее IP-адресе, по которому можно «достучаться» для её проверки.
Что для этого надо сделать?

  • заходим на сервер Veeam Backup and Replication в папку C:\Program Files\Veeam\Backup and Replication\Backup\SbRoles и копируем и вставляем сюда же один из файлов, тем самым сделав дубль одной из ролей, например у меня так создался файл SendEmailAfterRestore.xml
  • заходим в файл SendEmailAfterRestore.xml и в строке между <SbRole><Id></Id>  меняем идентификатор на какой-либо другой, главное чтобы он не пересекался с уже имеющимся, у меня это 4CDC7CC4-A906-4de2-979B-E5F74C44841F
  • в строке между <SbRole><Name></Name> пишем любое новое имя для роли, у меня это «Send email after restore server»
  • в строке между <TestScript><Name></Name> пишем название производимого действия, например у меня это «Send Email»
  • в строке <TestScriptFilePath> пишем путь до скрипта, через который будет отправляться письмо, у меня это путь C:\Scripts\SendEmail.ps1. Ниже я напишу что в скрипте мы пишем
  • в строке <Arguments> пишем аргументы, которые нам нужны для скрипта, в моем случае это %vm_fqdn% %vm_ip% backup-admins@mail.ru

После этого сохраняем получившийся файл SendEmailAfterRestore.xml
Создаем новый файл C:\Scripts\SendEmail.ps1 и в него вставьте следующие строки:

$arg1 = $args[0]
$arg2 = $args[1]
$recipient = $args[2]
$smtpServer = «relay.mail.ru»
$smtpPort = 25
$smtpUsername = ‘mail\VeeamUser’
$smtpPassword = ‘xxxxxxx’
$sender = ‘Veeam@mail.ru’
$Subject = «Восстановлен из бекапа сервер $arg1»
$messageBody = «Имя сервера: $arg1`nДоступен по IP-адресу: $arg2»
Send-MailMessage -To $recipient -From $sender -SmtpServer $smtpServer -Subject $Subject -Body $messageBody -Encoding UTF8
exit 0
У выделенных «жирным» элементов укажите свои значения и после этого можно перезапускать консоль Veeam, в которой можно будет увидеть новую роль, как на скриншоте в начале статьи.

Замена STS сертификата на vCenter

Менял я недавно vCenter сертификат с названием «STS Signing Certificate». Делал этот через веб-интерфейс клиента .
После нажатия на «Actions» — «Refresh with vCenter certificate» сертификат в интерфейсе успешно обновился, но появилось уведомление о необходимости всех систем. Я на всякий случай перезагрузил весь vCenter.  Сертификат как видно на скриншоте выдался на 8 лет до 2033 года. После этого я зашел по ssh на vCenter и запустил скрипт vCert.sh , с помощью которого проверил статус сертификатов.  В отчете  работы скрипта показывалось несколько ошибок. Путем некоторых манипуляций я перевыпустил еще раз «STS Signing Certificate». При такой манипуляции скрипт выпустил сертификат уже только на 2 года, при этом некоторые ошибки все еще висели:
«Checking VMDir certificate» и «Check STS VECS store configuration»

Для решения проблемы с «Checking VMDir certificate» я для начала выгрузил  отчет, который может сгенерировать скрипт vCert. В нем нашел такой сертификат:
Service Principal (Solution User) Certificates
Service Principal: WebClient_2014.05.19_021659
Issuer: O=VMware, Inc., OU=LogBrowser_2014.05.19_021659, CN=VMWARE/emailAddress=support@vmware.com
Subject: O=VMware, Inc., OU=LogBrowser_2014.05.19_021659, CN=VMware default certificate/emailAddress=support@vmware.com
Not Before: May 18 09:18:50 2014 GMT
Not After : May 16 09:18:57 2024 GMT
SHA1 Fingerprint : C6:7A:73:97:5C:CB:42:AC:48:55:72:0B:5E:8D:C7:5E:7B:0B:D9:FD
Signature Algorithm: sha256WithRSAEncryption
Subject Key Identifier:
Key Usage:
|_Digital Signature
|_Key Encipherment
|_Data Encipherment
Extended Key Usage:
|_TLS Web Server Authentication
Subject Alternative Name entries:
|_DNS:VMWARE
Other Information:
|_Is a Certificate Authority: No
|_Issuing CA in VMware Directory/VECS: No

Из-за него и возникала эта ошибка. Для его удаления я зашел в пункты меню 3 и затем 10, где скрипт vCert ругался на неиспользуемый сертификат (смотри скриншот ниже).  Я его удалил и после этого ошибка «Checking VMDir certificate» пропала

С ошибкой «Check STS VECS store configuration LEGACY» побороться оказалось также просто,  необходимо выполнить  команды
sed -i 's/STS_INTERNAL_SSL_CERT/MACHINE_SSL_CERT/' /usr/lib/vmware-sso/vmware-sts/conf/server.xml
/usr/lib/vmware-vmafd/bin/vecs-cli store delete --name STS_INTERNAL_SSL_CERT

и затем рестартовать одну из служб

service-control --restart vmware-stsd

Долгий запрос сертификата APNs (Apple MDM) в Workspace One

Обнаружил недавно проблему при запросе сертификата APNs в продукте Workspace ONE (бывший Airwatch) — он выполняется слишком долго (самый первый шаг).
Начал смотреть Procmon куда лезет в файловой системе этот продукт при запросе сертификата и выяснил, что он долго обрабатывает каталог C:\Windows\ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SystemCertificates\Request\Certificates. Зашел в него и оказалось что там около 500 тыс. файлов. Через поиск в интернете быстро находится статья о проблеме со старыми версиями Airwatch https://kb.omnissa.com/s/article/82553 В результате, с помощью скрипта https://github.com/sntcz/Clear-MachineKeys  перенес файлы в другой каталог и проблема медленного запроса сертификата больше не проявлялась.

Скрипт на powershell обновления прошивок iLO

Import-Csv "C:\Users\username\Desktop\servers.csv" -Delimiter ';' -Encoding UTF8 | ForEach-Object {
$con = Connect-HPEiLO -Address $_.'Интерфейс управления' -Username 'username' -Password 'password' -DisableCertificateAuthentication
IF (($con.TargetInfo.iLOGeneration -eq 'iLO4') -and ($con.TargetInfo.iLOFirmwareVersion -ne '2,82')) {
Update-HPEiLOFirmware -Connection $con -Location "C:\Users\username\Desktop\ilo4_282.bin" -UploadTimeout 700 -Confirm:$false -Force
}
IF (($con.TargetInfo.iLOGeneration -eq 'iLO5') -and ($con.TargetInfo.iLOFirmwareVersion -ne '2,99')) {
Update-HPEiLOFirmware -Connection $con -Location "C:\Users\username\Desktop\ilo5_299.bin" -UploadTimeout 700 -Confirm:$false -Force
}
}

Обратите внимание на выделенные строки, там нужно вписать правильные значения. После обновления версию прошивки можно проверить командой:
Get-HPEiLOFirmwareVersion -Connection $con | select IP, FirmwareVersion

Скрипт вывода информации о занятом и выделенном дисковом пространстве в кластере vSphere

Get-Module -ListAvailable VMware* | Import-Module
$vcservers = "адрес сервера vSphere"
$username = "имя пользователя"
$report = @()
$Used = 0
$Unused = 0
$AllUsed = 0
$AllAllocated = 0
Connect-VIServer $vcservers -User $username -Password 'пароль пользователя'

$allvms = Get-Cluster -name ‘имя кластера‘ | Get-VM
foreach ($VMName in $allvms){
$Server = Get-VM $VMName | Get-View
foreach ($size_com in $($Server.Storage.PerDatastoreUsage).Committed) {
$Used += $size_com
}
foreach ($size_uncom in $($Server.Storage.PerDatastoreUsage).Uncommitted) {
$Unused += $size_uncom
}
$Used = [math]::Round((($Used)/1024/1024/1024),2)
$Unused = [math]::Round((($Unused)/1024/1024/1024),2)
$Allocated = $Used + $Unused
$row = «» | select ‘Имя сервера’, ‘Занято(ГБ)’, ‘Выделено(ГБ)’
$row.’Имя сервера’ = $VMName
$row.’Занято(ГБ)’ = $Used
$row.’Выделено(ГБ)’ = $Allocated
$report += $row
$AllUsed += $Used
$AllAllocated += $Allocated
}
$report | ft
Write-Host «Всего занято дискового пространства (ГБ): $AllUsed»
Write-Host «Всего выделено дискового пространства (ГБ): $AllAllocated»
Disconnect-VIServer $vcservers -Confirm:$False

Скрипт вывода в CSV занятого пространства на каждом датасторе для всех включенных виртуальных машин в кластере VMware

$VCServer = 'fqdn vcenter сервера'
$VC = Connect-VIServer $VCServer -User 'учетная запись vCenter' -Password 'пароль для учетной записи'
$report = @()
$allvms = Get-Cluster VM-Cluster05 | Get-VM | where {$_.PowerState -eq "PoweredOn"}
foreach ($vm in $allvms) {
$vmview = $vm | Get-View
foreach($disk in $vmview.Storage.PerDatastoreUsage){
$dsview = (Get-View $disk.Datastore)
$dsview.RefreshDatastoreStorageInfo()
$row = "" | select VMNAME, DATASTORE, VMUSED_GB
$row.VMNAME = $vmview.Config.Name
$row.DATASTORE = $dsview.Name
$row.VMUSED_GB = [math]::round((($disk.Committed)/1024/1024/1024),0)
$report += $row
}
}
$report | Export-Csv "C:\Temp\vm_ds.csv" -NoTypeInformation
Disconnect-VIServer $VC -Confirm:$False

Контролируем доступ по RDP с помощью Telegram и Powershell

Решил я тут на днях  немного упростить жизнь и заодно вспомнить что такое написание скриптов. Не буду хвалиться,  скажу сразу, что за образец взял готовую статью с habr.com. Мне понадобилось с помощью телеграмм и его бота управлять правилом встроенного в windows server брандмауэра. На нём настроено ограничение на вход по RDP с конкретных подсетей (сами знаете что будет, если RDP сервис выставить в интернет без какой-либо защиты). Вот готовый скрипт, осталось только в нем вставить идентификатор бота, аккаунта с которого можно будет отправлять ему сообщения и возможно поменять название правил файервола (у меня они со стандартными именами в русской локализации). После этого добавляйте его в планировщик задач.
Читать далее «Контролируем доступ по RDP с помощью Telegram и Powershell»

Скрипт переноса общей папки на сервере с Windows

Понадобилось тут написать небольшой скрипт, после того как массово пришлось переносить папки на файловом сервере на другой диск. Выкладываю его сюда, вдруг кому-нибудь пригодится. Поменяйте только значение переменных на свои.

# Cоздание копии папки $NameFolder находящейся в $FolderPath1 в директорию $FolderPath2 и копирование ее содержимого со всеми атрибутами.
# Проверка есть ли подключения к общей папке. Если нет, то производится остановка расшаривания и докопирование содержимого. Исходная папка рекурсивно удаляется
# Логи сохраняются в папку $LogsFolderPath

$NameFolder = ‘Общая папка отдела’ #название исходной папки
$FolderSource= ‘F:\Общие папки\’ #путь к исходной папке (обязателен обратный слэш в конце пути)
$FolderDest = ‘D:\Общие папки\’ #путь к папке назначения (обязателен обратный слэш в конце пути)
$LogFolder = ‘C:\MoveFolderLogs\’ #путь к папке с логами (должна быть создана вручную)

$notshare = $false #определяем, что по-умолчанию исходная папка расшарена
$LogFile = $LogFolder + «sync-$NameFolder.log»
$FolderPath1 = $FolderSource+$NameFolder
$FolderPath2 = $FolderDest+$NameFolder

if (!(Test-Path -Path $LogFolder)){
Write-Host «Не создана папка для логов!» -ForegroundColor Yellow }

$SmbShare = Get-SmbShare | where {$_.Path -eq «$FolderPath1» }
if (!(Test-Path -Path $FolderPath2)){
$ACL = Get-Acl $FolderPath1 -Audit
Write-Host «Создание папки назначения» -ForegroundColor Green
New-Item -name $NameFolder -Path $FolderDest -ItemType Directory 1>$null
Set-Acl -AclObject $ACL -Path $FolderPath2
} else
{ Write-Host «Папка назначения уже создана» -ForegroundColor Green }
if (!($SmbShare)){
Write-Host «Исходная папка не расшарена» -ForegroundColor Yellow
$notshare = $true;
$NewSmbShareName = $NameFolder
}
if ((($SmbShare).CurrentUsers -eq «0») -or ($notshare -eq $true)){
if ($notshare -eq $false){
Write-Host «Зашаривание общей папки» -ForegroundColor Green
Remove-SmbShare -Name ($SmbShare).Name -Force
Write-Host «Начинаем копировать файлы общей папки…» -ForegroundColor Yellow -NoNewline
robocopy.exe $FolderPath1 $FolderPath2 /COPYALL /E /DCOPY:DAT /R:3 /W:5 /V /NP /NS /LOG+:$LogFile 1>$null
Write-Host «Завершено» -ForegroundColor Green
Write-Host «Расшаривание общей папки по новому расположению» -ForegroundColor Green
New-SmbShare -Name ($SmbShare).Name -Path $FolderPath2 -CachingMode None -ChangeAccess «Everyone» 1>$null
Write-Host «Удаление исходной папки» -ForegroundColor Green
Remove-Item -Path $FolderPath1 -Force -Recurse
}
else {
Write-Host «Начинаем копировать файлы общей папки…» -ForegroundColor Yellow -NoNewline
robocopy.exe $FolderPath1 $FolderPath2 /COPYALL /E /DCOPY:DAT /R:3 /W:5 /V /NP /NS /LOG+:$LogFile 1>$null
Write-Host «Завершено» -ForegroundColor Green
Write-Host «Расшаривание общей папки по новому расположению» -ForegroundColor Green
New-SmbShare -Name $NewSmbShareName -Path $FolderPath2 -CachingMode None -ChangeAccess «Everyone» 1>$null
Write-Host «Удаление исходной папки» -ForegroundColor Green
Remove-Item -Path $FolderPath1 -Force -Recurse
}
}
else {
Write-Host «Подключений к общей папке»($SmbShare).Name»:»($SmbShare).CurrentUsers -ForegroundColor Yellow
Write-Host «Начинаем копировать файлы общей папки…» -ForegroundColor Yellow -NoNewline
robocopy.exe $FolderPath1 $FolderPath2 /COPYALL /E /DCOPY:DAT /R:3 /W:5 /V /NP /NS /LOG+:$LogFile 1>$null
Write-Host «Завершено» -ForegroundColor Green
Write-Host «Запустите этот скрипт повторно после завершения активных SMB-подключений» -ForegroundColor Red
}

Powershell cкрипт для массового отображения/изменения ACL на файловом сервере

Привет! Понадобилось мне недавно провести вручную операцию по удалению из ACL лишней записи. Проблема была в том, что таких папок было около 50 штук. Спасало только то, что это нужно было сделать в папке с одним и тем же именем в разных директориях с одним общим корнем. Я это сделал вручную, так как задачу надо было выполнить быстро, но решил для себя написать скрипт, чтобы можно было быстро править ACL-листы папок в Windows. Необходимо только, чтобы на сервере был Powershell и немного его знания, так как скрипт практически не оттестирован и не проверен в реальной работе на большом количестве данных.
Вот он сам, по комментариям внутри него думаю будет понятно, что надо делать.

function Print_Dir($list_catalogs)
    {
         $Table = New-Object system.Data.DataTable “$Table_Security”  <#Создание таблицы для отображения ACL#>
         $column1 = New-Object system.Data.DataColumn Директория,([string])
         $column2 = New-Object system.Data.DataColumn ACL,([string])
         $column3 = New-Object system.Data.DataColumn Владелец,([string])
         $table.columns.add($column1)
         $table.columns.add($column2)
         $table.columns.add($column3)
         foreach ($Foundfolder in $list_catalogs) 
            {
                $Access = (Get-Acl $Foundfolder.FullName).AccessToString  
                $row = $table.NewRow()
                $row.Директория = $Foundfolder.FullName
                $row.ACL = “$Access”
                $row.Владелец = $AccessACL.Owner
                $table.Rows.Add($row)
            } 
         $table | format-table -Wrap
        
    }

function Found_Folder()
    {
                $Root_Path = Read-Host 'Введите корневую директорию'   <#Директория в которой производится поиск по-умолчанию#>
                $Target_Folder = Read-Host 'Введите название папки'    <#папка для поиска по-умолчанию #>
                $FFolder = Get-ChildItem $Root_Path -Recurse -Directory -Force -ErrorAction SilentlyContinue -Filter "$Target_Folder" <#Найденные папки#>
                return $FFolder
    }

While ($KEY='1')
{
$ACL_Key = Read-Host 'Что необходимо сделать? (1 - Вывести текущие значения ACL; 2 - Добавление; 3 - Удаление; 4 - Выход из программы)'
switch ($ACL_Key)
{
    1 
        {
                $Found_Folder = Found_Folder
                Print_Dir($Found_Folder)
        }
    2
        {
                $Found_Folder = Found_Folder
                $AccessRuleAdd = New-Object System.Security.AccessControl.FileSystemAccessRule "ONIX\TestAV", "Modify","ContainerInherit,ObjectInherit", "None","Allow" <#ACL, которую требуется добавить в папки#>
                foreach ($Foundfolder in $Found_Folder)
                    {
                        $ACL = $Foundfolder.GetAccessControl("Access")  
                        $ACL.AddAccessRule($AccessRuleAdd)
                        $Foundfolder.SetAccessControl($ACL)
                    } 
                Print_Dir($Found_Folder)
        }
    3
        {
                $Found_Folder = Found_Folder
                $AccessRuleDel = New-Object System.Security.AccessControl.FileSystemAccessRule "ONIX\TestAV", "Modify","ContainerInherit,ObjectInherit", "None","Allow" <#ACL, которую требуется добавить в папки#>
                foreach ($Foundfolder in $Found_Folder)
                    {
                        $ACL = $Foundfolder.GetAccessControl("Access")  
                        $ACL.RemoveAccessRule($AccessRuleDel)
                        $Foundfolder.SetAccessControl($ACL)
                    } 
                Print_Dir($Found_Folder)
        }
    4   
        {
            exit
        }
} 
}