<?xml version="1.0"?>
<rss version="2.0"><channel><title><![CDATA[Windows Server & Active Directory Latest Topics]]></title><link>https://wtmsp.com/forum/9-windows-server-active-directory/</link><description><![CDATA[Windows Server & Active Directory Latest Topics]]></description><language>en</language><item><title>Help desk password resets without Domain Admin, plus a klist trick for computer groups</title><link>https://wtmsp.com/topic/13-help-desk-password-resets-without-domain-admin-plus-a-klist-trick-for-computer-groups/</link><description><![CDATA[<p>Our help desk resets passwords and unlocks accounts all day long. When we take over a small or mid-sized domain, the most common over-privilege I find is the help desk (or the office manager who does it on the side) sitting in Domain Admins just so they can do that. AD has had granular delegation since Windows 2000, and it takes a few minutes to set up.</p>
<p>Further down is a related trick I use from the RMM a lot: getting a machine, and scripts running as SYSTEM on it, to pick up a new group membership without rebooting someone's PC in the middle of their day.</p>
<h2>Delegating resets and unlocks</h2>
<p>You'll need Domain Admin once to set it up, users organised into OUs so you can scope it, and a security group for the people getting the rights, for example <code>GRP-Helpdesk-PwReset</code>. Always delegate to a group, never to individuals. When someone joins or leaves the help desk you change group membership, not ACLs.</p>
<ol>
<li>In Active Directory Users and Computers, right-click the OU containing the users (for example <code>OU=Staff,DC=contoso,DC=local</code>) and choose <strong>Delegate Control</strong>.</li>
<li>Add <code>GRP-Helpdesk-PwReset</code>.</li>
<li>Under common tasks, tick <strong>Reset user passwords and force password change at next logon</strong>.</li>
<li>Finish the wizard.</li>
</ol>
<p>That common task doesn't include unlocking, which catches people out. Run the wizard again on the same OU, choose <strong>Create a custom task to delegate</strong>, then <em>Only the following objects in the folder</em>, tick <strong>User objects</strong>, and on the permissions page show <em>Property-specific</em> permissions and tick <strong>Read lockoutTime</strong> and <strong>Write lockoutTime</strong>.</p>
<p>If you're setting this up across a lot of OUs or clients, I'd script it with <code>dsacls</code> instead:</p>
<pre class="ipsCode" data-language="powershell">$ou  = "OU=Staff,DC=contoso,DC=local"
$grp = "CONTOSO\GRP-Helpdesk-PwReset"

dsacls $ou /I:S /G "${grp}:CA;Reset Password;user"
dsacls $ou /I:S /G "${grp}:RPWP;pwdLastSet;user"
dsacls $ou /I:S /G "${grp}:RPWP;lockoutTime;user"</pre>
<p><code>/I:S</code> applies the entry to child objects only, <code>CA</code> is a control access right (Reset Password), and <code>RPWP</code> is read and write property.</p>
<p>The help desk can then use ADUC from RSAT, or PowerShell:</p>
<pre class="ipsCode" data-language="powershell">Set-ADAccountPassword -Identity jdoe -Reset -NewPassword (Read-Host -AsSecureString "New password")
Set-ADUser -Identity jdoe -ChangePasswordAtLogon $true
Unlock-ADAccount -Identity jdoe</pre>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>Why it won't work on your admins</strong></p></div>
<p>Members of protected groups (Domain Admins, Account Operators and so on) have <code>adminCount=1</code>, and their permissions get reset hourly from the AdminSDHolder object. Your help desk delegation won't apply to them, by design. Honestly, that's what you want. The help desk shouldn't be able to reset a Domain Admin's password.</p>
</div>
<h2>New group membership for SYSTEM, no reboot</h2>
<p>Computer accounts get group memberships too, usually to grant access to a file share, a certificate template or a GPO's security filter. The catch is that a computer gets its Kerberos tickets when it boots and renews them for hours afterwards. Add it to a group and it won't "see" the membership until it gets a new ticket, which normally means a reboot. That's a hard sell when someone is halfway through their work on that machine.</p>
<p>You can force it by purging the tickets for the SYSTEM logon session (LUID <code>0x3e7</code>). The next time anything running as SYSTEM needs a ticket, the machine asks the DC for a fresh TGT, and that one carries the new group.</p>
<p>First add the computer to the group. Note the trailing <code>$</code> on the computer's account name.</p>
<pre class="ipsCode" data-language="powershell">Add-ADGroupMember -Identity "GRP-Deploy-Share-Read" -Members "WS-0142$"</pre>
<p>Make sure the change has replicated to the DC the machine authenticates against (<code>repadmin /syncall /APed</code> if you're in a hurry). Then on the target machine, from an elevated prompt or your RMM, which usually runs as SYSTEM anyway:</p>
<pre class="ipsCode" data-language="powershell">klist -li 0x3e7 purge
gpupdate /force          # if the group is used for GPO security filtering
certutil -pulse          # if the group grants enrollment on a certificate template</pre>
<p>Now the script running as SYSTEM can reach the share or service that's restricted to the group. Access the resource by its DNS name, not its IP address, so Kerberos actually gets used.</p>
<p>If the membership was only for a one-off job, like copying installers from a restricted share or a single enrollment, take the computer back out when it's done and purge again so the access goes away now and not in ten hours:</p>
<pre class="ipsCode" data-language="powershell">Remove-ADGroupMember -Identity "GRP-Deploy-Share-Read" -Members "WS-0142$" -Confirm:$false
# then on WS-0142:
klist -li 0x3e7 purge</pre>
<p>Put the removal in the same script or ticket as the add. We've found computers sitting in "temporary" groups months after the job, because nobody came back for them.</p>
<div class="ipsRichTextBox" data-i-background-color="indigo"><div class="ipsRichTextBox__title"><p><strong>Where the trick stops working</strong></p></div>
<p>Purging tickets refreshes what the machine presents to other servers over Kerberos. It doesn't rebuild the local token of processes already running as SYSTEM, so <code>whoami /groups</code> in an existing SYSTEM session won't change, and neither will local permission checks against the new group. Anything that depends on the local token still needs a reboot.</p>
</div>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>Testing both halves</strong></p></div>
<ul>
<li>Log on as a help desk member (not an admin) and reset a test user's password and unlock them. Try the same on a user outside the OU. It should be denied.</li>
<li>After the purge, <code>klist -li 0x3e7</code> shows a fresh TGT issued a moment ago, and the SYSTEM-context task can read the restricted resource.</li>
</ul>
</div>
<p>I mostly use the purge for remote one-off jobs where a reboot would interrupt someone, for testing GPO filtering or certificate autoenrollment without rebooting each time, and for temporary access during a deployment script. It isn't a substitute for proper standing access. If machines need a group permanently, put them in it and let them pick it up on their next reboot like normal.</p>]]></description><guid isPermaLink="false">13</guid><pubDate>Sun, 18 Oct 2026 20:23:42 +0000</pubDate></item><item><title>Stop binding your VPN to a real person's AD account</title><link>https://wtmsp.com/topic/12-stop-binding-your-vpn-to-a-real-persons-ad-account/</link><description><![CDATA[<p>The VPN, the remote access portal, the copier that does scan-to-email, the wiki, the helpdesk system. Anything that looks people up in AD needs an account to bind with, and in a lot of environments we inherit, that account belongs to an actual person. Usually whoever set it up. It works fine until they change their password at the 90-day prompt, mistype it on their phone and lock themselves out, or leave. Then everybody's logins to that system break at once.</p>
<p>It's messy in quieter ways too. The logs show that person "logging in" thousands of times a day, and because those accounts are often admins, the appliance ends up holding admin credentials. What we do instead is boring on purpose. One dedicated service account per system, minimum rights, a long random password, no interactive logon, and a written rotation process.</p>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>The one we caught right before a handover</strong></p></div>
<p>Before handing a client environment over to another provider, we audited every integration and found the remote access portal binding to AD as one of our own engineers, by name. The day that account got disabled, nobody at the client would have been able to connect remotely. We created a dedicated read-only bind account, tested it with <code>ldapsearch</code>, switched the portal over, confirmed staff could log in, and added it to the handover documentation. Ten minutes of work, and the new team didn't spend their first morning on a remote access outage.</p>
</div>
<p>To do this you'll need rights to create OUs, users and GPOs, a password manager or vault for the generated password, and access to the config of whatever system is going to bind.</p>
<h2>Give service accounts their own OU</h2>
<p>Keeping them out of your normal user OUs means user GPOs, password policies and cleanup scripts don't touch them by accident.</p>
<pre class="ipsCode" data-language="powershell">New-ADOrganizationalUnit -Name "Service Accounts" -Path "OU=Admin,DC=contoso,DC=local" -ProtectedFromAccidentalDeletion $true</pre>
<h2>Create the account</h2>
<p>Generate the password in your password manager first. We go 32 characters or more. Name the account so whoever finds it in two years knows what it's for, and put the owner and runbook in the description.</p>
<pre class="ipsCode" data-language="powershell">$pw = Read-Host "Password for svc-vpn-ldap" -AsSecureString

New-ADUser -Name "svc-vpn-ldap" `
    -SamAccountName "svc-vpn-ldap" `
    -UserPrincipalName "svc-vpn-ldap@contoso.local" `
    -Path "OU=Service Accounts,OU=Admin,DC=contoso,DC=local" `
    -AccountPassword $pw `
    -Enabled $true `
    -PasswordNeverExpires $true `
    -CannotChangePassword $true `
    -Description "LDAP bind for remote access portal. Owner: IT. See runbook SVC-001."</pre>
<p>"Password never expires" is a deliberate trade-off. An expiring password on a service account causes exactly the outage we're trying to avoid. The compensating controls are the long random password and the rotation process further down.</p>
<h2>Keep it to Domain Users</h2>
<p>For read-only lookups (authenticate a user, read their group memberships), plain <strong>Domain Users</strong> membership is enough, since authenticated users can read most user and group attributes by default. Please don't add it to Domain Admins or any admin group "to make it work". If an app genuinely needs to write, like a password self-service tool, delegate that specific permission on the specific OU and nothing else.</p>
<h2>Block interactive logon</h2>
<p>A bind account should never be able to sit at a desktop or open an RDP session. Make a group, something like <code>GRP-Deny-Interactive-Logon</code>, and add the account. Then in a GPO linked at the domain level (or the OUs holding your servers and workstations), go to <em>Computer Configuration, Policies, Windows Settings, Security Settings, Local Policies, User Rights Assignment</em> and add the group to <strong>Deny log on locally</strong> and <strong>Deny log on through Remote Desktop Services</strong>.</p>
<p>Don't add it to <em>Deny access to this computer from the network</em> on your DCs. LDAP binds are network logons, so that breaks the one thing the account exists to do.</p>
<h2>Use TLS, and test before you touch the appliance</h2>
<p>Set the appliance to LDAPS (636) or StartTLS if it supports it. A simple bind over plain 389 sends the password in clear text. Before I change anything on the device, I test the bind from any Linux box with the OpenLDAP client tools:</p>
<pre class="ipsCode" data-language="bash">ldapsearch -H ldaps://dc01.contoso.local -D "svc-vpn-ldap@contoso.local" -W \
  -b "DC=contoso,DC=local" "(sAMAccountName=jdoe)" memberOf</pre>
<p>If that returns the user's groups, the account works. Then update the appliance, test a real user's login, and only then remove the old credentials.</p>
<p>Before you disable the old shared account, watch the DC logs for its logon attempts for a few days. There's always a second device nobody remembered, and in my experience it's usually a scan-to-email printer.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>How to tell it worked</strong></p></div>
<ul>
<li>Users can log in to the system that binds to AD</li>
<li><code>Get-ADUser svc-vpn-ldap -Properties LastLogonTimestamp, PasswordNeverExpires, MemberOf</code> shows recent activity and only Domain Users</li>
<li>Trying to RDP or log on locally as the service account is refused</li>
<li>The old named account no longer shows bind activity in the DC security logs (look for its logons, events 4624 and 4625, from the appliance's IP)</li>
</ul>
</div>
<h2>Write it down so rotation isn't scary</h2>
<p>For each service account we record what uses it and where the credential is entered (device, admin URL, config file), who owns the integration, where the password is stored, and when it was last rotated along with the steps. Rotation then is just generating a new password, updating the vault, setting it in AD, updating each consumer and testing. One account per system keeps that list short, and one rotation can't break five things.</p>
<p>People sometimes ask why not use a gMSA. They're great for Windows services, but the password is retrieved by Windows hosts, so a VPN appliance or printer can't use one. For appliances, a normal user account managed like this is the right tool.</p>]]></description><guid isPermaLink="false">12</guid><pubDate>Sun, 18 Oct 2026 20:22:41 +0000</pubDate></item><item><title>Get the PDC emulator's time right and the rest of the domain follows</title><link>https://wtmsp.com/topic/11-get-the-pdc-emulators-time-right-and-the-rest-of-the-domain-follows/</link><description><![CDATA[<p>Time problems never show up as "the clock is wrong". They show up as a user who randomly can't authenticate, Group Policy that stops applying, or me trying to line up firewall logs against server logs and finding them minutes apart. Kerberos tolerates five minutes of clock skew by default, and past that things get weird fast.</p>
<p>The design is simple once you see it. The DC holding the <strong>PDC emulator</strong> role in the forest root domain syncs to a reliable external NTP source. Every other DC syncs from the PDC emulator, or another DC higher up the hierarchy. Member servers and workstations sync from a DC in their domain, and that part happens on its own for domain-joined machines. So nearly all the work is on the PDC. You'll need admin access to your DCs, outbound UDP 123 from the PDC emulator to the NTP servers you pick, and about fifteen minutes.</p>
<h2>Find the PDC and see what it's doing</h2>
<pre class="ipsCode" data-language="powershell">netdom query pdc
# or
(Get-ADDomain).PDCEmulator</pre>
<p>Then on the PDC emulator:</p>
<pre class="ipsCode" data-language="powershell">w32tm /query /status
w32tm /query /source
w32tm /query /configuration</pre>
<p>Read the <strong>Source</strong> and <strong>Stratum</strong> lines. If Source says <strong>Free-running System Clock</strong>, the server has no time source at all and just trusts its own clock. <strong>Local CMOS Clock</strong> is the same problem, it's reading the hardware clock. <strong>VM IC Time Synchronization Provider</strong> means it's getting time from the Hyper-V host, which I'll come back to.</p>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>The domain that drifted together</strong></p></div>
<p>On one domain we took over, users were hitting intermittent Kerberos failures and the timestamps on firewall and server logs disagreed by several minutes. <code>w32tm /query /source</code> on the PDC came back <strong>Free-running System Clock</strong>. Nobody had ever given it an external source, so it was counting on its own oscillator, and every other machine in the domain was faithfully following it. The fix was exactly the next section, then a resync on the other DCs. The clients corrected themselves over the next few polling cycles.</p>
</div>
<h2>Point the PDC at external NTP</h2>
<pre class="ipsCode" data-language="powershell">w32tm /config /manualpeerlist:"time.nist.gov,0x8 0.pool.ntp.org,0x8 1.pool.ntp.org,0x8" /syncfromflags:manual /reliable:yes /update
net stop w32time
net start w32time
w32tm /resync /rediscover</pre>
<p><code>/manualpeerlist</code> is a space-separated list of peers. The <code>,0x8</code> suffix tells Windows to use client mode with them, which is what public NTP servers expect. <code>/syncfromflags:manual</code> says to use that list instead of the domain hierarchy. <code>/reliable:yes</code> advertises this DC as a reliable time source to the rest of the domain, and <code>/update</code> tells the service to load the new config.</p>
<p>I always list more than one peer, so a single unreachable server doesn't leave you free-running again.</p>
<p>If the status still shows the local clock afterwards, check that UDP 123 is actually getting out. <code>w32tm /stripchart /computer:time.nist.gov</code> timing out is a good sign the firewall is blocking it. And if the PDC is already far off, Windows may refuse to jump the clock because of the maximum correction limits (<em>MaxPosPhaseCorrection</em> and <em>MaxNegPhaseCorrection</em>). Set the time by hand close to correct, then resync.</p>
<h2>Put everyone else back on the hierarchy</h2>
<p>Run this on every other DC, and on any member server someone "fixed" by hand at some point:</p>
<pre class="ipsCode" data-language="powershell">w32tm /config /syncfromflags:domhier /update
net stop w32time
net start w32time
w32tm /resync
w32tm /query /source</pre>
<p>The source should now be a DC name, not an internet server or the local clock.</p>
<h2>Virtual DCs shouldn't trust the host</h2>
<p>A virtual DC shouldn't take its time from the hypervisor. The host's clock is often the thing that's wrong, and then the whole domain is following an unmanaged box nobody ever set up NTP on. On Hyper-V, the cleanest fix that keeps the integration service's other benefits is to disable only the VM IC time provider inside the guest:</p>
<pre class="ipsCode" data-language="powershell">reg add HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\VMICTimeProvider /v Enabled /t REG_DWORD /d 0 /f
net stop w32time
net start w32time
w32tm /query /source</pre>
<p>You can also untick <em>Time synchronization</em> under Integration Services in the VM settings. On VMware, make sure periodic time sync with the host is off in VMware Tools for DC guests, and give the ESXi hosts proper NTP so any one-off syncs (after a vMotion or snapshot revert, for example) are at least correct.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>Checking your work</strong></p></div>
<pre class="ipsCode" data-language="powershell">w32tm /query /status
w32tm /monitor
w32tm /stripchart /computer:time.nist.gov /samples:5 /dataonly</pre>
<ul>
<li>On the PDC, <code>/query /status</code> shows one of your NTP peers as the source, a sensible stratum (typically 2 to 4), and a recent <em>Last Successful Sync Time</em>.</li>
<li><code>w32tm /monitor</code> lists every DC with a small offset from the PDC.</li>
<li><code>/stripchart</code> against an external server shows offsets in milliseconds, not seconds.</li>
<li>On a workstation, <code>w32tm /query /source</code> shows a DC.</li>
</ul>
</div>
<div class="ipsRichTextBox" data-i-background-color="indigo"><div class="ipsRichTextBox__title"><p><strong>If you ever move the PDC role</strong></p></div>
<p>The manual peer config lives on the server, not the role. Transfer the PDC emulator to a new DC and the new one keeps following the hierarchy, so nothing in the domain talks to an external source anymore. Configure the new PDC as above and set the old one back to <code>domhier</code>. Some teams handle this with a GPO linked to the Domain Controllers OU, using a WMI filter that matches only the PDC (<code>Select * from Win32_ComputerSystem where DomainRole = 5</code>), so the setting follows the role automatically.</p>
</div>
<p>If you've got ten seconds today, run <code>w32tm /query /source</code> on your PDC. I'm still surprised how often the answer is wrong.</p>]]></description><guid isPermaLink="false">11</guid><pubDate>Sun, 18 Oct 2026 20:21:41 +0000</pubDate></item><item><title>My ten-minute AD health check with dcdiag and repadmin</title><link>https://wtmsp.com/topic/10-my-ten-minute-ad-health-check-with-dcdiag-and-repadmin/</link><description><![CDATA[<p>A lot of the AD calls we get start the same way. Someone at the front desk says a user "only sometimes" can't get into an app, or a new hire's drive mappings never show up. When we dig in, it's rarely anything exotic. It's replication that quietly stopped weeks ago, a DC nobody noticed was heading for tombstone, or SYSVOL that never finished moving to DFSR. I run this same check on every domain we take on, and again any time something is flaky.</p>
<p>You'll want a DC or a management box with RSAT (AD DS tools), an account in Domain Admins (or delegated rights to read replication metadata), and an elevated prompt or PowerShell window.</p>
<h2>Start with dcdiag across the whole enterprise</h2>
<p><code>dcdiag</code> runs a battery of tests against a DC: connectivity, replication, advertising, FSMO reachability, SYSVOL and more. I always run it verbose and save it to a file, because the lines that matter scroll past way too fast on screen.</p>
<pre class="ipsCode" data-language="powershell">dcdiag /v /c /e &gt; C:\Temp\dcdiag-all.txt
dcdiag /test:dns /v /e &gt; C:\Temp\dcdiag-dns.txt</pre>
<p><code>/e</code> tests every DC in the enterprise and <code>/c</code> runs the comprehensive set. Don't skip <code>/e</code>. Without it you're only testing the box you're logged into. We had one domain where the local DC was spotless and a branch office DC hadn't replicated in 40 days.</p>
<p>Search the file for <strong>failed test</strong>. Some failures are noise. <em>SystemLog</em>, for example, fails if there's been any error in the System log in the last hour. Anything in <em>Replications</em>, <em>Advertising</em>, <em>NetLogons</em>, <em>KccEvent</em> or <em>DFSREvent</em> deserves a proper look.</p>
<h2>Then the replication summary</h2>
<pre class="ipsCode" data-language="powershell">repadmin /replsummary</pre>
<p>You get one table showing, per DC, the largest replication delta and how many of its partners are failing. You want zero in the fails column and deltas in minutes, not days. If any delta is getting close to your tombstone lifetime (180 days on modern forests), stop and fix that first. A DC that's been out of replication longer than that must not just be reconnected.</p>
<h2>Per-partner detail when something looks off</h2>
<pre class="ipsCode" data-language="powershell">repadmin /showrepl
repadmin /showrepl * /csv &gt; C:\Temp\showrepl.csv
repadmin /queue</pre>
<p><code>/showrepl</code> lists each naming context (Domain, Configuration, Schema, DomainDnsZones, ForestDnsZones) and each inbound partner with the result of its last attempt. Once you have more than a handful of DCs, the CSV is much easier to filter. <code>/queue</code> shows pending inbound requests. If the queue never drains, that DC is overloaded or can't reach its partner.</p>
<p>The errors I see most here are 1722 (RPC server unavailable, usually firewall or DNS), 8453 (access denied on replication) and 8524 (DSA operation unable to proceed because of a DNS lookup failure). I check DNS first every time. Most replication errors turn out to be DNS errors in disguise.</p>
<h2>Forcing replication</h2>
<pre class="ipsCode" data-language="powershell">repadmin /syncall /APed</pre>
<p>The flags are <strong>A</strong> for all partitions, <strong>P</strong> to push changes outward from this DC, <strong>e</strong> to include partners in other sites, and <strong>d</strong> to identify servers by distinguished name in the output. Run it on the DC where the change was made. Every partition should report "SyncAll terminated with no errors". Then rerun <code>repadmin /replsummary</code> to confirm.</p>
<div class="ipsRichTextBox" data-i-background-color="orange"><div class="ipsRichTextBox__title"><p><strong>The help desk ticket that was really replication</strong></p></div>
<p>This comes up more than you'd think. The help desk added a user to an access group on DC01 and could see it in ADUC, but the line-of-business app kept denying them. The app did its own LDAP lookups against DC02, which hadn't received the change yet. Within a site, changes normally replicate within seconds. Between sites the default interval is 180 minutes, and in this case someone had stretched the site link schedule further. A <code>repadmin /syncall /APed</code> on DC01 fixed it on the spot.</p>
<p>So before you start troubleshooting the app, find out which DC it's actually talking to. <code>nltest /dsgetdc:contoso.local</code> on a Windows client works, or look at the app's LDAP server setting. Also remember that a user's own Windows session won't see a new group until they log off and back on, because group SIDs are baked into the logon token. That's a different problem from replication, so rule it out separately.</p>
</div>
<h2>FSMO roles</h2>
<pre class="ipsCode" data-language="powershell">netdom query fsmo</pre>
<p>You should get five roles, all held by DCs that actually exist and are online. If one points at a DC that was removed without being demoted, you'll need to seize that role to a healthy DC with <code>ntdsutil</code> and clean up the dead DC's metadata. While you're here, note which DC is the PDC emulator. It matters for time sync and password changes.</p>
<p>Speaking of dead DCs, leftover DNS records and connection objects from DCs that were simply switched off throw replication errors that look alarming but are really a metadata cleanup job. Remove the dead DC in AD Sites and Services and clean up its DNS records instead of chasing each error.</p>
<h2>SYSVOL and DFSR</h2>
<pre class="ipsCode" data-language="powershell">dfsrmig /getglobalstate
net share
Get-CimInstance -Namespace root\microsoftdfs -ClassName DfsrReplicatedFolderInfo |
    Select-Object ReplicatedFolderName, State</pre>
<p><code>dfsrmig /getglobalstate</code> should say <em>Eliminated</em>, which means the migration from FRS to DFSR is complete. Anything else means you're still on FRS, or halfway off it, and newer Windows Server versions won't accept that as a DC. <code>net share</code> has to show both <strong>SYSVOL</strong> and <strong>NETLOGON</strong>. A DC missing those won't process Group Policy for clients, and that's usually how users find out for you. In the CIM query, a State of <strong>4</strong> means Normal, 2 is initial sync and 5 is in error.</p>
<p>Also check the <em>DFS Replication</em> event log on each DC for event 2213, which means replication paused after a dirty shutdown. It needs a manual resume, and it's the one I'm most likely to forget.</p>
<div class="ipsRichTextBox" data-i-background-color="green"><div class="ipsRichTextBox__title"><p><strong>What a healthy domain looks like</strong></p></div>
<ul>
<li><code>dcdiag /e</code> shows no failures in the replication, advertising or DFSR tests</li>
<li><code>repadmin /replsummary</code> shows zero fails and small deltas for every DC</li>
<li><code>netdom query fsmo</code> lists only live DCs</li>
<li>Every DC shares SYSVOL and NETLOGON, and DFSR state is 4</li>
</ul>
</div>
<p>I run this monthly and keep the output files. Comparing this month's against last month's is how you catch the slow drift before it turns into a Monday morning outage.</p>]]></description><guid isPermaLink="false">10</guid><pubDate>Sun, 18 Oct 2026 20:20:40 +0000</pubDate></item></channel></rss>
