Как отследить переезд файловых ролей на другой хост кластера
Добрый день! Уважаемые читатели и гости IT блога Pyatilistnik.org. В минувший раз мы с вами рассмотрели причины и методы устранения черного экрана Windows. Сегодня я хочу с вами поделится полезным PowerShell скриптом, который позволит вам отслеживать переезд файловых ролей на файловом отказоустойчивом кластере Microsoft Windows. Данная задача нужна для того, чтобы средство резервного копирования Veeam Backup могло корректно сделать резервную копию данных, так как если роль переезжает, то могут быть проблемы.
⚒Описание задачи
Как я и указал выше есть файловый кластер построенный на технологиях Windows, по нодам кластера распределены файловые роли. Для того чтобы их бэкапить используется Veeam Backup & Replication 11. Есть небольшая проблема в его связке с резервным копированием файловых ролей. Если файловая роль переезжает на другую ноду, например при обслуживании сервера (Установка обновлений), то Veeam Backup & Replication вместо дифференциального резервного копирования начинает делать новый полный бэкап, а если у вас диски файловой роли могут весить по 50 ТБ и более, то данный процесс очень сильно замедлит резервное копирование, которое должно стартовать по расписанию. Чтобы этого не допускать, был написан небольшой скрипт PowerShell, который это мониторит и оповещает администратора, что произошло данное событие и желательно вернуть файловую роль на ее законное место.
На выходе я хочу получить вот такое оповещение.
✅И второй канал посвященный чисто PowerShell, я назвал его PowerShell азбука - https://t.me/azbuka_powershell
Вот и сам текст PowerShell скрипта по проверке переезда роли на DFS кластере.
#requires -module ActiveDirectory
#requires -module FailoverClusters
#requires -RunAsAdministrator
#💻Создаем папку для логов если ее нет и будим туда записывать все происходящее
function Date {Get-Date -Format "yyyy.MM.dd HH:mm:ss"}
$log_dir = "$PSScriptRoot\Logs\" + $($MyInvocation.MyCommand.Name -replace (".ps1", ""))
if (! (Test-Path $log_dir -PathType Container -ErrorAction SilentlyContinue))
{
New-Item $log_dir -ItemType D -Force | Out-Null
}
$ClusterGroups_dir = "$log_dir\ClusterGroups"
if (! (Test-Path $ClusterGroups_dir -PathType Container -ErrorAction SilentlyContinue))
{
New-Item $ClusterGroups_dir -ItemType D -Force | Out-Null
}
$log = "$log_dir\" + (Get-Date -Format "yyyy_MM_dd_HH_mm_ss") + ".log"
$ClusterGroups_out = "$ClusterGroups_dir\" + (Get-Date -Format "yyyy_MM_dd_HH_mm_ss") + ".csv"
### 👨💻Тело скрипта проверяющего, что роль перемещена
"$(Date) Start Processing" | Tee-Object $log -Append
$cluster = "DFSCLUSTER.pyatilistnik.org"
$ClusterGroups = $null
"$(Date) Fetching Cluster Information" | Tee-Object $log -Append
try {
$ClusterGroups = Get-Cluster $cluster -ErrorAction Stop | Get-ClusterGroup -ErrorAction Stop | ? {$_.GroupType -eq "FileServer"}
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
# Break
}
"$(Date) Exporting data to `"$ClusterGroups_out`" file" | Tee-Object $log -Append
$ClusterGroups | select Name, OwnerNode | Export-Csv $ClusterGroups_out -NoTypeInformation -Encoding Unicode
"$(Date) Trying to compater 2 last results" | Tee-Object $log -Append
$ClusterGroups_out_last2 = $null
$ClusterGroups_out_last2 = (Get-ChildItem $ClusterGroups_dir -File | sort LastWriteTime -Descending | select -First 2 | select -Last 1).FullName
if (! $ClusterGroups_out_last2)
{
"$(Date) Unable to get 2nd file for comparison" | Tee-Object $log -Append
Break
}
"$(Date) Going to compare files: `"$ClusterGroups_out`" and `"$ClusterGroups_out_last2`"" | Tee-Object $log -Append
$ClusterGroups_out_content = $ClusterGroups_out_last2_content = $null
$ClusterGroups_out_content = Import-Csv $ClusterGroups_out
$ClusterGroups_out_last2_content = Import-Csv $ClusterGroups_out_last2
$ClusterGroup_diffs = @()
foreach ($ClusterGroup in $ClusterGroups_out_content)
{
$current_owner = $last_owner = $null
$current_owner = $ClusterGroup.OwnerNode
$last_owner = ($ClusterGroups_out_last2_content | ? {$_.Name -eq $ClusterGroup.Name}).OwnerNode
"$(Date) Current owner - `"$current_owner`", last owner - `"$last_owner`"" | Tee-Object $log -Append
if ($current_owner -ne $last_owner)
{
$ClusterGroup_diff = New-Object PSObject
$ClusterGroup_diff | Add-Member -MemberType NoteProperty -Name "ClusterGroup Name" -Value $ClusterGroup.Name
$ClusterGroup_diff | Add-Member -MemberType NoteProperty -Name "Last Owner Node" -Value $last_owner
$ClusterGroup_diff | Add-Member -MemberType NoteProperty -Name "Current Owner Node" -Value $current_owner
$ClusterGroup_diffs += $ClusterGroup_diff
}
}
### 👩💻Формируем отчет в виде таблицы и отправляем его по почте gmail.com
if ($ClusterGroup_diffs)
{
"$(Date) Trying to send notification" | Tee-Object $log -Append
$Header = @"
<style>
TABLE {border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
TH {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
</style>
"@
$body = $ClusterGroup_diffs | select "ClusterGroup Name", "Last Owner Node", "Current Owner Node" | ConvertTo-Html -Head $Header
$body += "<p>Generated on $($env:COMPUTERNAME + "." + $((Get-WmiObject Win32_ComputerSystem).Domain))"
$from = "support@pyatilistnik.org"
$Subject = "Check File Server Roles Owner in $cluster Cluster"
$smtpserver = "pyatilistnik.org"
$secure = $false
$port = 25 # TLS, for SSL use 465
# $username = "support_user"
# $password = "P@ssw0rd"
$message = New-Object System.Net.Mail.MailMessage
$message.From = $from
$message.To.Add("Адресат-1")
$message.BCC.Add("Адресат-2")
$message.BCC.Add("Адресат-3")
# $message.BCC.Add()
$message.Subject = $Subject
$message.Body = $body
$message.IsBodyHtml = $true
$smtp = New-Object Net.Mail.SmtpClient($smtpserver)
try {
$smtp.Send($message)
}
catch {
"$(Date) $($_.exception.message)" | Tee-Object $log -Append
# Break
}
}
else
{
"$(Date) There are no differences" | Tee-Object $log -Append
}
###
"$(Date) End Processing" | Tee-Object $log -Append
На этом у меня все. Надеюсь, что вам будет полезен данный код. С вами бы Иван Сёмин, автор и создатель IT портала Pyatilistnik.org.
А зачем мониторить, когда в джобе вима есть pre script.
Не проще так?
Это больше для уведомления команды не связанной с СРК