dfsrdiag is the operational and diagnostic command line tool that ships with DFS Replication, and its dfsrdiag backlog subcommand answers one question: how many file updates does one member still owe another. On a domain controller that question is really about sysvol, because sysvol replicates over DFSR, and a Group Policy edit that never leaves the domain controller that made it is a backlog nobody looked at.
The number matters more than the file names. A backlog of four on a Monday morning is ordinary latency; the same four still sitting there an hour later is not, and sixty thousand after a restore is a different problem again. Two tools report it, dfsrdiag backlog at a CMD prompt and Get-DfsrBacklog in PowerShell, and they do not agree about where the number lives.
dfsrdiag has no reference page on Microsoft Learn. It is absent from the Windows Commands A to Z index and its URL returns a 404. The PowerShell side is documented, but every DFSR reference page cited here carries the same ms.date of 12/20/2016, and the one-liner those pages hand you for reading the count returns a string, compares wrongly against a threshold, and reports only the first replicated folder it happens to see. What follows is five boundaries, each measured rather than asserted, and a Get-DfsrBacklog sweep that covers every direction.
Applies to: Windows Server 2019 / 2022 / 2025, the three monikers the DFSR reference pages are published under.
Quick answer
On a domain controller this is the pair that answers “is sysvol behind, and by how much”. The PowerShell form asks for the count in the verbose stream, because the object output stops at 100 files. The CMD form prints the count on its first line.
# Get-DfsrBacklog caps its object output at 100 files, so the count has to come out
# of the verbose stream. 4>&1 merges that stream into the output, which already holds
# file records, so keep only the verbose ones or the parse below hits a null Message.
$v = Get-DfsrBacklog -GroupName 'Domain System Volume' -FolderName 'SYSVOL Share' `
-SourceComputerName DC01 -DestinationComputerName DC03 -Verbose 4>&1 |
Where-Object { $_ -is [System.Management.Automation.VerboseRecord] }
# Anchor the parse to the end of the line so nothing in the folder name shifts the field.
foreach ($m in @($v.Message)) {
if ($m -match 'Replicated folder: "(?<rf>[^"]+)"\. Count: (?<n>\d+)\s*$') {
'{0,-16}{1}' -f $Matches['rf'], [int]$Matches['n']
}
}
The CMD equivalent needs no parsing at all when you only want to read it yourself. Both names contain a space, so both are quoted.
rem Typed at a CMD prompt. dfsrdiag prints the count itself, above the file list.
dfsrdiag backlog /rgname:"Domain System Volume" /rfname:"SYSVOL Share" /sendingmember:DC01 /receivingmember:DC03
Get-DfsrBacklog reference page says it plainly: “This is not necessarily an indication of problems. A backlog indicates latency, and a backlog may be expected in your environment”. Read the number twice, ten minutes apart, before deciding anything.
Before the first example
Four things have to be true before any command below returns a number. Each one gets its own block so you can run them in order.
1. An elevated prompt on a member of the replication group. Microsoft’s own sysvol procedure calls for an elevated command prompt, and the backlog query reads the same service.
rem A High Mandatory Level group in the token means the prompt is elevated.
whoami /groups | findstr /c:"S-1-16-12288"
rem The backlog query talks to this service. Stopped means every answer below is empty.
sc query DFSR
2. dfsrdiag.exe on the machine. The archived Microsoft post on slow DFSR replication states where it comes from: Dfsrdiag is installed when you install DFSR on the server. On a domain controller that is already true.
rem where resolves a name against PATH, so an empty result means the tool is absent.
where dfsrdiag
where dfsrmig
3. The replication group and replicated folder names. On a domain controller they are Domain System Volume and SYSVOL Share. The first is hidden from the cmdlet that lists groups unless you ask for it, which is Boundary 2 below.
# -IncludeSysvol is what makes this cmdlet return the group every DC already has.
Get-DfsReplicationGroup -GroupName * -IncludeSysvol | Format-Table GroupName, State
# Membership names the members, the folder and where its content actually sits on disk.
Get-DfsrMembership -GroupName 'Domain System Volume' |
Format-Table ComputerName, FolderName, ContentPath, State
4. One helper function. Every example after this one calls it. It does three jobs that the documented one-liner does not: it keeps only the verbose records, it anchors the parse, and it turns the raw number into a bucket so a report can be compared against a baseline without every row differing on every run.
function Get-BacklogRow {
[CmdletBinding()]
param (
[Parameter(Mandatory)] [string] $From,
[Parameter(Mandatory)] [string] $To,
[string] $GroupName = 'Domain System Volume',
[string] $FolderName = 'SYSVOL Share',
[int] $Threshold = 100
)
# 4>&1 merges the verbose stream into the output stream, which already holds up to
# 100 file records. Those records have no Message, so filter before parsing.
$records = Get-DfsrBacklog -GroupName $GroupName -FolderName $FolderName `
-SourceComputerName $From -DestinationComputerName $To -Verbose 4>&1 |
Where-Object { $_ -is [System.Management.Automation.VerboseRecord] }
$rows = foreach ($m in @($records.Message)) {
if ($m -match 'Replicated folder: "(?<rf>[^"]+)"\. Count: (?<n>\d+)\s*$') {
$n = [int]$Matches['n']
[pscustomobject]@{
From = $From
To = $To
Folder = $Matches['rf']
Backlog = $n
State = if ($n -eq 0) { 'clear' } elseif ($n -le $Threshold) { 'latency' } else { 'backlog' }
}
}
}
# No verbose record is not the same as no backlog, so say which one it was.
if ($rows) { $rows }
else {
[pscustomobject]@{ From = $From; To = $To; Folder = '-'; Backlog = -1; State = 'no record' }
}
}
Get-DfsrBacklog and dfsrdiag both run only on Windows, so no output in this article was captured from either of them. Every output block below is a measurement run: the same parsing, bucketing and comparison code, running on PowerShell 7.4.6 with a lab fixture in place of the service. Where the shape of real tool output matters, the article says which Microsoft page publishes it.
Example 1: ask one direction about one pair
The problem: a Group Policy change made on DC01 has not appeared on DC03, and the Group Policy side of the investigation has come up clean.
The solution: query the pair in the direction the change has to travel, and read the bucket rather than the number.
# From DC01 to DC03: what DC01 holds that DC03 has not applied yet. Swapping the two
# names is a different question, not a second opinion on the same one.
Get-BacklogRow -From DC01 -To DC03 | Format-Table -AutoSize
One row comes back per replicated folder, carrying Backlog and State. State is the column worth alerting on, because the raw number moves on a busy pair between one reading and the next and a threshold on it produces noise. A no record row means DFSR reported nothing for that direction, which is not the same statement as a count of zero.
Example 2: the count, not the first hundred files
The problem: a monitoring script alerts when the sysvol backlog goes over 500 files. It has never fired, including on the morning a domain controller came back from a restore tens of thousands of files behind.
The solution: the object output cannot reach 500. The reference page states the cap in one sentence: “The maximum number of files that this command displays is 100.” Its own example descriptions settle whether that cap sits on the display or on the objects, because each one says the command “retrieves the first 100 unreplicated changes”. Any threshold above 100 is unreachable through the objects, and the accurate number is in the verbose stream.
# Wrong: the object count saturates at 100, so this comparison can never be true.
(Get-DfsrBacklog -GroupName 'Domain System Volume' -FolderName 'SYSVOL Share' `
-SourceComputerName DC01 -DestinationComputerName DC03).Count -gt 500
# Right: the helper reads the count out of the verbose stream, where no cap applies.
# The number is called Backlog and not Count, for the reason measured below.
(Get-BacklogRow -From DC01 -To DC03).Backlog -gt 500
The table below follows from that one documented sentence. Seven realistic backlog sizes, the number of objects each one can produce, and what a threshold of 500 concludes from each column.
real objects .Count -gt 500 verbose n -gt 500
---- ------- -------------- -----------------
0 0 False False
7 7 False False
99 99 False False
100 100 False False
101 100 False False
2400 100 False True
50000 100 False True
rows the real count alerts on 2
rows .Count alerts on 0
No threshold above 100 can ever be crossed by the object count, so a check
written against .Count stays silent at every size that matters.
.Count stays silent at every size that matters, and it looks correct in review because it works perfectly for a backlog of seven.
The helper calls its number Backlog and not Count for a related reason, and it is worth seeing before you rename it back. PowerShell gives every array and every scalar a Count of its own, so a property with that name is read correctly for as long as the pipeline returns exactly one bare object and silently stops being read the moment it does not.
expression .Count .Backlog what .Count returned
---------- ------ -------- --------------------
$a = OneRow 2400 2400 the property
(OneRow) 2400 2400 the property
@(OneRow) 1 2400 the array length
$b = TwoRows 2 17,2400 the array length
threshold on .Count with two rows False
threshold on the real maximum True
One row answers with the property and looks correct. Two rows, or one @() around
the call, answer with the row count, and a threshold check reads 2 rather than
2400 and reports nothing wrong.
@(), or add a second folder, and the same expression starts returning the number of rows.
Example 3: tell a draining backlog from a stuck one
The problem: the backlog from DC01 to DC03 reads 61192 and nobody can say whether that is a server catching up after maintenance or a server that stopped.
The solution: Get-DfsrState reports what is in flight right now, and two backlog readings ten minutes apart report the direction of travel. Neither answer is available from a single backlog number.
# Get-DfsrState returns both inbound and outbound updates, so the Inbound column is
# what tells you which direction each update belongs to.
Get-DfsrState -ComputerName DC03 |
Format-Table FileName, UpdateState, Inbound, SourceComputerName -AutoSize
# The only question a single reading cannot answer: is the number going down.
$first = (Get-BacklogRow -From DC01 -To DC03).Backlog
Start-Sleep -Seconds 600
$second = (Get-BacklogRow -From DC01 -To DC03).Backlog
'{0,-12}{1}' -f 'first', $first
'{0,-12}{1}' -f 'second', $second
'{0,-12}{1}' -f 'draining', ($second -lt $first)
The Get-DfsrState reference page describes the output as files currently replicating and files immediately queued to replicate next, and its own example shows UpdateState holding Scheduled for queued files and Downloading for files in flight. A large backlog with entries in Downloading is draining. A large backlog with nothing in flight is not.
UpdateState is a column seen in an example rather than a documented member. Confirm the shape on your own machine with Get-DfsrState | Select-Object -First 1 | Format-List * before a script depends on it.
Example 4: make the service re-read its configuration
The problem: something changed in Active Directory, the change has replicated between domain controllers, and DFSR is still behaving as though it had not.
The solution: force the full poll instead of waiting for it. The Update-DfsrConfigurationFromAD reference page gives both intervals: “By default, the DFS Replication service queries domain controllers every five minutes by using a lightweight check for membership configuration changes in AD DS” and “By default, the DFS Replication service performs a full poll every hour.” The five minute interval is the lightweight check and the hourly one is the full poll, and only the second reloads the whole configuration.
# Without -Verbose this cmdlet prints nothing at all, which reads as a failure.
# Its documented output type is None, so the verbose stream is the only confirmation.
Update-DfsrConfigurationFromAD -ComputerName DC01, DC03 -Verbose
The page is explicit about the silence: “To return a response, use the Verbose parameter.” The CMD equivalent is dfsrdiag pollad, which is the exact line Microsoft’s sysvol procedure calls for at each of its steps.
Example 5: every direction, diffed against a baseline
The problem: three domain controllers means six directions to check, and the pair you suspect is one of the six.
The solution: sweep every ordered pair into one table, keep a baseline from a quiet moment, and compare the buckets rather than the counts. This is the last example because it is the one worth keeping.
# Every ordered pair, skipping the self-pair: a member has no backlog against itself
# and asking for one wastes a query per member on every run.
$dcs = 'DC01', 'DC02', 'DC03'
$report = foreach ($a in $dcs) {
foreach ($b in $dcs) {
if ($a -eq $b) { continue }
Get-BacklogRow -From $a -To $b
}
}
$report | Format-Table From, To, Folder, Backlog, State -AutoSize
Take the baseline once, when you believe replication is healthy, and keep the file. Comparing on State rather than on Backlog is what stops the diff reporting every row on every run, because a busy pair rarely holds the same count twice.
New-Item -ItemType Directory -Path C:\bat -Force | Out-Null
# Take the baseline once, at a quiet time, and keep it under version control if you can.
$report | Export-Clixml C:\bat\dfsr-baseline.xml
# Later, on the same shape of object. Compare the bucket, never the raw count.
$baseline = Import-Clixml C:\bat\dfsr-baseline.xml
Compare-Object $baseline $report -Property From, To, Folder, State
The run below is the code above with a lab fixture in place of the service: six ordered pairs over three domain controllers, one of them deliberately reporting no record at all, against a baseline taken when everything was quiet.
from to folder backlog state
---- -- ------ ------- -----
DC01 DC02 SYSVOL Share 0 clear
DC01 DC03 SYSVOL Share 61192 backlog
DC02 DC01 SYSVOL Share 11 latency
DC02 DC03 SYSVOL Share 2 latency
DC03 DC01 SYSVOL Share 0 clear
DC03 DC02 - -1 no record
ordered pairs queried 6
baseline properties From,To,Folder,Backlog,State
report properties From,To,Folder,Backlog,State
the two shapes match True
from to folder state side
---- -- ------ ----- ----
DC01 DC03 SYSVOL Share backlog =>
DC02 DC03 SYSVOL Share latency =>
DC03 DC02 - no record =>
DC01 DC03 SYSVOL Share clear <=
DC02 DC03 SYSVOL Share clear <=
DC03 DC02 SYSVOL Share clear <=
pairs whose state moved 3
An empty table above is the pass, which reads like a failure the first time.
The same two servers under four different spellings
Three of the four rows below name the same two machines in the same order. The fourth looks as though it does and does not, which is the one that costs an afternoon.
| Command | The first name | The second name | What the pair means |
|---|---|---|---|
dfsrdiag backlog | /sendingmember: | /receivingmember: | direction of replication |
Get-DfsrBacklog | -SourceComputerName | -DestinationComputerName | direction of replication |
| the same cmdlet, by alias | -SMem | -RMem | direction of replication |
Write-DfsrHealthReport | -ReferenceComputerName | -MemberComputerName | a baseline server and everyone else, not a direction |
-ReferenceComputerName looks like it belongs in the same family as -SourceComputerName and it does not: the health report takes one server as the baseline and compares the rest against it. Nothing in that pair says which way data flows.
The Get-DfsrBacklog reference page also documents both short aliases, -SMem for the sending member and -RMem for the receiving one, which is worth knowing when the line is already long enough to need a continuation.
The same check from a CMD prompt
dfsrdiag is a CMD tool and it prints its own count, which makes it the shorter route when a human is reading the answer. The archived Microsoft post on slow DFSR replication publishes a capture and describes the limit in the same breath: it shows “up to the first 100 file names, and also gives an accurate snapshot count”. The count is accurate above 100; the list is not complete above 100.
The shape is a count line followed by a numbered list. The block below carries this article’s server name and plausible sysvol file names in place of the ones in Microsoft’s capture, which is otherwise identical in form:
Member <DC03> Backlog File Count: 12
Backlog File Names (first 12 files)
1. File name: Registry.pol
2. File name: GptTmpl.inf
...
Pulling the number out for a scheduled task is one for /f loop. The count sits in the sixth whitespace-separated token of that first line.
rem Typed at a CMD prompt: ONE percent sign on the loop variable.
rem tokens=6 picks the number out of: Member <DC03> Backlog File Count: 12
for /f "tokens=6" %C in ('dfsrdiag backlog /rgname:"Domain System Volume" /rfname:"SYSVOL Share" /sendingmember:DC01 /receivingmember:DC03 ^| findstr /c:"Backlog File Count"') do @echo %C
The percent sign is the only part of that line that changes when it moves into a file. Microsoft’s for reference states the rule in two sentences: “Use a single percent sign (%) to carry out the for command at the command prompt. Use double percent signs (%%) to carry out the for command within a batch file.”
| Where you are typing it | Loop variable | The same line, shortened |
|---|---|---|
| A CMD prompt | %C | for /f "tokens=6" %C in ('...') do @echo %C |
| A .bat or .cmd file | %%C | for /f "tokens=6" %%C in ('...') do @echo %%C |
The tokenizing is worth checking rather than trusting, and so is what happens when the query covers more than one replicated folder. The run below reimplements the default for /f split and applies it to a one folder capture and a two folder capture.
token value
----- -----
1 Member
2 <DC03>
3 Backlog
4 File
5 Count:
6 12
one folder echoed: 12 a SET keeps only 12
two folders echoed: 12 61192 a SET keeps only 61192
findstr matches one line per replicated folder, so the loop body runs once
per folder. A script that assigns the token to a variable keeps the last
one it saw, which is whichever folder dfsrdiag reported last.
findstr matches one line per folder and the loop body runs once per folder. A script that assigns the token to a variable keeps whichever count DFSR reported last. Name the folder in the query and the problem does not arise.
The CMD side of Example 4 is one word long, and it is the line that appears at four separate steps across Microsoft’s two sysvol synchronisation procedures.
rem Typed at an elevated CMD prompt. Forces a full LDAP poll on the local server.
dfsrdiag pollad
Boundary 1: dfsdiag is not dfsrdiag
One letter separates two tools that serve two different subsystems, and only one of them has a reference page. dfsdiag diagnoses DFS Namespaces: its page opens with “Provides diagnostic information for DFS Namespaces.” and documents five subcommands, each introduced by a forward slash. dfsrdiag diagnoses DFS Replication, takes its subcommand as a bare word, and is not on Microsoft Learn at all.
| Tool | Subsystem | Subcommand form | Reference page on Microsoft Learn |
|---|---|---|---|
dfsdiag | DFS Namespaces | dfsdiag /testdcs | yes, with five subcommands |
dfsrdiag | DFS Replication | dfsrdiag backlog | no |
dfsrmig | sysvol migration from FRS to DFSR | dfsrmig /getmigrationstate | yes |
Two checks agree on the missing page. The Windows Commands A to Z index lists dfsdiag with its five subcommands and lists dfsrmig, and contains no entry for dfsrdiag; and the URL that would follow the pattern of every other entry returns a 404.
dfsradmin, has no reference page either, and Microsoft’s sysvol procedure rules it out for this job in particular: “You can’t use the DFS Management snap-in (Dfsmgmt.msc) or the Dfsradmin.exe command-line tool to achieve this.” The namespace half of the family is covered separately in the dfsutil and dfsdiag guide.
Boundary 2: the group every domain controller has is hidden by default
Get-DfsReplicationGroup does not return the sysvol replication group unless you ask for it. The -IncludeSysvol parameter says why: “By default, this resource group is not returned as its management is controlled by Active Directory.” So an administrator who runs the cmdlet on a domain controller, sees an empty result and concludes DFSR is not replicating anything has read the output correctly and drawn the wrong conclusion.
Of the thirteen DFSR reference pages checked for this article, -IncludeSysvol appears on exactly one of them. Nothing on the Get-DfsrBacklog page says whether its wildcard covers sysvol, so naming the group is the only spelling that is not in doubt.
Both names contain a space, which means both are always quoted. The failure when they are not is worth seeing, because the error message names a word out of the group name and sends people looking for a problem with something else entirely. The run below declares a stand-in with the four documented parameters at their documented positions and reports what each one received.
quoted, which is correct:
GroupName [Domain System Volume]
FolderName [SYSVOL Share]
SourceComputerName [DC01]
DestinationComputerName [DC03]
unquoted, the same four names:
binding failed ParameterBindingException
message A positional parameter cannot be found that accepts argument 'System'.
Boundary 3: a backlog has a direction
The Get-DfsrBacklog page defines the measurement in one sentence: “Any files or folders listed in the DFS Replication backlog have not yet replicated from the source computer to the destination computer.” That is one direction between two members. Neither tool defaults to both ways, and a clean answer one way says nothing at all about the other.
So the unit of work is the ordered pair, not the member and not the connection. The run below counts them, and counts the self-queries a nested loop makes when nobody guards against them.
members naive NxN ordered self one way
------- --------- ------- ---- --------
2 4 2 2 1
3 9 6 3 3
4 16 12 4 6
8 64 56 8 28
12 144 132 12 66
The nested loop with no guard asks every member for its backlog against itself:
one wasted query per member, every run.
Stopping at one direction per pair halves the queries and hides half the paths,
because a member that is behind inbound can be clean outbound.
Boundary 4: the documented parse returns a string, and only one folder
The Get-DfsrBacklog page gives a one-liner for turning the verbose count into something a script can use. It splits the message on colons and takes the third field. The field it picks is the right one. What comes back is the wrong type, and depending on the shape of the output it is also the wrong folder or no answer at all.
First, the type. The split leaves the leading space in place, so the result is a string and every comparison against a threshold becomes a string comparison. The run below asks a backlog of 2400 two questions and gets both of them wrong, in opposite directions.
documented parse returns [ 2400]
its type is String
its length is 5
equals the number 2400 False
a monitoring script asks two questions about a backlog of 2400:
is it over 100 False should be True
is it under 500 True should be False
cast to int gives 2400
is it over 100 True should be True
is it under 500 False should be False
Second, the scope. Leave -FolderName out and the cmdlet reports every replicated folder it finds, so the verbose stream carries one record per folder. Calling a method across that array runs it on every element and returns one flat list, so the index that meant the third field of one message still lands inside the first message and quietly discards the rest. Add the file records that 4>&1 merges into the same array and the expression stops working altogether.
records parts Split[2] first folder in the stream
------- ----- -------- --------------------------
1 3 [ 2400] RF01
2 6 [ 2400] RF01
3 9 [ 17] SYSVOL Share
Split runs on every message and the results arrive as one flat list, so [2]
always lands inside the FIRST message. Row 3 reports 17 and never mentions
the folder that is 2400 behind.
array length with 4>&1 4
how many carry a Message 1
Split[2] on that array You cannot call a method on a null-valued expression.
records what the anchored parse returns
------- -------------------------------
1 RF01=2400
2 RF01=2400, SYSVOL Share=17
3 SYSVOL Share=17, RF01=2400, RF03=9
Both faults have the same two-line fix, and both lines are in the helper from the prerequisites: filter to VerboseRecord before touching .Message, and anchor the pattern to the end of the line so the folder name and the count stay together.
Boundary 5: a full poll does not move a single file
dfsrdiag pollad and dfsrdiag syncnow are the two commands that get confused with each other when replication looks stuck, and they do different jobs. The poll makes the service re-read its configuration from Active Directory. The sync overrides the schedule so that data can actually move.
The Sync-DfsReplicationGroup page states the trade: “Use this cmdlet to alter the schedule temporarily to allow replication, because this cmdlet does not require Active Directory replication and LDAP polling.” When the schedule is closed that is the shorter path, because it needs neither the AD replication nor the LDAP poll that the other route waits on.
# Ignore the replication schedule from DC01 to DC03 for fifteen minutes. This is the
# cmdlet form of dfsrdiag syncnow and it needs no AD replication and no LDAP poll.
Sync-DfsReplicationGroup -GroupName 'Domain System Volume' `
-SourceComputerName DC01 -DestinationComputerName DC03 -DurationInMinutes 15
The one place the poll is the operative step is sysvol recovery, and there it is doing exactly its documented job: making the service notice an attribute somebody changed in Active Directory. FRS had D2 and D4 values on a Bur Flags registry value for this; the sysvol procedure page opens by saying those values “don’t exist for the Distributed File System Replication (DFSR) service”, and that “sysvol replication is intentionally protected from any editing through its management interfaces to prevent accidents”. Confirmation is entirely event driven.
| Event ID in the DFSR log | What the procedure says it means | When it appears |
|---|---|---|
4114 | sysvol replication is no longer being replicated | after msDFSR-Enabled is set to FALSE |
4614 and 4604 | sysvol replication has been initialized | after the non-authoritative poll, the D2 equivalent |
4602 | sysvol replication has been initialized | after the authoritative poll, the D4 equivalent |
Reading those four IDs out of the log is a Get-WinEvent filter rather than a scroll through Event Viewer, and the log to open is the one named DFS Replication. There is a separate guide on filtering event logs with Get-WinEvent.
# The DFSR log is small, so an ID filter is enough. 4114 means a folder went offline,
# 4602, 4604 and 4614 are the initialised messages the procedure tells you to expect.
Get-WinEvent -FilterHashtable @{ LogName = 'DFS Replication'; Id = 4114, 4602, 4604, 4614 } |
Select-Object TimeCreated, Id, Message -First 10
What the reference pages do not say
The documentation for this corner of Windows Server has an age to it, and knowing where the gaps are saves an afternoon of assuming you misread something.
- There is no
dfsrdiagpage. It is missing from the Windows Commands A to Z index, which does listdfsdiaganddfsrmig, and the URL that would match every other entry returns a 404. The subcommand names come off the tool’s own help text, which is why this article only names the ones a Microsoft page uses in an example. - Every one of the thirteen DFSR reference pages checked for this article carries
ms.date: 12/20/2016. Eight of them are linked below; the other five areGet-DfsReplicatedFolder,Get-DfsrPreservedFiles,Get-DfsrConnection,Get-DfsrMemberandSuspend-DfsReplicationGroup. The pages are published under the 2019, 2022 and 2025 monikers, and forGet-DfsrBacklog,Update-DfsrConfigurationFromADandGet-DfsrStatethe 2019 and 2025 copies are identical apart from the version inside the online help link. - The description on the
Get-DfsrBacklogpage misspells its own cmdlet asGet-DfrsBacklog, in all three monikers. - The output type is named,
Microsoft.DistributedFileSystemReplication.DfsrIdRecord, and not one of its properties is listed. The verbose message this whole article parses is documented only by appearing inside an example, which is why the parse here is anchored rather than positional. - A handful of parameters are marked as not accepting wildcards on the 2019 pages and as accepting them on the 2025 pages, with both copies stamped the same day. Treat that as a docs regeneration rather than a product change, and confirm on the machine you are standing at.
When the properties matter, the machine is the reference. One object and Format-List * settles it.
# The reference page names the output type and lists none of its properties.
Get-DfsrBacklog -GroupName 'Domain System Volume' -FolderName 'SYSVOL Share' `
-SourceComputerName DC01 -DestinationComputerName DC03 |
Select-Object -First 1 | Format-List *
Hidden gems
- The health report does not count files unless you ask.
-CountFilessays so in the parameter description: “By default, the cmdlet does not count files, in order to save time while generating a report.” A report generated without it tells you about state and nothing about volume. -GroupNameand-FolderNametake wildcards, and that is the case that breaks the documented parse.-FolderName *reports every folder in one call, which is convenient right up to the moment something reads only the first record. The helper handles it; the one-liner does not.$Matchessurvives a failed match. A pattern that does not match leaves the previous match’s captures in place, so a loop over several messages can read the previous line’s captures for a line that never matched. Read$Matchesinside theifthat tested the match, never after it.Get-DfsrFileHashis DFSR’s own hash, not a general purpose one. The page says the value is “identical to the one computed by the Distributed File System (DFS) Replication service” and names no algorithm, so compare it only against anotherGet-DfsrFileHashresult. A checksum from any other tool will not agree with it.-SMemand-RMemshorten a line that already needs a continuation. Both are documented aliases, and on a four parameter call with two quoted names they are the difference between one line and two.- Never call an object property
Count. Example 2 measures it: a single bare object answers with your property, and an array or an@()wrapper answers with the number of rows. The bug appears the day a second replicated folder joins the group.
The third gem is the one that quietly corrupts a report, so it is worth a run of its own. Three messages, one of which matches nothing, read once inside the if and once after it.
line matched read inside if read after the if
---- ------- -------------- -----------------
1 True SYSVOL Share=17 SYSVOL Share=17
2 False not read SYSVOL Share=17
3 True RF01=2400 RF01=2400
Line 2 matched nothing and the column on the right still reports line 1, because
a failed match leaves the previous captures in place instead of clearing them.
Where this matters
- A Group Policy change that reached some clients and not others. The policy is correct,
gpresultshows it applied at one site and missing at another, and the backlog from the domain controller that made the edit is the number that explains it. - A domain controller back from a restore. Its inbound backlog is enormous and its outbound backlog is empty, which is why one direction per pair is not enough.
- A monitoring check that has never fired. Written against the object count, it cannot cross any threshold above 100, and it passes review because it behaves correctly on a small backlog.
- A logon script that exists on one domain controller only. sysvol is a replicated folder like any other, and the backlog is reported the same way, once the group name is spelled in full.
- A closed replication schedule during a maintenance window. A full poll changes nothing; overriding the schedule for a fixed number of minutes is the command that does.
- A sysvol recovery that went half done. Setting one domain controller authoritative without making the others non-authoritative produces conflicts, and the four DFSR event IDs are what tell you which stage each server reached.
Tips and limitations
- Run both from an elevated prompt. Microsoft’s sysvol procedure calls for one, and the DFSR service has to be running on both members either way.
- The object output of
Get-DfsrBacklogstops at 100 files. The count in its verbose stream does not, anddfsrdiag backlogprints an accurate count above 100 as well. - Quote
Domain System VolumeandSYSVOL Shareeverywhere. Both contain a space and the binding error names a word from inside the group name. - A backlog number on its own is not a verdict. Two readings, or one reading plus
Get-DfsrState, are. - Compare a sweep against a baseline on a bucket, not on a raw count, or every row differs on every run and the report stops being read.
- sysvol cannot be edited through the DFS Management snap-in or
dfsradmin, by design. The only documented route is the attribute and poll procedure, and it is worth reading in full before starting. - Everything here is read-only except three things:
Sync-DfsReplicationGroupalters the schedule for a fixed number of minutes,Update-DfsrConfigurationFromADforces a poll, and Example 5 writes its baseline toC:\bat.
Official documentation
- Get-DfsrBacklog: DFSR | Microsoft Learn
- Update-DfsrConfigurationFromAD: DFSR | Microsoft Learn
- Get-DfsrState: DFSR | Microsoft Learn
- Sync-DfsReplicationGroup: DFSR | Microsoft Learn
- Get-DfsReplicationGroup: DFSR | Microsoft Learn
- Get-DfsrMembership: DFSR | Microsoft Learn
- Write-DfsrHealthReport: DFSR | Microsoft Learn
- Get-DfsrFileHash: DFSR | Microsoft Learn
- DFSR Module | Microsoft Learn
- How to force authoritative and non-authoritative synchronization for DFSR-replicated sysvol replication | Microsoft Learn
- Windows commands A to Z index | Microsoft Learn
- dfsdiag: Windows Commands | Microsoft Learn
- dfsrmig: Windows Commands | Microsoft Learn
- for: Windows Commands | Microsoft Learn
- Top 10 Common Causes of Slow Replication with DFSR | Microsoft Learn archive
Related tools
- Event Log Analyzer: the sysvol procedure is confirmed entirely through DFSR event IDs 4114, 4602, 4604 and 4614, and this is where you paste them.
Related guides
- Migrating SYSVOL from FRS to DFSR with dfsrmig: the migration that created the replication group this article queries.
- DFS Namespaces from the command line with dfsutil and dfsdiag: the namespace half of the family, and the tool one letter away from this one.
- Checking Active Directory replication with repadmin: the sysvol procedure depends on an AD change reaching every domain controller first.
- Active Directory health checks with dcdiag: the wider domain controller checks that sit either side of a sysvol problem.
- Reading Windows event logs with Get-WinEvent: how to filter the DFS Replication log for the four IDs in Boundary 5.
- Group Policy troubleshooting cheat sheet: the symptom that most often brings people to a sysvol backlog in the first place.
- Active Directory troubleshooting cheat sheet: the one page version of the checks around this one.
Five cheat sheets, one PDF
Subnet masks, PowerShell, Linux commands, HTTP status codes and the ESXi command line - one page each, free to keep. Leave an address and it arrives in a minute.