Monitoring the DAG Replication Network

The Exchange 2010 Database Availability Group (DAG) is an important feature that provides high availability.  Therefore, monitoring the DAG replication network is an important part of keeping the high availability in your environment as healthy as possible.  Replication of Exchange 2010 databases in your messaging environment has specific network requirements outlined in this TechNet document.  The best scenario is to use two network adapters per DAG node member.  One adapter supports the MAPI Network which is used by other servers, for example other Exchange 2010 servers or directory servers.  The other adapter is for the DAG replication network which is dedicated for database replication.  With all this said, Exchange 2010 is smart enough to switch replication from the replication network to the MAPI network in the event of a communications problem on the DAG replication network.

So how do you know that this event has occurred and that the DAG replication network is not replicating all your data?  Hopefully you have some sort of monitoring in place that will let you know!  If you don’t then let’s get something in place.  This script will do the following:

  • Collect all the mounted databases and database copies.
  • Checks the status of the IncomingLogCopyNetwork and OutgoingConnections.
  • Applies logic (defined by you about your environment) to determine if a change has occurred.
  • Finally we’ll use a datatable to create an HTML email for notification purposes.

First establish the name of the MAPI network.  You can use Get-DatabaseAvailabilityGroupNetwork to see the networks in use by your DAG.  Once you have established the MAPI network name, put it into a variable.  We will use the MAPI network name in our logic checks to make sure it isn’t listed.

$ReplNet = "MapiNetwork"

Now enumerate all the mounted databases and database copies, dump them into a variable

$AllDBs = Get-MailboxDatabase | `
where {$_.mastertype -eq "DatabaseAvailabilityGroup" -and $_.recovery -ne "true"} | `
Get-MailboxDatabaseCopyStatus -ConnectionStatus

To get a better mental picture of the replication flow related to the collected data, pipe the $AllDbs variable to Select-Object:

$ALLDBs | Select-Object name,status,IncomingLogCopyingNetwork,OutgoingConnections | `
Format-Table -autosize

The IncomingLogCopyingNetwork corresponds to the database replicas. The status will show the source DAG node, the one pushing logs, and the network it is using.  You’ll want to see that your MAPI network is not specified here.  The OutgoingConnections corresponds to the mounted database.  The status shows the target DAG nodes and again, the network it is using.  You do not want to see the MAPI network replicating data.

We will use a datatable to send an HTML email notification if needed.  So let’s prep the structure here:

# Create the master datatable to hold all the collected mailbox data.
$ReplData = New-Object System.Data.DataTable “ReplData”
# Create columns in the data table by specifying their name and attribute type.
$ReplData.Columns.Add("Name",[String]) | Out-Null
$ReplData.Columns.Add("Status",[String]) | Out-Null
$ReplData.Columns.Add("IncomingLogCopyingNetwork",[String]) | Out-Null
$ReplData.Columns.Add("OutgoingConnections0",[String]) | Out-Null
$ReplData.Columns.Add("OutgoingConnections1",[String]) | Out-Null

Next we make an empty array for checking our data:

$DBCheck = @()

Now let’s do some work on the returned data.  We are using the ForEach loop to look at each database individually.  If the status is Healthy, meaning it is a database replica, check the incoming log network attribute.  If it matches the MAPI network name then you have a problem, so append the database to the $DBCheck array. Do the same thing for any databases that have a status of mounted.  Wait a second… What is this [0] and [1] business?  This illustrates the example that you can have more than one target in the OutgoingConnections.  There are two database replicas in my test environment and PowerShell can look at them by using the index method.  Also note that this code block does not account for unhealthy replication status.  Don’t overlook this fact if you use the code, please build upon it to suit your needs.

ForEach ($DB in $AllDBs) {
	if ($DB.Status -eq "Healthy" -and $DB.IncomingLogCopyingNetwork -match $ReplNet) {
		$DBCheck += $DB
	} Else {
	if ($DB.Status -eq "Mounted" -and $DB.OutgoingConnections[0].Status -match $ReplNet) {
		$DBCheck += $DB
	} ElseIf ($DB.Status -eq "Mounted" -and $DB.OutgoingConnections[1].Status -match $ReplNet) {
		$DBCheck += $DB
	} Else {

Refine the captured databases by selecting the attributes that belong in the datatable we prepped earlier.

$DBCheck = $DBCheck | select name,status,incominglogcopyingnetwork,outgoingconnections

We must now sift through the databases noted (i.e. captured) during the previous loop.  So if there is any data in the $DBCheck variable we know that there is a replication offender that needs to be identified.  These offenders populate the datatable.  First we’ll check the OutgoingConnections attribute and if it is null then we write the replication network of the IncomingLogCopyingNetwork.  Else we inspect the OutgoingConnections.

ForEach ($DBnoted in $DBCheck) {
	If ($DBnoted.OutgoingConnections -eq $null) {
		$NewTBRow = $ReplData.NewRow()
		$NewTBRow.Name = $DBnoted.Name
		$NewTBRow.Status = $DBnoted.Status
		$NewTBRow.IncomingLogCopyingNetwork = $DBnoted.IncomingLogCopyingNetwork
		$NewTBRow.OutgoingConnections0 = $null
		$NewTBRow.OutgoingConnections1 = $null
	} Else {
		$NewTBRow = $ReplData.NewRow()
		$NewTBRow.Name = $DBnoted.Name
		$NewTBRow.Status = $DBnoted.Status
		$NewTBRow.IncomingLogCopyingNetwork = $DBnoted.IncomingLogCopyingNetwork
		$NewTBRow.OutgoingConnections0 = $DBnoted.OutgoingConnections[0]
		$NewTBRow.OutgoingConnections1 = $DBnoted.OutgoingConnections[1]

Finally we’ll check to see if the $DBCheck variable is indeed null. If it isn’t we’ll build and HTML email and send it off!

if ($null -eq $DBCheck) {
	# Do nothing here when null equals $DBCheck
} else {
	$EmailSubject = "Replication Alert: Databases are replicating on the wrong network"
	#Prep the body of the email message with table styles to control the formatting of any tables presented in it.
	$EmailBody = "`r`n" $EmailBody += "`r`n"
	$EmailBody += "</pre> `r`n"
	$EmailBody += "TABLE{border-width: 1px;border-style: outset;border-color: black;border-spacing: 1px;border-collapse: separate;}`r`n"
	$EmailBody += "TH{border-width: 1px;padding: 1px;border-style: inset;border-color: black;}`r`n"
	$EmailBody += "TD{border-width: 1px;padding-left: 3px;padding-right: 3px;border-style: inset;border-color: black;}`r`n"
	$EmailBody += "TABLE.First{border-style: none;}`r`n"
	$EmailBody += "TD.First{border-style: none;}`r`n"
	$EmailBody += "<pre> `r`n"
	$EmailBody += "`r`n" $EmailBody += "`r`n"
	$EmailBody += $ReplData | convertto-html -Fragment @{ Label = "Name"; Expression = { $_.Name } },`
	@{ Label = "Status"; Expression = { $_.Status } }, @{ Label = "IncomingLogCopyingNetwork"; Expression = { $_.IncomingLogCopyingNetwork } },`
	@{ Label = "OutgoingConnections0"; Expression = { $_.OutgoingConnections0 } }, @{ Label = "OutgoingConnections1"; Expression = { $_.OutgoingConnections1 } }
	$EmailBody += "</pre> <hr /> <pre>"
	#Close out the HTML content in the body of the email message.
	$EmailBody += "`r`n" $EmailBody += "`r`n"
	Send-MailMessage -to `
	-from `
	-subject "DAG Replication Network" `
	-BodyAsHtml $EmailBody `
	-smtpserver "Exchange"

This is something that you can break down and run during one of those situation in which you aren’t quite sure if operations are normal in your environment.  Better to have an automated method of quickly determining status that poking around and trying to figure out what could be wrong with your DAG replication network.  Another application of this script is to run it as a scheduled task.  You could run it on a tight interval or engage it when you know that there is some sort of work being done that could affect your Exchange 2010 DAG.

Leave a Comment