Если в Вашей инфраструктуре настроена репликация виртуальных машин, то Вы наверняка не раз сталкивались с тем, что репликация останавливалась по разным причинам. Чтобы вовремя отреагировать на ошибки репликации был написан данный скрипт.
Зачем мониторить репликацию?
Остановившаяся репликация может привезти к очень опасной ситуации для всех реплицируемых виртуальных машин, в тот момент, когда закончится место у стораджа на котором хранятся виртуалки. Так же существует всем известный закон подлости — когда репликация остановилась, через некоторое время (например сутки) что-то произошло с основным сервером и тогда Вы теряете не реплицированные данные.
Скрипт реагирует на регистрацию ошибок в журнале событий ОС, а так же с периодичностью 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”