Если в Вашей инфраструктуре настроена репликация виртуальных машин, то Вы наверняка не раз сталкивались с тем, что репликация останавливалась по разным причинам. Чтобы вовремя отреагировать на ошибки репликации был написан данный скрипт.
Зачем мониторить репликацию?
Остановившаяся репликация может привезти к очень опасной ситуации для всех реплицируемых виртуальных машин, в тот момент, когда закончится место у стораджа на котором хранятся виртуалки. Так же существует всем известный закон подлости — когда репликация остановилась, через некоторое время (например сутки) что-то произошло с основным сервером и тогда Вы теряете не реплицированные данные.
Скрипт реагирует на регистрацию ошибок в журнале событий ОС, а так же с периодичностью 15 минут проверяет состояние репликации.
В случае ошибок репликации какой либо из VM, скрипт отправляет письмо с отчетом о состоянии репликации, три последние ошибки по каждой VM из системного журнала. Письмо отправляется с периодичностью в 1 час.
Если репликация восстановилась самостоятельно отправляется письмо:
Настройка скрипта:
Создать каталог в котором будет работать скрипт, например:
C:Scripts
В эту папку копируем файлы:
- OnReplCheck.xml
- OnReplFailed.xml
- VM-Repl-MSG.ps1
Необходимо заполнить секцию конфигурации скрипта своими данными:
##### Configuration Section Starts ##### $SMTPServer = "mail.Corp.com.ua" $EMailMSGTo = "Me <Me@MyDomain.com.ua>" # Send Mail using Gmail account #$UseGmail = $false # Set gmail Email address if $UseGmail = $true $EMailMSGFrom = "Virtual HV-Repl <administrator@Corp.com.ua>" $EMailMSGUseSSL = $false $ScriptPath = Split-Path $MyInvocation.MyCommand.Path $Date = get-date -Format d_M_yyyy_hh_mm_ss # If $HTMLfile variable set, e-mail messages will be writed to file $HTMLfile = $null $HtLogFile = $ScriptPath + "log.txt" $HtMailData = @{} $HtLogWrite = @{} $global:WriteToLogBool = $null # Task Sheduler Data $TaskUser = "CORPAdministrator"
Выполнить регистрацию скрипта в Task Scheduler:
.VM-Repl-MSG.ps1 -EventTask "Install" -TPwd "Pa$$w0rd"
Скрипт пингает удаленную сторону IPsec туннеля, поправьте IP в строке №174:
$Computer = "192.168.*.*"
Смотрите код… Скрипт по умолчанию отправляет почту при помощи внутреннего сервера, так же есть функция отправки почты при помощи Gmail.
Если Вы улучшите функциональность скрипта или найдете ошибки, пишите hmh@ittc.com.ua
Скачать VM-Repl-MSG-Source.zip
Чтобы быстро передернуть репликацию всех VM
Get-VMReplication | Reset-VMReplicationStatistics Get-VMReplication | Resume-VMReplication
#======================================================================== # Created on: 14.05.2014 20:25 # Created by: HmH # Organization: ITTC # Filename: VM-Repl-MSG.ps1 # Description: Monitor Hyper-V primary server replication #======================================================================== Param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)] [Alias('EventTask')] # This is the name of the parameter e.g. -Status Success [String]$EventT, # This is the value [Don't forget the comma at the end!] [Parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true)] [Alias('TPwd')] [String]$TaskPwd, [Parameter(Mandatory = $false, Position = 2, ValueFromPipelineByPropertyName = $true)] [Alias( 'GUser' )] [String]$GMailUser, [Parameter(Mandatory = $false, Position = 3, ValueFromPipelineByPropertyName = $true)] [Alias( 'GPwd' )] [String]$GMailPwd, [switch]$UseGmail ) #If (!$args[0]) { #write-host "no args" #Exit} $Startdate = Get-Date ##### Configuration Section Starts ##### $SMTPServer = "mail.Corp.com.ua" $EMailMSGTo = "Me " # Send Mail using Gmail account #$UseGmail = $false # Set gmail Email address if $UseGmail = $true $EMailMSGFrom = " HV-Repl " $EMailMSGUseSSL = $false $ScriptPath = Split-Path $MyInvocation.MyCommand.Path $Date = get-date -Format d_M_yyyy_hh_mm_ss # If $HTMLfile variable set, e-mail messages will be writed to file $HTMLfile = $null $HtLogFile = $ScriptPath + "log.txt" $HtMailData = @{} $HtLogWrite = @{} $global:WriteToLogBool = $null # Task Sheduler Data $TaskUser = "CORPAdministrator" ##### Configuration Section Ends##### $HtLog = Get-Content $HtLogFile | Select-Object -last 5 | ConvertFrom-StringData if ($EventT -eq "failed"){ $HtLogWrite.Add("TaskEvent","Failed") write-host "failed" } elseif ($EventT -eq "check") { $HtLogWrite.Add("TaskEvent","Check") } elseif ($EventT -eq "install") { $FailedXMLPath = $ScriptPath + "OnReplFailed.xml" $CheckXMLPath = $ScriptPath + "OnReplCheck.xml" Register-ScheduledTask -Xml (get-content $FailedXMLPath | out-string) -TaskName "OnReplFailed" -User $TaskUser -Password $TaskPwd –Force Register-ScheduledTask -Xml (get-content $CheckXMLPath | out-string) -TaskName "OnReplCheck" -User $TaskUser -Password $TaskPwd –Force Write-Host "Tasks Registered" exit } else {exit} Function CheckSendEMail { $Date = Get-Date $LogDate = Get-Date -Date $HtLog.LogDate $SendThreshold = Get-Date -Date "1:0:0" -UFormat %H:%M:%S $DateDate = $Date - $LogDate If ($HtLog.ReplStatus -ne $HtLogWrite.ReplStatus){ $global:WriteToLogBool = $true Return $true } Elseif ($DateDate -gt $SendThreshold) { if ($HtLogWrite.ReplStatus -ne "Success"){ $global:WriteToLogBool = $true Return $true } else { $global:WriteToLogBool = $false Return $false } } Else { If ($HtLog.TaskEvent -eq "Failed" -and $HtLogWrite.TaskEvent -eq "Check" ){ $global:WriteToLogBool = $true Return $false } Else { $global:WriteToLogBool = $false Return $false } } } function WriteToLog ($ht) { $ht.GetEnumerator() | Sort-Object Name | ForEach-Object {"{0}={1}" -f $_.Name,$_.Value} | Add-Content $HtLogFile } $VMListAll = Get-VM | where {$_.ReplicationState -ne "Disabled"} $HtLogWrite.add("ReplVMsCount",$VMListAll.Count) $VMList = get-vm | where {$_.ReplicationHealth -eq "Critical" -or $_.ReplicationHealth -eq "Warning"} If ($VMList){ $HtLogWrite.Add("ReplStatus","Failed") If ($HtLogWrite.TaskEvent -eq "Failed"){ $HtMailData.add("HeaderMSG","Comp Hyper-V Replication Failed!!! Event Failed") } else { $HtMailData.add("HeaderMSG","Comp Hyper-V Replication Failed!!! Event Check") } } Else { $HtLogWrite.Add("ReplStatus","Success") if ($HtLogWrite.TaskEvent -eq "Check"){ $HtMailData.add("HeaderMSG","Server Hyper-V Replication Success!!! Event Check") } else { $HtMailData.add("HeaderMSG","Server Hyper-V Replication Success!!! Event Failed") } } # Check do we need to send notification E-Mail $SendEMail = CheckSendEMail $Date = Get-Date $HtLogWrite.Add("LogDate",$Date) $HtLogWrite.Add("SendMail",$SendEMail) # Restor VM replication if VM in suspended state # If ($VMListAll -ne $VMList){ # Foreach ($Vm in $VMList) { # If ($Vm.ReplicationState -ne "Replicating") { # $Vm | Reset-VMReplicationStatistics # Start-Sleep -s 3 # $Vm | Resume-VMReplication # } # } # } # Exit script. Because we don't need to send notification e-mail If (!$SendEMail) { if ($WriteToLogBool){WriteToLog $HtLogWrite} exit } Function CheckConnection($IPAddressCheck){ $Ping = @{} $Ping = Get-WmiObject Win32_PingStatus -Filter "Address = '$Computer'" | Select @{Label="Status";Expression={ If ($_.StatusCode -ne 0) {"Failed"} Else {"Success"}}},ResponseTime return $ping } $HtmlMSGPingStatus = "" $Computer = "192.168.*.*" $PingRes = CheckConnection $Computer if ($PingRes.Status -eq "Success") { $HtmlMSGPingStatus += "
- IPSec Link ping: «+$PingRes.Status + » » + $PingRes.ResponseTime + » ms» + «
" +"`r`n" } Else { $HtmlMSGPingStatus += "
- IPSec Link ping: «+$PingRes.Status + «
" +"`r`n" } $Computer = "8.8.8.8" $PingRes = CheckConnection $Computer if ($PingRes.Status -eq "Success") { $HtmlMSGPingStatus += "
- Google DNS ping: «+$PingRes.Status + » » + $PingRes.ResponseTime + » ms» + «
" +"`r`n" } Else { $HtmlMSGPingStatus += "
- Google DNS ping: «+$PingRes.Status + «
" +"`r`n" $HTMLfile = $ScriptPath + "MSGBody_"+$date+".html" } $HtMailData.add("PingStatus",$HtmlMSGPingStatus) $RVMsStateTbl = "" $i = 1 Foreach ($VM in $VMListAll) { $VMReplState = $VM | Measure-VMReplication $i++ if ($i % 2 -eq 1) { $RVMsStateTbl += "" +"`r`n" } else { $RVMsStateTbl += "" +"`r`n" } $RVMsStateTbl += "" + $VMReplState.Name + "" + "" + $VMReplState.State + "" + "" + $VMReplState.Health + "" + "" + $VMReplState.LReplTime + "" + "" + [math]::Round(($VMReplState.PReplSize/1073741824),2,1) + "" + "" + [math]::Round(($VMReplState.AvgReplSize/1073741824),2,1) + "" +"`r`n" $RVMsStateTbl += "" +"`r`n" } $HtMailData.Add("ReplVMsState",$RVMsStateTbl) ## # TODO Start ## #Loop through each VM to get the corresponding events $i = 1 ForEach ($VM in $VMList) { $VMReplStats = $VM | Measure-VMReplication #We should start getting events after last successful replication. Till then replication was happening. $FromDate = $VMReplStats.LastReplicationTime #This string will filter for events for the current VM only $FilterString = "*[UserData[VmlEventLog[(VmId='" + $VM.ID + "')]]]" $EventList = Get-WinEvent -FilterXML $FilterString | Where {$_.TimeCreated -ge $FromDate -and $_.LevelDisplayName -eq "Error"} | Select -Last 3 #Dump relevant information to the CSV file foreach ($Event in $EventList) { $i++ if ($i % 2 -eq 1) { $MSGtbl += "" +"`r`n" } else { $MSGtbl += "" +"`r`n" } If ($VM.ReplicationMode -eq "Primary") { $Server = $VMReplStats.PrimaryServerName } Else { $Server = $VMReplStats.ReplicaServerName } #$csv +=$VM.Name + "," + $Event.TimeCreated + "," + $Server + "," + $Event.Message +"`r`n" $MSGtbl += "" + $VM.Name + "" + "" + $Event.TimeCreated + "" + "" + $Server + "" + "" + $Event.Message + "" +"`r`n" $MSGtbl += "" +"`r`n" } } $HtMailData.Add("ReplStatus",$MSGtbl) ## # TODO End ## Function GenerateEMailMSG ($HtMailData){ $HeaderReplVMsState = @"
Replication VMs Status: | ||||||
«@ $BottomReplVMsState = @»
|
"@ $HeaderPingStatus = @"
Ping status: |
|
"@ $HeaderReplStatus = @"
Replication log details: | ||||
«@ $BottomReplStatus = @»
|
"@ $EMailMSGToSend = @"
$(if ($HtMailData.PingStatus) { $HeaderPingStatus $HtMailData.Get_Item(«PingStatus») $BottomPingStatus }) $(if ($HtMailData.ReplVMsState){ $HeaderReplVMsState $HtMailData.Get_Item(«ReplVMsState») $BottomReplVMsState }) $(if ($HtMailData.ReplStatus) { $HeaderReplStatus $HtMailData.Get_Item(«ReplStatus») $BottomReplStatus })
$(if ($HtMailData.HeaderMSG){$HtMailData.Get_Item(«HeaderMSG»)}) |
This is automated report on replication fail! Script total time: $( ((Get-Date) — $StartDate).ToString().SubString(0,8) ) |
"@ return $EMailMSGToSend } $HtmlMSGBody = "" $HtmlMSGBody = GenerateEMailMSG $HtMailData If ($HTMLfile -ne $null) { $fso = new-object -comobject scripting.filesystemobject $file = $fso.CreateTextFile($HTMLfile,$true) $file.write($HtmlMSGBody) $file.close() } If ($HtLogWrite.ReplStatus -eq "Success") { $EmailMSGSubject = "[ATTENTION] Replication restored!" } Else { $EmailMSGSubject = "[ATTENTION] Replication requires your attention!" } #If there are VMs in critical health state, send an email to me If ($Gmail){ $SMTPServer = "smtp.gmail.com" $SMTPClient = New-Object Net.Mail.SMTPClient( $SmtpServer, 587 ) $SMTPClient.EnableSSL = $true $SMTPClient.Credentials = New-Object System.Net.NetworkCredential($GMailUser, $GMailPwd); $emailMessage = New-Object System.Net.Mail.MailMessage $emailMessage.SubjectEncoding = System.Text.Encoding.UTF8 $emailMessage.BodyEncoding = System.Text.Encoding.UTF8 $emailMessage.BodyTransferEncoding = System.Text.Encoding.UTF8 $emailMessage.IsBodyHtml = $true $emailMessage.From = $EMailMSGFrom foreach ( $recipient in $EMailMSGTo ) { $emailMessage.To.Add( $recipient ) } $emailMessage.Subject = $EmailMSGSubject $emailMessage.Body = $HtmlMSGBody $SMTPClient.Send( $emailMessage ) } else { send-mailmessage -to "$EMailMSGTo" -from "$EMailMSGFrom" -subject "$EmailMSGSubject" -Encoding "UTF8" -BodyAsHtml -body "$HtmlMSGBody" -smtpServer "$SMTPServer" } Write-host "Log Write next Line" # Finaly write HashTable to log WriteToLog $HtLogWrite
3 thoughts on “Powershell cкрипт мониторинга репликации Hyper-V”