Powershell and DFSR
Sorry for the long delay between posts, but work has been absolutely crazy.
Anyway, one of the recent tasks I have been working on is to find a way to check DFSR to make sure that our remote sites are properly replicating data back to our corporate datacenter. Part of this new infrastructure relies heavily on Microsoft DFSR and all the cool stuff it brings (in 2003 R2).
Our support teams have been asking for ways to ensure that data has completely synchronized to our corporate datacenter every night. Unfortunately there isn’t an easy way to determine this scriptomatically. Well leave it to me to try some different things and attempt to put SOMETHING in place to do this.
Basically we have remote sites replicating during non-business-hours back to a central “hub” DFSR server. We would then backup this “hub” server with our corporate backup infrastructure. This is a WHOLE lot easier than getting users in remote sites to swap tapes or whatever and send them offsite, etc.
The only way I have been able to determine the state of replication is to query the “backlog” of the remote site DFSR servers. This should tell us how many files are sitting there awaiting replication. DFSRDIAG is a tool that can help us enumerate these files, but then we have to parse out the data. We also need to know which replication partner, which replicated folder, and which replication group these remote sites belong to.
One way to enumerate that info is through a WMI query. From the DFSR “hub” server you can enumerate all DFSR connections, groups, folders, etc. by running some queries against the “MicrosoftDFS” namespace. This is different from standard WMI queries because the default namespace (cimv2) does not contain any DFSR configuruations.
Once we connect to this namespace, it is a fairly trivial task to cycle through all the connection partners, replication groups, and replicated folders.
We can then run the “DFSRDIAG” tool to see how many files are in the backlog.
Once we have determine how many files are out there for each replicated folder, we then write a custom event log entry and have our monitoring tools pick those up.
For this script I have set a threshold of 10 files before writing an “error” event log. This can easily be changed based on your specific needs, though.
You should also be able to easily customize the eventIDs and source information by modifying the values assigned to those variables.
For actually writing to the event log, I am “borrowing” some code my colleauge Mike put together.
Anyway, I think the script is fairly self explanitory. If you need additionaly info or have questions, please let me know.
Thanks and happy scripting…
– Mark
## Check-DFSR.ps1 script ## Written by: Mark A. Weaver ## Site: http://www.vmweaver.com ## Version: 2.0 ## Date: 5/7/2009 ## Purpose: This script will query the local WMI root for DFS replication groups and folders. ## It will then run DFS utilities to determine the number of files in the backlog on the ## destination partners in the replication group. ## ## This script was written for the spefic use of being run on a centralized DFSR server ## which acts as the HUB for remote office backups. ## ## ## Monitoring Rules can be setup to collect and report on the events being generated. ## ## Event information is written to the Application log using the EventIDs at the bottom. ## Input: None ############################# ## Updates: ## 20090408 Weaver: Fixed issue where multiple events are generated throughout the execution ## 20090408 Weaver: Added BacklogFileCount to event message ## 20090409 Weaver: Fixed list of replication connections issue due to change in replication topology ## 20090507 Weaver: Added functionality to return results from all partners in the replication ## ## ###################################################################### ###################################################################### # Write-Event powershell function # Written by Mike Hays # http://blog.mike-hays.net # # function Write-Event( [string]$Source = $(throw "An event Source must be specified."), [int]$EventId = $(throw "An Event ID must be specified."), [System.Diagnostics.EventLogEntryType] $EventType = $(throw "Event EventType must be specified. (Error, Warning, Information, SuccessAudit, FailureAudit)"), [string]$Message = $(throw "An event Message must be specified."), $EventLog ) { #Uncommon event logs can be specified (even custom ones), but since that isn't generally #the desired result, I prevent that here $acceptedEventLogs = "Application", "System" if ($eventEventLog -eq $null) { $eventEventLog = "Application" } elseif (!($acceptedEventLogs -icontains $eventEventLog)) { Write-Host "This function supports writing to the following event logs:" $acceptedEventLogs Write-Host "Defaulting to Application Eventlog" $eventEventLog = "Application" } #Create a .NET object that is connected to the Eventlog $event = New-Object -type System.Diagnostics.Eventlog -argumentlist $EventLog #Define the Source property $event.Source = $Source #Write the event to the log $event.WriteEntry($Message, $EventType, $EventId) } ###################################################################### ###################################################################### ## Main ## Errors written: ## Log File: Application ## Source: Check-DFSR Script ## ID: 9500 - Lists fully replicated replication folders ## ID: 9501 - Lists replication folders with less than the $BacklogErrorLevel files waiting ## ID: 9502 - Lists replication folders with more than the $BacklogErrorLevel files waiting ## ID: 9503 - If a connection is not pingable, this event is written. $BacklogErrorLevel = 10 $ComputerName = $env:ComputerName ## Query DFSR groups from the local MicrosftDFS WMI namespace. $DFSRGroupWMIQuery = "SELECT * FROM DfsrReplicationGroupConfig" $RGroups = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query $DFSRGroupWMIQuery ## Setup my variables $ping = New-Object System.Net.NetworkInformation.Ping $SuccessAudit = $Null $WarningAudit = $Null $ErrorAudit = $Null $EventSource = "Check-DFSR Script" $SuccessEventID = 9500 $WarningEventID = 9501 $ErrorEventID = 9502 $NoPingEventID = 9503 foreach ($Group in $RGroups) { ## Cycle through all Replication groups found $DFSRGFoldersWMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID='" + $Group.ReplicationGroupGUID + "'" $RGFolders = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query $DFSRGFoldersWMIQuery ## Grab all connections associated with a Replication Group $DFSRConnectionWMIQuery = "SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID='" + $Group.ReplicationGroupGUID + "'" $RGConnections = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query $DFSRConnectionWMIQuery foreach ($Connection in $RGConnections) { $ConnectionName = $Connection.PartnerName.Trim() $IsInBound = $Connection.Inbound $IsEnabled = $Connection.Enabled ## Do not attempt to look at connections that are Disabled if ($IsEnabled -eq $True) { ## If the connection is not ping-able, do not attempt to query it for Backlog info $Reply = $ping.send("$ConnectionName") if ($reply.Status -eq "Success") { ## Cycle through the Replication Folders that are part of the replication group and run DFSRDIAG tool to determine the backlog on the connection partners. foreach ($Folder in $RGFolders) { $RGName = $Group.ReplicationGroupName $RFName = $Folder.ReplicatedFolderName ## Determine if current connect is an inbound connection or not, set send/receive members accordingly if ($IsInBound -eq $True) { $SendingMember = $ConnectionName $ReceivingMember = $ComputerName } else { $SendingMember = $ComputerName $ReceivingMember = $ConnectionName } $Out = $RGName + ":" + $RFName + " - S:"+$SendingMember + " R:" + $ReceivingMember Write-Host $Out ## Execute the dfsrdiag command and get results back in the $Backlog variable $BLCommand = "dfsrdiag Backlog /RGName:'" + $RGName + "' /RFName:'" + $RFName + "' /SendingMember:" + $SendingMember + " /ReceivingMember:" + $ReceivingMember $Backlog = Invoke-Expression -Command $BLCommand $BackLogFilecount = 0 foreach ($item in $Backlog) { if ($item -ilike "*Backlog File count*") { $BacklogFileCount = [int]$Item.Split(":")[1].Trim() } } if ($BacklogFileCount -eq 0) { #Update Success Audit $SuccessAudit += $RGName + ":" + $RFName + " is in sync with 0 files in the backlog from "+ $SendingMember + " to " + $ReceivingMember +".`n" } elseif ($BacklogFilecount -lt $BacklogErrorLevel) { #Update Warning Audit $WarningAudit += $RGName + ":" + $RFName + " has " + $BacklogFileCount + " files in the backlog from " + $SendingMember + " to " + $ReceivingMember + ".`n" } else { #Update Error Audit $ErrorAudit += $RGName + ":" + $RFName + " has " + $BacklogFilecount + " files in the backlog from " + $SendingMember + " to " + $ReceivingMember + ".`n" } #Write-Host + $Folder.ReplicatedFolderName "- " $BackLogFilecount -foregroundcolor $FGColor } } else { Write-Host $ConnectionName "is not pingable" $NoPingMessage = "Server """ + $ConnectionName + """ could not be reached.`nPlease verify it is on the network and pingable." Write-Event $EventSource $NoPingEventID "Warning" $NoPingMessage "Application" } } } } ## Write my events to the local Application log. if ($SuccessAudit -ne $Null) { Write-Event $EventSource $SuccessEventID "Information" $SuccessAudit "Application" } if ($WarningAudit -ne $Null) { Write-Event $EventSource $WarningEventID "Warning" $WarningAudit "Application" } if ($ErrorAudit -ne $Null) { Write-Event $EventSource $ErrorEventID "Error" $ErrorAudit "Application" }
Hi! There is a message: “Exception calling” WriteEntry “with” 3 “argument (s):” Log entry string is too long. A string written to the event log cannot exceed 32766 characters. “”
Show you how to fix this situation? Or how can I redirect log to a text file?
Serge,
Yikes! Sorry to hear about the issue you are having and thanks for all the info you provided. Right now I am buried at work, but I will need to come back and revist your reply…
— Mark
Alex,
sounds like you are hitting a windows limit on eventlog entry size.
One way I think I will approach this is to re-write the eventlog functions to split out messages longer than the limit and create mulitple entries. This may take me some time as I am quite swamped at work right now.
The other thing you ask is redirecting to a log file. This should be fairly simple.
This (basically) specifies where you want your logs to be written and sticks a timestamp in front of it.
i haven’t tested these changes, so let me know if you run into issues..
Just replace the last part of the script with this instead..
################################
$LogDate=Get-Date -Format “yyyyMMddhhmm”
$SuccessLog = “C:\” +$logDate + “-Success.log”
$WarningLog = “C:\” +$logDate + “-Warning.log”
$ErrorLog = “C:\” +$logDate + “-Error.log”
if ($SuccessAudit -ne $Null)
{
#Write-Event $EventSource $SuccessEventID “Information” $SuccessAudit “Application”
Out-File -InputObject $SuccessAudit -FilePath $SuccessLog -Append
}
if ($WarningAudit -ne $Null)
{
#Write-Event $EventSource $WarningEventID “Warning” $WarningAudit “Application”
Out-File -InputObject $WarningAudit -FilePath $WarningLog -Append
}
if ($ErrorAudit -ne $Null)
{
#Write-Event $EventSource $ErrorEventID “Error” $ErrorAudit “Application”
Out-File -InputObject $ErrorAudit -FilePath $ErrorLog -Append
}
########################################
— Mark
Mark,
I was very pleased to find this script and see others have had success in its implementation. I have scheduled this script to run on our hub dfsr servers and I see the check-dfsr events in the eventlog. I have left the backlogerrorlevel at the default value of 10. The problem I am having is it is only reporting 9500 events and indicating all of the replication group connections are in sync with 0 backlog even when there are really backlogs greater than 100 (verified by running the dfsrdiag backlog manually). Do you have any ideas of what could cause the script to report incorrectly?
Any ideas would really be appreciated,
Thank you,
Sharon
Sharon,
Do your replication groups or replicated folder names have spaces in them?
There was a change made that put quotes around the replication groups and folder names. Please see the previous comments to make sure you have this.
I probably need to do some more error checking to make sure no false-positives are generated.
– Mark
For anyone that wants emails sent out I have updated the script to include HTML emails with formatting. (Added by Moderator from previous post)
Moderator please remove all other comments from me.. This should work now:
$SuccessAuditHTML = “HTML”
$SuccessAuditHTML += “BODY”
$WarningAuditHTML = “HTML”
$WarningAuditHTML += “BODY”
$ErrorAuditHTML = “HTML”
$ErrorAuditHTML += “BODY”
foreach ($Group in $RGroups)
{
## Cycle through all Replication groups found
$DFSRGFoldersWMIQuery = “SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID=’” + $Group.ReplicationGroupGUID + “‘”
$RGFolders = Get-WmiObject -Namespace “root\MicrosoftDFS” -Query $DFSRGFoldersWMIQuery
## Grab all connections associated with a Replication Group
$DFSRConnectionWMIQuery = “SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID=’” + $Group.ReplicationGroupGUID + “‘”
$RGConnections = Get-WmiObject -Namespace “root\MicrosoftDFS” -Query $DFSRConnectionWMIQuery
foreach ($Connection in $RGConnections)
{
$ConnectionName = $Connection.PartnerName.Trim()
$IsInBound = $Connection.Inbound
$IsEnabled = $Connection.Enabled
## Do not attempt to look at connections that are Disabled
if ($IsEnabled -eq $True)
{
## If the connection is not ping-able, do not attempt to query it for Backlog info
$Reply = $ping.send(“$ConnectionName”)
if ($reply.Status -eq “Success”)
{
## Cycle through the Replication Folders that are part of the replication group and run DFSRDIAG tool to determine the backlog on the connection partners.
foreach ($Folder in $RGFolders)
{
$RGName = $Group.ReplicationGroupName
$RFName = $Folder.ReplicatedFolderName
## Determine if current connect is an inbound connection or not, set send/receive members accordingly
if ($IsInBound -eq $True)
{
$SendingMember = $ConnectionName
$ReceivingMember = $ComputerName
}
else
{
$SendingMember = $ComputerName
$ReceivingMember = $ConnectionName
}
$Out = $RFName + ” – S:”+$SendingMember + ” R:” + $ReceivingMember
Write-Host $Out
## Execute the dfsrdiag command and get results back in the $Backlog variable
$BLCommand = “dfsrdiag Backlog /RGName:’” + $RGName + “‘ /RFName:’” + $RFName + “‘ /SendingMember:” + $SendingMember + ” /ReceivingMember:” + $ReceivingMember
$Backlog = Invoke-Expression -Command $BLCommand
$BackLogFilecount = 0
foreach ($item in $Backlog)
{
if ($item -ilike “*Backlog File count*”)
{
$BacklogFileCount = [int]$Item.Split(“:”)[1].Trim()
}
}
if ($BacklogFileCount -eq 0)
{
#Update Success Audit
$SuccessAudit += $RFName + ” : 0 files backlogged from “+ $SendingMember + ” to ” + $ReceivingMember +”.`n`r”
$SuccessAuditHTML += $RFName + ” : 0 files backlogged from “+ $SendingMember + ” to ” + $ReceivingMember + “BR”
}
elseif ($BacklogFilecount -lt $BacklogErrorLevel)
{
#Update Warning Audit
$WarningAudit += $RFName + ” ” + $BacklogFileCount + ” backlogged files from ” + $SendingMember + ” to ” + $ReceivingMember + “.`n`r”
$WarningAuditHTML += $RFName + ” ” + $BacklogFileCount + ” backlogged files from ” + $SendingMember + ” to ” + $ReceivingMember + “BR”
}
else
{
#Update Error Audit
$ErrorAudit += $RFName + ” ” + $BacklogFilecount + ” backlogged files from ” + $SendingMember + ” to ” + $ReceivingMember + “.`n`r”
$ErrorAuditHTML += $RFName + ” ” + $BacklogFileCount + ” backlogged files from ” + $SendingMember + ” to ” + $ReceivingMember + “BR”
}
#Write-Host + $Folder.ReplicatedFolderName “- ” $BackLogFilecount -foregroundcolor $FGColor
}
}
else
{
Write-Host $ConnectionName “is not pingable”
$NoPingMessage = “Server “”" + $ConnectionName + “”" could not be reached.`nPlease verify it is on the network and pingable.”
Write-Event $EventSource $NoPingEventID “Warning” $NoPingMessage “Application”
}
}
}
$SuccessAuditHTML += “BR”
$WarningAuditHTML += “BR”
$ErrorAuditHTML += “BR”
}
## Write my events to the local Application log.
$SuccessAuditHTML += “/BODY”
$SuccessAuditHTML += “/HTML”
$WarningAuditHTML += “/BODY”
$WarningAuditHTML += “/HTML”
$ErrorAuditHTML += “/BODY”
$ErrorAuditHTML += “/HTML”
Write-Host $SuccessAuditHTML
if ($SuccessAudit -ne $Null)
{
Write-Event $EventSource $SuccessEventID “Information” $SuccessAudit “Application”
}
if ($WarningAudit -ne $Null)
{
Write-Event $EventSource $WarningEventID “Warning” $WarningAudit “Application”
}
if ($ErrorAudit -ne $Null)
{
Write-Event $EventSource $ErrorEventID “Error” $ErrorAudit “Application”
}
## This is to create an email content
$Mail = New-Object System.Net.Mail.MailMessage($Sender,$Recipient)
$Mail.IsBodyHTML = $True
## Setup SMTP Mail Server info
$MailClient = New-Object System.Net.Mail.SmtpClient
$MailClient.Host = $Mailserver
if ($SuccessAudit -ne $NULL)
{
$MailTxt = “Information ”
$Mail.Subject = $MailTxt + “: DFS-R Report on ” + (Get-Date)
$Mail.Body = $SuccessAuditHTML
# Send the message
$MailClient.Send($Mail)
}
if ($WarningAudit -ne $NULL)
{
$MailTxt = “Warning ”
$Mail.Subject = $MailTxt + “: DFS-R Report on ” + (Get-Date)
$Mail.Body = $WarningAuditHTML
# Send the message
$MailClient.Send($Mail)
}
if ($ErrorAudit -ne $NULL)
{
$MailTxt = “Error ”
$Mail.Subject = $MailTxt + “: DFS-R Report on ” + (Get-Date)
$Mail.Body = $ErrorAuditHTML
# Send the message
$MailClient.Send($Mail)
}
You will need to add the HTML Tags “” to HTML, BODY, and BR within the script.
Sorry for the multiple comments
Steve,
Wow! Thanks for the update. I am sure that will help a bunch of folks out. I appreciate the effort on this.
— Mark
@Steve
What do you mean by this because my emails have no formatting:
You will need to add the HTML Tags “” to HTML, BODY, and BR within the script.
N/M I hadn’t had my coffee for the morning yet =)
Fantastic script, it was exactly what I needed. Thanks!
Glad it worked out for you! Let me know if you have suggestions on how to improve it.
– Mark
I love the additions of having email notification sent out and that’s scheduled once per day so thank you for that piece!!
I’ve also updated your script to run on my desktop and query the remote hub server so i can easily run it on the fly and without having to be logged in locally on the hub.
Excellent script! It proves to be very useful. Do you think there is a way to monitor the whole mesh?
eg: you have three servers a,b,c currently this script runs on server ‘a’ it will perfectly monitor the backlog from a-b,a-c (inbound and outbound). It would be nice if there was a way that it also monitored b-c (inbound and outbound). The wmi objects only show the connections to the local server”a’ and not to the whole mesh. It’s just an idea.
Many thanks in advance!
Thanks! Yeah, I have thought I about re-doing it to monitor a whole mesh, but I think it would really require almost a complete re-write.
I may try to wrap my head around that at some point, but right now I have so much going on.
Good suggestion, though, and I probably should have just written it that way to begin with, but it wasn’t really needed for the project I was working on.
— Mark
@Mark A. Weaver
The problem that i stumbled on was that WMI doesn’t reveal the other partners. While the DFS Management.msc will show this under [DFS Management|Replication| tab connections]. Do you know a quick solution to query this info? I’m happy to share my updated script once it’s finished..
Well, I think you would need to query each replication partner and query it’s replication partners, etc, until the entire mesh has been enumerated and each path checked for replication status.
For example:
ServerA
ServerB
ServerC
ServerD
..are in a fully meshed DFS Replication group.
A->B (A replicates to B)
A->C
A->D
B->A
B->C
B->D
…etc…
So, first you would need to query A for its replication partners and the replication state, then go to each partner and query what replication partners IT has for the same replication group, etc, etc.
If you look through the other comments, I think there was info about being able to get the backlog count through the WMI provider. In this way you should be able to get all of the information needed to check back log counts remotely through the WMI namespace and classes.
Not too sure if I am making sense with this.
Conceivably this could be done with some type of recursive function to walk the entire mesh.
The replication group information may also live in ActiveDirectory, though I am too sure where.
I will see if I can research this more, too.
Sorry I couldn’t be of more help.
— Mark
@Mark A. Weaver
I’ll start digging first in AD trying to find the configuration there..
Thanks! Actually this was about the same I was thinking.
Dear Mark,
Great script and works perfect, but question is it posible to run this script also on a other suport server instead of the Hub Server.
Johan
@Shane
Can you please post your version of the script i would like to run te script also on a remote server.
Greets Johan
Thanks!
I am sure it would be possible by pointing the wmi queries at the hub server. You can try that by putting the “-ComputerName ” switch onto the Get-WMIObject calls I am making to assign $RGroups, $RGFolders, and $RGConnections.
Keep in mind that the ping test will be from the server the script is running on. Additionally I use the DFSRDIAG tool to actually do the real DFSR work, so this tool will need to be installed on the server from which you are running this.
I believe there was a comment earlier about being able to query the backlog count through WMI instead of using the DFSRDIAG tool, but I can’t seem to locate it right now.
I don’t currently have a DFSR infrastructure I can test this against, unfortunately.
Please test it out and let me know how it works by doing those few changes…
Hope this helps!
– Mark
I have written a VBScript that enumerates all the members, connections etc, from the System\DFSR-GlobalSettings\\Topology OU.
Using adsiedit, everything is GUID based, but there are attributes that reveal the hostname of the endpoints. These are actually the receiving servers, and they have msDFSR-Connection objects associated which my script enumerates the actual sending hostname and whether the link is enabled or not. It then simply shells out with the dfsrdiag backlog command and reports accordingly.
The topology I have implemented is multi-tiered with two “root” servers, multiple regional “hubs” and over 50 servers globally deployed in total and over 300Gb replicated. I have included a “self protection” check that if there is a massive backlog into the root servers for some reason the inbound replication link into the root servers is automatically disabled and email alerting is sent to my team. This stops a global replication/reconciliation cycle being triggered.
Awesome! Do you have a link that you can post to it?
— Mark
so i ran this script, the original at the top, and its picking up my SYSVOL replication only and not my replication group i created manually. How do i get this to stop looking at my SYSVOL replication?
I am running win2k8 R2 with DFS-R replication group.
Interesting… I hadn’t seen that before…
If you just do a :
Get-WmiObject -Namespace “root\MicrosoftDFS” -query “SELECT * FROM DfsrReplicationGroupConfig” | Select-Object ReplicationGroupName
Do you see your replication group (non-SYSVOL) that you created?
Mark
@Mark A. Weaver
nope, i don’t see it, command worked but the list/table is empty.
@Mark A. Weaver
Here is the output and what happens.
PS C:\Windows\system32> ######################################################################
PS C:\Windows\system32> ######################################################################
PS C:\Windows\system32> ## Main
PS C:\Windows\system32> ## Errors written:
PS C:\Windows\system32> ## Log File: Application
PS C:\Windows\system32> ## Source: Check-DFSR Script
PS C:\Windows\system32> ## ID: 9500 – Lists fully replicated replication folders
PS C:\Windows\system32> ## ID: 9501 – Lists replication folders with less than the $BacklogErrorLevel files waiting
PS C:\Windows\system32> ## ID: 9502 – Lists replication folders with more than the $BacklogErrorLevel files waiting
PS C:\Windows\system32> ## ID: 9503 – If a connection is not pingable, this event is written.
PS C:\Windows\system32>
PS C:\Windows\system32> $BacklogErrorLevel = 10
PS C:\Windows\system32>
PS C:\Windows\system32> $ComputerName = $env:ComputerName
PS C:\Windows\system32> ## Query DFSR groups from the local MicrosftDFS WMI namespace.
PS C:\Windows\system32> $DFSRGroupWMIQuery = “SELECT * FROM DfsrReplicationGroupConfig”
PS C:\Windows\system32> $RGroups = Get-WmiObject -Namespace “root\MicrosoftDFS” -Query $DFSRGroupWMIQuery
PS C:\Windows\system32>
PS C:\Windows\system32>
PS C:\Windows\system32> ## Setup my variables
PS C:\Windows\system32> $ping = New-Object System.Net.NetworkInformation.Ping
PS C:\Windows\system32> $SuccessAudit = $Null
PS C:\Windows\system32> $WarningAudit = $Null
PS C:\Windows\system32> $ErrorAudit = $Null
PS C:\Windows\system32> $EventSource = “Check-DFSR Script”
PS C:\Windows\system32> $SuccessEventID = 9500
PS C:\Windows\system32> $WarningEventID = 9501
PS C:\Windows\system32> $ErrorEventID = 9502
PS C:\Windows\system32> $NoPingEventID = 9503
PS C:\Windows\system32>
PS C:\Windows\system32> foreach ($Group in $RGroups)
>> {
>> ## Cycle through all Replication groups found
>> $DFSRGFoldersWMIQuery = “SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID=’” + $Group.Replicat
ionGroupGUID + “‘”
>> $RGFolders = Get-WmiObject -Namespace “root\MicrosoftDFS” -Query $DFSRGFoldersWMIQuery
>>
>> ## Grab all connections associated with a Replication Group
>> $DFSRConnectionWMIQuery = “SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID=’” + $Group.ReplicationG
roupGUID + “‘”
>> $RGConnections = Get-WmiObject -Namespace “root\MicrosoftDFS” -Query $DFSRConnectionWMIQuery
>> foreach ($Connection in $RGConnections)
>> {
>>
>> $ConnectionName = $Connection.PartnerName.Trim()
>> $IsInBound = $Connection.Inbound
>> $IsEnabled = $Connection.Enabled
>>
>> ## Do not attempt to look at connections that are Disabled
>> if ($IsEnabled -eq $True)
>> {
>> ## If the connection is not ping-able, do not attempt to query it for Backlog info
>> $Reply = $ping.send(“$ConnectionName”)
>> if ($reply.Status -eq “Success”)
>> {
>>
>>
>> ## Cycle through the Replication Folders that are part of the replication group and run DFSRDIAG tool
to determine the backlog on the connection partners.
>> foreach ($Folder in $RGFolders)
>> {
>> $RGName = $Group.ReplicationGroupName
>> $RFName = $Folder.ReplicatedFolderName
>>
>> ## Determine if current connect is an inbound connection or not, set send/receive members accordi
ngly
>> if ($IsInBound -eq $True)
>> {
>> $SendingMember = $ConnectionName
>> $ReceivingMember = $ComputerName
>> }
>> else
>> {
>> $SendingMember = $ComputerName
>> $ReceivingMember = $ConnectionName
>> }
>> $Out = $RGName + “:” + $RFName + ” – S:”+$SendingMember + ” R:” + $ReceivingMember
>> Write-Host $Out
>> ## Execute the dfsrdiag command and get results back in the $Backlog variable
>> $BLCommand = “dfsrdiag Backlog /RGName:’” + $RGName + “‘ /RFName:’” + $RFName + “‘ /SendingMe
mber:” + $SendingMember + ” /ReceivingMember:” + $ReceivingMember
>> $Backlog = Invoke-Expression -Command $BLCommand
>>
>> $BackLogFilecount = 0
>> foreach ($item in $Backlog)
>> {
>> if ($item -ilike “*Backlog File count*”)
>> {
>> $BacklogFileCount = [int]$Item.Split(“:”)[1].Trim()
>> }
>>
>> }
>>
>>
>> if ($BacklogFileCount -eq 0)
>> {
>> #Update Success Audit
>> $SuccessAudit += $RGName + “:” + $RFName + ” is in sync with 0 files in the backlog from
“+ $SendingMember + ” to ” + $ReceivingMember +”.`n”
>>
>> }
>> elseif ($BacklogFilecount -lt $BacklogErrorLevel)
>> {
>> #Update Warning Audit
>> $WarningAudit += $RGName + “:” + $RFName + ” has ” + $BacklogFileCount + ” files in the b
acklog from ” + $SendingMember + ” to ” + $ReceivingMember + “.`n”
>> }
>> else
>> {
>> #Update Error Audit
>> $ErrorAudit += $RGName + “:” + $RFName + ” has ” + $BacklogFilecount + ” files in the bac
klog from ” + $SendingMember + ” to ” + $ReceivingMember + “.`n”
>> }
>> #Write-Host + $Folder.ReplicatedFolderName “- ” $BackLogFilecount -foregroundcolor $FGColor
>> }
>> }
>> else
>> {
>> Write-Host $ConnectionName “is not pingable”
>> $NoPingMessage = “Server “”" + $ConnectionName + “”" could not be reached.`nPlease verify it is on th
e network and pingable.”
>> Write-Event $EventSource $NoPingEventID “Warning” $NoPingMessage “Application”
>> }
>> }
>>
>> }
>>
>> }
>> ## Write my events to the local Application log.
>>
Domain System Volume:SYSVOL Share – S:MYDC05 R:MYDC01
The term ‘dfsrdiag’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC05 /ReceivingMember:M
VDC01
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC04 R:MYDC01
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC04 /ReceivingMember:M
VDC01
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC02 R:MYDC01
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC02 /ReceivingMember:M
VDC01
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC03 R:MYDC01
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC03 /ReceivingMember:M
VDC01
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC01 R:MYDC02
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC01 /ReceivingMember:MY
DC02
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC01 R:MYDC03
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC01 /ReceivingMember:J
VDC02
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC01 R:MYDC04
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<<< Backlog /RGName:'Domain System Volume' /RFName:'SYSVOL Share' /SendingMember:MYDC01 /ReceivingMember:E
VDC01
+ CategoryInfo : ObjectNotFound: (dfsrdiag:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Domain System Volume:SYSVOL Share – S:MYDC01 R:MYDC05
The term 'dfsrdiag' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:9
+ dfsrdiag <<< if ($SuccessAudit -ne $Null)
>> {
>> Write-Event $EventSource $SuccessEventID “Information” $SuccessAudit “Application”
>> }
>>
PS C:\Windows\system32> if ($WarningAudit -ne $Null)
>> {
>> Write-Event $EventSource $WarningEventID “Warning” $WarningAudit “Application”
>> }
>>
PS C:\Windows\system32> if ($ErrorAudit -ne $Null)
>> {
>> Write-Event $EventSource $ErrorEventID “Error” $ErrorAudit “Application”
>>
>>
Thanks for replying.
First thing I notice is the piece about:
“The term ‘dfsrdiag’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the sp
elling of the name, or if a path was included, verify that the path is correct and try again.”
This script actually uses the dfsrdiag.exe application to determine backlog.
So, it looks like you are running this on a Domain Controller since it is detecting the SYSVOL shares. What troubles me is that:
1. dfsrdiag.exe is not in the path (or even on the system)
2. the DFSR groups you created aren’t showing up when querying the WMI provider.
Can you verify that the DFS Replication feature is enabled on the Domain Controller (Under File Service Role)?
When the DFS Replication feature is installed, the dfsrdiag.exe should show up in the path.
Also, make sure that the Replication Group configuration has the domain controller as one of the members.
If not, then should log into one of the members of the replication group, make sure you can run dfsrdiag.exe from a command line, and then try the script.
Let me know what you find out. I would love to assist further, if possible.
Thanks,
— Mark
that did it Mark, thanks a million! the problem is my lack of full understanding of DFS-R
, we have win2k8 R2 domain based DFS and i thought we should run all dfs commands from a DC. however the members were file servers so this makes sense now. its working great now, and thanks for sharing this will help tremendously!
How do most use this script, do they setup in the task scheduler or something different?
@Tom
I have typically done this as a scheduled task that run once a week.
I then had my monitoring tool would pick and alert on the appropriate event log entries.
Glad you were able to get this working!!
Please let me know if you have any other questions or problems.
Thanks,
— Mark
There is a problem with this script. It can positively report that the backlog is zero on replication pairs where there is an issue with DFS replication. For instance the DFS service is down on the sender. If you were to run the DFSRDIAG Backlog command from the PowerShell you would get a different error rather than an actual backlog number. This script reports that as a backlog of zero.
I will have to take a look and see why that isn’t being handled appropriately. Do you have an example of what the DFSRDIAG command returns if you run it as you describe?
I think I may have found the issue. It is because I set a “default” value for $BacklogFileCount = 0.
I am not in front of my lab right now, but you could try initializing it to $NULL:
$Backlog = Invoke-Expression -Command $BLCommand
$BackLogFilecount = $NULL
foreach ($item in $Backlog)
…
…
and see if that accurate reports the information.
Please let me know if that helps.
— Mark