Hybrid identity lives or dies on the sync engine that projects on-premises Active Directory into Microsoft Entra ID. Get the authentication method, the sourceAnchor, and the sync rule precedence right and it runs for years untouched; get them wrong and you are doing a tenant-wide re-sync at 2 a.m., re-matching thousands of orphaned objects and explaining to the CISO why half the company cannot sign in. Entra Connect Sync is deceptively simple to install with the Express path and brutally unforgiving to operate once you have stepped off the defaults — because underneath the wizard sits a full metadirectory engine (connector spaces, a metaverse, declarative sync rules with precedence) that most administrators never learn until it breaks.
Naming note: the product formerly known as Azure AD Connect is now Microsoft Entra Connect Sync. The installed component, the run profiles, the Synchronization Service Manager (
miisclient.exe), the Synchronization Rules Editor, and theADSyncPowerShell module are all unchanged; only the branding moved. This article uses the current name but you will still see “Azure AD Connect”, “AAD Connect”, and “ADSync” in the binaries, cmdlets, and event log. The separate, lightweight, agent-only offering is Microsoft Entra Cloud Sync (formerly Azure AD Connect cloud sync) — a different engine entirely, covered in its own section.
This is the deep dive. We treat Entra Connect Sync as three layers: the sync engine (how objects flow AD → connector space → metaverse → connector space → Entra, governed by run profiles and declarative rules), the authentication method (PHS, PTA, or federation — how a password is validated, a decision separate from sync), and Seamless SSO (silent Kerberos sign-in, orthogonal to both). By the end you will reason about a stuck export, a soft-match gone wrong, a cloudFiltered object that vanished from the tenant, a duplicate proxyAddresses error, and a Kerberos key you forgot to roll — and fix each with the exact ADSync cmdlet, connector-space search, or portal path that tells the truth. Every mechanism gets its real cmdlet; every design fork gets a table.
What problem this solves
Almost every organisation running Microsoft 365 has on-premises Active Directory as the authoritative source for user accounts, groups, and their attributes — and needs those identities to exist in Entra ID so Exchange Online, Teams, SharePoint, and thousands of SaaS apps can authenticate them. You cannot maintain two directories by hand: the moment you have more than a handful of users, manual creation drifts — a user gets disabled in AD but stays enabled in the cloud, a display name lags, a leaver keeps their mailbox. Entra Connect Sync makes Entra ID a continuously-reconciled projection of on-premises AD, so one HR-driven change in AD flows to the cloud within the sync interval and one authoritative source governs the whole estate.
What breaks without a correct design: the classic failure is not “sync stops working” — it is “sync works exactly as configured, and the configuration is wrong.” An administrator edits a default sync rule in place; a minor auto-upgrade silently recreates that default and drops the edit; downstream cloudFiltered logic stops scoping; migrated objects get filtered out and deleted from the tenant, and every one of those users loses their mailbox and their ability to sign in. Or the sourceAnchor was objectGUID, a forest migration re-creates every object with a new GUID, and the cloud objects are orphaned soft-matches waiting to duplicate. Or PTA was deployed with a single agent because “it worked in the demo,” and the day that server reboots for patching, nobody can authenticate. These are not edge cases; they are the standard ways hybrid identity deployments fail, and they are all preventable with the design discipline this article teaches.
Who hits this: every Microsoft 365 tenant with on-premises AD — which is most enterprises. It bites hardest on multi-forest environments (acquisitions, mergers, resource forests), on organisations with non-routable .local UPN suffixes, on anyone who chose PTA or federation without wiring the redundancy those methods demand, and on teams who treat the sync engine as a black box and never learn to read a connector space. The fix is almost never “reinstall Connect” — it is “understand which of the five stores the object is stuck in, and why the rule that governs that hop did what it did.”
To frame the whole field before the deep dive, here is every major design decision this article covers, the question it forces, and the default a senior architect reaches for:
| Design decision | The question it forces | Default a senior architect picks | Where getting it wrong hurts |
|---|---|---|---|
| Authentication method | Where is the password validated? | PHS (with PTA/federation only for hard mandates) | Outage resilience, ID Protection leaked-credential detection |
| sourceAnchor | What immutably links on-prem to cloud? | ms-DS-ConsistencyGuid |
Forest migration, DR, orphaned objects |
| Filtering | Which objects reach the cloud at all? | OU-based, then attribute-based for exceptions | Over-sync (noise) vs under-sync (deletions) |
| Sync rule changes | How do you change default behaviour? | Disable-and-clone, never edit in place | Upgrades silently wipe inline edits |
| HA topology | What happens when the server dies? | Staging-mode second server + quarterly drill | Sync stops; no export; no writeback |
| Connect vs Cloud Sync | Full engine or lightweight agents? | Connect Sync for complex; Cloud Sync for simple/multi-forest disconnected | Feature gaps, scale ceilings |
| Seamless SSO key rotation | Who rolls the Kerberos key? | Automated job every ≤30 days | Security finding; silent expiry risk |
Learning objectives
By the end of this article you can:
- Trace an object end to end through the five stores — AD, the AD connector space, the metaverse, the Entra connector space, and the tenant — and name which run profile moves it across each hop.
- Read and reason about sync rule precedence, distinguish inbound from outbound rules, and apply the supported disable-and-clone pattern to change default behaviour without an upgrade resurrecting your edit.
- Choose between Password Hash Sync, Pass-through Authentication, and federation (AD FS) on mechanics — what actually crosses the wire, what the on-prem dependency is at sign-in, and what each costs you in resilience and security posture.
- Design Seamless SSO correctly: understand the
AZUREADSSOACCcomputer account, the Kerberos decryption key, the Intranet-zone URL requirement, and the mandatory ≤30-day key roll. - Pick a sourceAnchor (
ms-DS-ConsistencyGuidvsobjectGUID), understand ImmutableID as its Base64 twin, and avoid the soft-match / hard-match traps that orphan cloud objects. - Configure OU-based and attribute-based filtering, enable password writeback and group writeback, and explain exactly what
cloudFiltered = Truedoes to an object. - Decide between Entra Connect Sync and Entra Cloud Sync, design staging-mode HA with a rehearsed failover, and run swing upgrades so a major version jump has an instant rollback.
- Diagnose real sync errors — duplicate
proxyAddresses,InvalidSoftMatch,AttributeValueMustBeUnique,LargeObject, stuck exports, connectivity failures — with the exact connector-space search andADSynccmdlet that confirms each.
Prerequisites & where this fits
You should already understand core Active Directory concepts — forests, domains, OUs, the difference between objectGUID and objectSID, userPrincipalName vs sAMAccountName, and userAccountControl flags. You should know what Entra ID is (the cloud directory behind Microsoft 365 and Azure) and that a verified custom domain in Entra is what makes a UPN suffix routable. Familiarity with PowerShell is essential — the entire operational surface of Connect Sync is the ADSync module plus a handful of Seamless SSO and Graph cmdlets. Basic TLS/proxy and Kerberos literacy helps for the authentication sections.
This article sits at the foundation of the Hybrid Identity track and is upstream of nearly everything else in Entra. The decision of whether to use this engine at all is covered in Entra Connect Sync vs Cloud Sync: the architecture decision — read it if you have not committed to Connect Sync yet; this deep dive assumes you have. Once identities are syncing, you layer authentication policy on top with Conditional Access at scale: personas and authentication context, and you gain leaked-credential detection and risk-based sign-in through Entra ID Protection: risk-based policies, tuning, and investigation — a capability that depends on PHS being enabled, which is one of the strongest arguments for turning PHS on even behind PTA or federation. If you run multiple tenants, Entra cross-tenant synchronization for the multi-tenant org is the cloud-to-cloud cousin of the on-prem-to-cloud sync described here. And because a corrupted on-prem forest can poison the whole pipeline, the Active Directory forest recovery runbook is the disaster-recovery backstop underneath all of this.
A quick map of who owns which layer during a hybrid-identity incident, so you escalate to the right team fast:
| Layer | What lives here | Who usually owns it | Failure classes it can cause |
|---|---|---|---|
| On-prem AD (source) | Users, groups, attributes, userAccountControl |
AD / Windows team | Bad UPN suffix, duplicate proxyAddresses, disabled bit |
| Connect Sync engine | Connector spaces, metaverse, sync rules, run profiles | Identity / Hybrid team | Filtering deletions, rule-precedence bugs, stuck exports |
| Authentication (PHS/PTA/AD FS) | Password validation path, agents, farm | Identity + platform | Sign-in outages, agent down, AD FS cert expiry |
| Seamless SSO | AZUREADSSOACC account, Kerberos key |
Identity team | Silent-SSO prompts, expired key security finding |
| Entra tenant (target) | Cloud objects, licences, Conditional Access | Identity / M365 team | Soft-match orphans, licence errors, CA blocks |
| Network / proxy | Outbound 443, WS-Trust, agent connectivity | Network team | Agent registration fails, export connectivity errors |
Core concepts
Six mental models make every later diagnosis obvious. Learn these and the rest of the article is detail.
Sync and authentication are two separate decisions. Entra Connect Sync projects objects — it creates and updates users, groups, and contacts in the cloud. How a user’s password is validated at sign-in is a completely separate decision layered on top: PHS validates in the cloud against a synced hash, PTA validates on-prem via agents, federation validates at an AD FS farm. You can run sync with any of the three, and you should almost always enable PHS regardless. Conflating “we sync identities” with “we authenticate a particular way” is the root of most design confusion.
The engine is a metadirectory with five stores. Objects do not flow directly from AD to Entra. They flow AD → AD connector space (a staging copy of the source) → metaverse (the single, consolidated, authoritative view) → Entra connector space (a staging copy of the target) → Entra tenant. Inbound sync rules flow attributes connector-space-to-metaverse; outbound rules flow metaverse-to-connector-space. When something is “wrong in the cloud,” the object is stuck at one of these hops, and the whole diagnostic method is: find which store it is in, and why the rule that governs the next hop did what it did.
Run profiles do the work, in order. Nothing moves until a run profile executes. A delta cycle runs Delta Import (pull AD changes into the AD connector space), Delta Synchronization (apply sync rules, recompute the metaverse, stage changes into the Entra connector space), Export (push staged changes to the tenant), and a confirming Delta Import on the Entra connector (read back what the tenant accepted). A Full Import / Full Synchronization re-reads and re-evaluates everything — expensive, and only run after you change rules or filtering. The scheduler fires a delta cycle every 30 minutes by default.
Sync rules are declarative and ordered by precedence — lower number wins. The product ships dozens of default rules. Each rule has a direction (inbound/outbound), a scope (which objects it applies to), a join (how a connector-space object matches a metaverse object), and transformations (how attributes flow). When two rules would set the same attribute, the one with the lower precedence number wins. Editing a Microsoft-authored default rule is the cardinal sin: on upgrade the engine can recreate that rule and silently discard your edit. The supported pattern is disable-and-clone.
The sourceAnchor is the immutable key, and you choose it once. Every synced object needs an unchanging value that links it to exactly one cloud object. Modern installs use ms-DS-ConsistencyGuid (the engine writes objectGUID into it on first sync, then uses that attribute forever), which survives cross-forest migration. The cloud stores its Base64 form as ImmutableID. Change the sourceAnchor after objects exist and you must delete and re-match every one of them — so this is a decide-once decision, and getting it wrong is the most expensive mistake in the whole product.
cloudFiltered and filtering decide existence. An object reaches the tenant only if it is in scope (its OU is selected) and not filtered out (cloudFiltered is not True). Set cloudFiltered = True on an object that already exists in the cloud and the next export deletes it. Filtering is therefore not a performance knob you can tweak casually — it is the switch that creates and destroys cloud objects, and the number-one accidental cause of mass deletions.
The vocabulary in one table
Before the deep sections, pin down every moving part. The glossary at the end repeats these for lookup; this table is the mental model side by side:
| Concept | One-line definition | Where it lives | Why it matters |
|---|---|---|---|
| Connector space (CS) | Staging copy of a connected system’s objects | One per AD forest + one for Entra | Where objects wait between import and sync |
| Metaverse (MV) | Single consolidated authoritative view | The Connect server DB | Truth; rules flow attributes in and out of it |
| Connector | The configured link to a system (AD forest or Entra) | Connect config | Owns import/export and its run profiles |
| Run profile | A named operation (import/sync/export) | Per connector | Nothing moves until one runs |
| Sync rule | Declarative rule: scope, join, transforms | Rules Editor / Get-ADSyncRule |
Governs how attributes flow, ordered by precedence |
| Precedence | Priority number; lower wins on conflict | Per rule | Which rule sets a contested attribute |
| Join | How a CS object matches an MV object | In inbound rules | Correct join = one person, not two |
| sourceAnchor | Immutable on-prem→cloud key | Global settings | The single decide-once value |
| ImmutableID | Base64 of the sourceAnchor in the cloud | Entra object | The cloud side of the anchor |
cloudFiltered |
If True, object is not exported | Computed on MV person | Flips existence in the cloud |
| PHS | Password Hash Sync (validate in cloud) | Auth method | Resilient default; enables ID Protection |
| PTA | Pass-through Authentication (validate on-prem) | Auth method + agents | On-prem dependency at every sign-in |
| Seamless SSO | Silent Kerberos sign-in | AZUREADSSOACC account |
Skips the password prompt on corp devices |
| Staging mode | Server imports/syncs but does not export | Get-ADSyncScheduler |
Warm standby / DR / test box |
The sync engine: connector spaces, metaverse, and run profiles
Understanding the engine is the difference between guessing and diagnosing. Internally the engine moves data through the five stores, and every troubleshooting session is a matter of localising an object to one of them.
Here is the data path, left to right, for a single user change originating in AD:
AD (source) AD CONNECTOR SPACE METAVERSE ENTRA CONNECTOR SPACE Entra (target)
objects ---> (staging copy of ---> (single, ---> (staging copy of ---> objects
AD objects) authoritative) Entra objects)
[ Delta/Full ] [ inbound rules ] [ outbound rules ] [ Export, then
Import ] CS -> MV MV -> CS confirming Import ]
- Connector space (CS): a per-connector staging copy of source or target objects, holding “holograms” of the real objects plus pending changes. There is one CS for each AD forest and one for Entra. A change lands in the AD CS on import, is projected into the metaverse on sync, is staged into the Entra CS on sync, and is pushed to the tenant on export.
- Metaverse (MV): the single, consolidated view of every identity, keyed by the sourceAnchor. Multiple forests can contribute to one MV person (a user in a resource forest joined to an account in an account forest). Inbound rules flow attributes CS→MV; outbound rules flow MV→CS toward Entra.
- Run profiles do all the movement, and the order in a delta cycle matters:
| # | Step | Direction | What it does | When it runs |
|---|---|---|---|---|
| 1 | Delta Import (AD) | AD → AD CS | Pull only changed AD objects into the AD connector space | Every cycle |
| 2 | Delta Synchronization | CS ↔ MV ↔ CS | Apply inbound rules (CS→MV), recompute MV, apply outbound rules (MV→Entra CS) | Every cycle |
| 3 | Export (Entra) | Entra CS → tenant | Push staged adds/updates/deletes to Entra | Every cycle |
| 4 | Delta Import (Entra) | tenant → Entra CS | Confirming import — read back what the tenant accepted, surface export errors | Every cycle |
A Full Import re-reads every object from a connected system (not just changes); a Full Synchronization re-evaluates every sync rule against every object. You run these only after changing sync rules, filtering, or schema — because on a large directory they are expensive and long-running. The scheduler batches all of this:
# Inspect and control the scheduler
Get-ADSyncScheduler # AllowedSyncCycleInterval, NextSyncCyclePolicyType, enabled flags
Start-ADSyncSyncCycle -PolicyType Delta # force a delta cycle now (import + sync + export)
Start-ADSyncSyncCycle -PolicyType Initial # FULL import + FULL sync + export (run after rule/filter changes)
Set-ADSyncScheduler -SyncCycleEnabled $false # pause the scheduler (e.g., during maintenance)
Set-ADSyncScheduler -SyncCycleEnabled $true # resume
The scheduler runs two independent tasks on the same 30-minute clock, and knowing which is which explains a lot of “why did my password change not sync but my display name did” confusion:
| Scheduler task | What it does | Interval | Notes |
|---|---|---|---|
| Sync cycle | Import → sync → export of objects and attributes | ~30 min (fixed floor) | The main object-sync loop |
| Password hash sync | Streams password hash changes (PHS only) | ~every 2 min | Independent of the sync cycle; near-real-time |
| Maintenance | Certificate/key rotation, DB housekeeping | Periodic | Includes PTA/SSO cert maintenance |
When you need to look at the engine directly rather than through cmdlets, the classic Synchronization Service Manager (miisclient.exe, in the Connect install folder) shows the connectors, the run history with per-object add/update/delete/error counts, and — critically — a connector-space search that lets you find a single object and read its pending changes, its lineage (which rules touched it), and its metaverse projection. That search is the single most useful diagnostic surface in the whole product, and most of the troubleshooting section below comes back to it.
Reading a run history
Every run profile execution records a result and per-object counters. These are the first things you read after a bad cycle:
| Run result | Meaning | Typical cause | First move |
|---|---|---|---|
success |
Everything applied | — | Nothing |
completed-export-errors |
Export ran but some objects failed | Duplicate attribute, unique violation, large object | Read the per-object error; fix source |
completed-sync-errors |
Sync ran but some objects errored | Bad rule expression, join failure | Inspect the erroring object’s lineage |
stopped-server |
The engine or service stopped mid-run | Service crash, reboot, DB issue | Check the Application event log (ADSync source) |
stopped-connectivity |
Could not reach the connected system | Outbound 443 blocked, proxy, DC unreachable | Fix connectivity, re-run import/export |
stopped-extension-dll-exception |
A rule/extension threw | Custom expression error | Fix the expression; re-run |
PHS, PTA, and federation: mechanics, agents, and security
Authentication — how a user’s password is actually validated — is a separate decision layered on top of sync. You have three options, and the choice is fundamentally about where the password is checked and what depends on being alive at sign-in time.
| Method | Where password is validated | On-prem dependency at sign-in | Latency to sign in | Best for |
|---|---|---|---|---|
| Password Hash Sync (PHS) | In the cloud, against a synced hash-of-a-hash | None — survives a full on-prem outage | Lowest (all-cloud) | The default for almost everyone |
| Pass-through Authentication (PTA) | On-prem DC via lightweight agents | Requires a live agent + reachable DC | +one on-prem round trip | “Passwords never leave the building” mandates |
| Federation (AD FS) | On-prem AD FS farm | Requires the whole AD FS estate (proxies, farm, DCs) | Highest (redirect + farm) | Smart-card, 3rd-party MFA at the IdP, complex claims rules |
Principal’s take: default to PHS. Even if a compliance mandate forces PTA or federation, enable PHS as a backstop so that (1) leaked-credential detection in Entra ID Protection works — it compares synced hashes against known-breached credentials, which is impossible without PHS — and (2) you have an instant failover if your PTA agents or AD FS farm go down. Flipping to PHS-only is a supported emergency procedure that gets everyone signing in again in minutes.
What actually crosses the wire with PHS
The single most common objection to PHS is “we cannot let password hashes leave the building.” That objection misunderstands the mechanism. PHS does not sync the cleartext password, and it does not sync the NTLM hash. The PHS process takes the MD4/NTLM hash stored in AD, re-hashes it with a per-user salt through PBKDF2 (HMAC-SHA256, 1000 iterations), and syncs that 32-byte value. The result is not reversible to the cleartext and is not usable against on-prem AD (on-prem authenticates against the NTLM hash, not the PBKDF2-of-NTLM value). So a full compromise of the Entra-side hash store does not hand an attacker anything they can replay against your domain controllers.
| PHS property | Reality |
|---|---|
| What is synced | PBKDF2(HMAC-SHA256, salt, NTLM-hash), 1000 iterations — a hash of a hash |
| What is not synced | Cleartext password; the raw NTLM/MD4 hash; the Kerberos keys |
| Reversible to cleartext? | No |
| Usable against on-prem AD? | No (on-prem uses the NTLM hash directly, not this derived value) |
| Sync frequency | Roughly every 2 minutes, independent of the 30-minute object sync |
| Permission required | Replicate Directory Changes + Replicate Directory Changes All on the domain |
| Enables ID Protection leaked-credential detection | Yes — this is a major reason to keep it on |
PTA mechanics and mandatory redundancy
Pass-through Authentication keeps validation on-prem. It works through lightweight PTA Authentication Agents: the agent opens a persistent outbound connection to Entra (no inbound firewall holes), and when a user signs in, Entra places the (encrypted) credential validation request on a queue, an agent picks it up, validates it against a domain controller with a standard Win32 LogonUser call, and returns success/failure. The password is validated by AD, exactly as an on-prem logon would be.
The catch — and it is the catch that causes real outages — is that PTA is a runtime dependency on every single sign-in. If no agent is alive, or no DC is reachable from the agents, nobody can authenticate. The Connect server installs the first agent automatically; you must install at least two more on separate servers.
Download "Microsoft Entra Connect Authentication Agent" -> install on 2+ EXTRA
domain-joined servers (NOT only the Connect server). Each registers itself to the tenant
over outbound 443. Spread them across failure domains (different hosts, ideally different racks/sites).
Verify in the portal:
Entra admin center -> Identity -> Hybrid management -> Microsoft Entra Connect
-> Connect Sync / Pass-through authentication -> agents = Active (>= 3)
| PTA design factor | Requirement / reality |
|---|---|
| Minimum agents for production | 3 (one on Connect server + two standalone) |
| Connectivity | Outbound 443 only; no inbound ports; supports outbound proxy |
| What the agent needs | Domain membership + line of sight to a writable DC |
| Encryption | Requests encrypted end to end; agent holds a per-tenant cert it auto-rotates |
| Single point of failure if… | Only one agent, or all agents lose all DCs |
| High-availability model | Active/active across agents; Entra load-balances requests |
| Recommended backstop | Enable PHS so you can flip to it if all agents die |
Federation (AD FS) — when and why
Federation with AD FS redirects the entire authentication to an on-premises farm that issues a SAML/WS-Fed token Entra trusts. It is the most capable (arbitrary claims rules, smart-card auth, third-party MFA at the IdP) and by far the most operationally heavy: you run a farm of AD FS servers, a farm of Web Application Proxy servers in the DMZ, load balancers, and a token-signing certificate whose expiry is a company-wide outage waiting to happen. Microsoft’s own guidance for years has been to move off AD FS to PHS/PTA + Conditional Access unless a specific requirement forces it.
| If you need… | Reach for | Notes |
|---|---|---|
| The simplest, most resilient default | PHS | Survives on-prem outage; enables ID Protection |
| Passwords validated on-prem, minimal infra | PTA + Seamless SSO | Runtime dependency; needs ≥3 agents |
| Smart-card / certificate sign-in at the IdP | Federation (AD FS) or move to cloud cert-based auth | Heaviest; consider Entra CBA instead |
| Complex issuance/authorization claims rules | Federation (AD FS) | Or replicate with Conditional Access + claims mapping |
| Third-party on-prem MFA at sign-in | Federation (AD FS) | Or adopt Entra MFA and retire the on-prem MFA |
| To leave AD FS | PHS + Seamless SSO + Conditional Access | The modern target state |
Switching methods is a single wizard/cmdlet change on the Connect server (Change user sign-in), not a rebuild. That is exactly why PHS-as-backstop is cheap insurance: the flip is fast and reversible.
Seamless SSO: the AZUREADSSOACC account and the Kerberos key
Seamless SSO is orthogonal to PHS/PTA — it silently signs in domain-joined, corporate-network users using Kerberos, so they skip the username/password prompt entirely (they still get prompted for MFA if Conditional Access requires it). You do not need it with federation (AD FS provides its own integrated Windows auth). You pair it with PHS or PTA.
The mechanism is precise: enabling Seamless SSO creates a computer account named AZUREADSSOACC in your on-premises AD and shares that account’s Kerberos decryption key with Entra ID. When a user on a corporate device browses to a sign-in URL, the browser requests a Kerberos ticket for AZUREADSSOACC, the domain controller issues it, the browser sends it to Entra, Entra decrypts it with the shared key, and the user is signed in silently. Two operational facts dominate everything here:
AZUREADSSOACCis a highly privileged object. Its Kerberos key is effectively a key to silent sign-in for your tenant. Protect the account like a Tier-0 asset — restrict who can read/manage it.- You must roll its Kerberos key at least every 30 days. Microsoft explicitly recommends this. Seamless SSO keeps working past 30 days, so nobody notices — until a security review flags a stale computer-account password on a Tier-0 object. Automate the roll.
# On the Connect server, from the Seamless SSO module folder
Import-Module 'C:\Program Files\Microsoft Azure Active Directory Connect\AzureADSSO.psd1'
New-AzureADSSOAuthenticationContext # prompts for a Hybrid Identity Administrator
Get-AzureADSSOStatus | ConvertFrom-Json # which domains have Seamless SSO enabled
# Roll the Kerberos decryption key (do this >= every 30 days)
$creds = Get-Credential # on-prem Domain Admin able to reset AZUREADSSOACC
Update-AzureADSSOForest -OnPremCredentials $creds
Client side, Seamless SSO requires two Entra URLs to be in the browser’s Local Intranet zone so the browser will release Kerberos tickets to them, and this is pushed by Group Policy:
| Requirement | Value / detail | Delivered via | Symptom if missing |
|---|---|---|---|
| Intranet-zone URL #1 | https://autologon.microsoftazuread-sso.com |
GPO (Site to Zone Assignment) | Falls back to password prompt |
| Intranet-zone URL #2 | https://aadg.windows.net.nsatc.net |
GPO | Falls back to password prompt |
| Device state | Domain-joined + on corp network / DC line of sight | AD join | No silent sign-in off-network |
AZUREADSSOACC account |
Present in AD, key shared with Entra | Enabling Seamless SSO | Feature not active for the forest |
| Kerberos key roll | Every ≤30 days | Scheduled Update-AzureADSSOForest |
Security finding; stale Tier-0 key |
| Browser support | Kerberos-capable browser honouring the zone | Client config | Prompt instead of silent sign-in |
sourceAnchor and ImmutableID: the decide-once key
The sourceAnchor is the immutable value that links exactly one on-premises object to exactly one cloud object, for the life of that identity. Get it right once and it is invisible forever; get it wrong and every migration or DR event becomes an orphaning event.
Historically people used objectGUID, which is stable within a forest but is regenerated if you ever migrate a user to a new forest (an acquisition, a domain consolidation, a resource-forest move). At that point the old cloud object no longer matches the new on-prem object, and you are into delete-and-re-match territory. Modern installs default to ms-DS-ConsistencyGuid: on first sync the engine copies objectGUID into the ms-DS-ConsistencyGuid attribute on the AD object and then uses that attribute as the anchor thereafter. Because ms-DS-ConsistencyGuid is a writable attribute that you carry with the object during a migration (or re-stamp), cross-forest moves and disaster recovery become dramatically safer.
The cloud stores the anchor as ImmutableID — the Base64-encoded form of the sourceAnchor’s binary value. When you do manual object matching (hard-match), or move a mailbox on-prem, you will work with the ImmutableID directly, so it helps to know it is just Base64 of the same bytes.
# On the Connect server: confirm which attribute is the sourceAnchor
Get-ADSyncGlobalSettings |
Select-Object -ExpandProperty Parameters |
Where-Object { $_.Name -like '*SourceAnchor*' }
# Expect: Microsoft.SynchronizationOption.SourceAnchorAttribute = mS-DS-ConsistencyGuid
# Convert an on-prem objectGUID to the ImmutableID (Base64) the cloud would hold
$guid = (Get-ADUser jdoe).ObjectGUID
[System.Convert]::ToBase64String($guid.ToByteArray())
| Anchor choice | Stable within forest | Survives cross-forest migration | Complexity | Recommendation |
|---|---|---|---|---|
objectGUID |
Yes | No (regenerated in new forest) | Simplest | Legacy only; avoid for new installs |
ms-DS-ConsistencyGuid |
Yes | Yes (writable, carried with object) | Slightly more setup | Default and recommended |
Custom attribute (e.g. employeeID) |
Only if you guarantee uniqueness/immutability | Depends on your process | Highest risk | Only with a strong governance reason |
Decide the sourceAnchor once, before objects exist in the cloud. Changing it after the fact means the cloud objects no longer match on the new anchor; you have to delete-and-re-match every synced object, which for a real tenant is a multi-hour, high-risk, all-hands operation. This is the single most expensive mistake in the product — treat the decision with the gravity it deserves.
Filtering: scoping what reaches the cloud
An object reaches the tenant only if it is in scope and not filtered out. There are two filtering mechanisms and they compose.
OU-based (domain/OU) filtering is the coarse, recommended primary filter: select only the OUs that hold real, cloud-worthy identities. It is set in the Connect wizard (Domain and OU filtering) and is the safest default because it is easy to reason about — an OU is either in or out.
Attribute-based filtering is the fine-grained exception mechanism: an inbound sync rule sets cloudFiltered = True on objects matching a condition (for example, extensionAttribute15 = "NoSync", or department = "Contractors"). Filtering out what you do not need keeps the metaverse small, sync fast, and the cloud tidy — but the danger is direction: cloudFiltered = True on an object that already exists in the cloud deletes it on the next export.
| Filtering type | Granularity | Where configured | Best for | Danger |
|---|---|---|---|---|
| Domain/OU filtering | Whole OUs | Connect wizard | The primary scope | Forgetting an OU → whole team missing |
Attribute-based (cloudFiltered) |
Individual objects | Inbound sync rule | Exceptions within an in-scope OU | Flipping to True on an existing object deletes it |
| Group-based (pilot) filtering | Members of a group | Wizard (pilot only) | Initial pilots only — not for production | Not supported for ongoing production filtering |
Here is a scoped inbound rule that filters out contractors and, for those still in scope, stops overwriting the cloud mail from AD — a common real request:
Synchronization Rules Editor -> Inbound -> Add new rule
Name: In from AD - Custom filter and mail flow
Connected System: contoso.local
CS Object Type: user MV Object Type: person
Link Type: Join
Precedence: 90 (above the default user rules you cloned/disabled)
Scoping filter (this rule applies only when):
department EQUAL "Contractors"
Transformations:
FlowType Target Source / Expression
Constant cloudFiltered True # <-- filters these objects OUT (they will not export)
# For a different scope you might instead flow mail directly and leave cloudFiltered False
On those expressions: cloudFiltered drives whether an object is exported (set True to filter it out, False/unset to keep it). The default rules read the AD disabled bit out of userAccountControl with IIF([userAccountControl] BAND 2 = 0, True, False) — that is how a disabled AD account (0x2, ACCOUNTDISABLE) arrives disabled in Entra. Understanding these two expressions explains most “why did this object disappear / why is it enabled/disabled” questions.
Writing custom sync rules without breaking precedence
Sync rules are evaluated by precedence — lower number wins when two rules contend for the same attribute. The product ships dozens of default rules occupying a band of precedence values (commonly from 0 upward into the 100s). The cardinal rule:
Never edit a default (Microsoft-authored) rule, and never delete one. On upgrade, Microsoft can recreate default rules — silently discarding edits you made in place, and recreating rules you deleted. Author your custom rules at a precedence the product does not reserve, and only after you have audited what is already there.
The supported pattern to change a default behaviour is disable-and-clone:
- Open the Synchronization Rules Editor.
- Find the default inbound rule (e.g.,
In from AD - User Join) and click Disable — do not delete it (the engine recreates deleted defaults). - Clone it, give the clone a precedence number that wins where you need it to, and edit the clone.
Always export your rule set before and after changes so you can diff and roll back, and codify it in source control so an upgrade can never resurrect a silent default over a hand edit:
# Document the current rule set (review this in source control / CI)
Get-ADSyncRule | Sort-Object Precedence |
Select-Object Precedence, Name, Direction, Disabled |
Format-Table -AutoSize
# Full, restorable export of every rule as JSON
Get-ADSyncRule | ConvertTo-Json -Depth 10 |
Out-File C:\ADSync\sync-rules-backup.json
# The supported change pattern: disable the default, then clone in the editor
$def = Get-ADSyncRule | Where-Object { $_.Name -eq 'In from AD - User Join' }
Disable-ADSyncRule -Identifier $def.Identifier
The anatomy of a sync rule — the parts you set and what each controls:
| Rule component | What it controls | Inbound example | Outbound example |
|---|---|---|---|
| Direction | CS→MV (inbound) or MV→CS (outbound) | In from AD - User Join |
Out to AAD - User Join |
| Connected system | Which forest/tenant it applies to | contoso.local |
contoso.onmicrosoft.com - AAD |
| Scope filter | Which objects the rule applies to | department = "Contractors" |
object type = user |
| Join / link type | How CS object matches MV object | Join on ms-DS-ConsistencyGuid |
Join on cloudAnchor |
| Precedence | Priority; lower wins on conflict | 90 |
95 |
| Transformations | How attributes flow (Direct/Constant/Expression) | Direct mail <- mail |
Direct displayName -> displayName |
Flow types you will use inside transformations:
| Flow type | Meaning | Typical use |
|---|---|---|
| Direct | Copy source attribute to target verbatim | displayName, mail, givenName |
| Constant | Set target to a fixed value | cloudFiltered = True/False |
| Expression | Compute the value with the rule language | accountEnabled from userAccountControl; concatenations |
Joins, soft-match, and hard-match: matching without orphaning
A join is how a connector-space object finds its metaverse object (and thus, downstream, its cloud object). Inside the engine, inbound rules join AD-CS objects to MV persons on the sourceAnchor. Between the metaverse and the cloud, there is a separate matching concern: a cloud object that already existed before you started syncing must be matched to the newly-synced object, or you get duplicates. Two mechanisms do this, and both are traps if you have not cleaned up first.
Soft match happens automatically: if a synced object and a pre-existing cloud object share the same primary SMTP address (proxyAddresses) or, in some cases, the same userPrincipalName, Entra links them rather than creating a duplicate. This is usually what you want during an initial sync of a tenant that already had cloud-only accounts (e.g., users created directly in Microsoft 365 before Connect was installed).
Hard match is manual and deterministic: you stamp the ImmutableID on the cloud object to point it explicitly at the on-prem object’s sourceAnchor. You reach for this when soft-match cannot work (no shared SMTP) or has gone wrong.
| Match type | How it links | When it fires | The trap |
|---|---|---|---|
| Soft match | Shared primary SMTP (proxyAddresses) or UPN |
Automatically on first sync | Wrong/duplicate SMTP links the wrong two objects |
| Hard match | You set the cloud object’s ImmutableID = on-prem anchor | Manually via Graph/PowerShell | Typo in the ImmutableID orphans the object |
| No match | Neither fires | New object with no cloud twin | Creates a fresh cloud object (correct for genuinely new users) |
The failure mode to fear is InvalidSoftMatch: two on-prem objects, or an on-prem and a cloud object, contend for the same SMTP/UPN, and the engine refuses to link ambiguously. You resolve it by de-duplicating the proxyAddresses/UPN on the source (which is exactly what IdFix and pre-sync hygiene prevent). Audit for duplicates before the first sync or you will orphan mailboxes and generate a pile of export errors.
Password writeback, group writeback, and device writeback
By default sync is one-way (AD → Entra). Three optional features write back from the cloud to on-prem or expand what syncs, each with its own licence and identity requirement.
Password writeback lets a cloud self-service password reset (SSPR) or a change flow back to on-premises AD in real time, so a user who resets their password in the cloud can immediately log on to a domain-joined workstation with the new password. It requires Entra ID P1 and is the feature that makes SSPR actually usable in a hybrid world.
Group writeback provisions cloud groups (notably Microsoft 365 groups) back into on-premises AD as distribution/security groups, so on-prem apps can consume cloud-created groups.
| Writeback feature | Direction | Licence required | Enables | Gotcha |
|---|---|---|---|---|
| Password writeback | Cloud → AD | Entra ID P1 | SSPR/password change reaching on-prem AD | Needs the sync account to have reset-password rights on target OUs |
| Group writeback | Cloud → AD | Entra ID P1 (M365 groups) | On-prem apps consuming cloud groups | Target OU + naming; can create object sprawl |
| Device writeback | Cloud → AD | P1 | Conditional Access on-prem (legacy AD FS scenarios) | Largely superseded by cloud device identity |
# Confirm password writeback is enabled and which connector carries it
$aad = Get-ADSyncConnector | Where-Object { $_.Type -eq 'Extensible2' } # the Entra connector
Get-ADSyncAADPasswordResetConfiguration -Connector $aad.Name # Enabled = True when on
# PHS status (separate from writeback) — is the hash sync flowing?
Get-ADSyncAADPasswordSyncConfiguration -SourceConnector "<forest connector name>"
Entra Connect Sync vs Entra Cloud Sync
Microsoft ships two on-prem-to-cloud sync engines, and choosing wrong means either fighting a lightweight tool that cannot do what you need, or over-engineering a simple environment. Entra Connect Sync (this article’s subject) is the heavyweight metadirectory engine installed on a Windows server. Entra Cloud Sync is an agent-only, cloud-configured engine (the same provisioning agent used by PTA) that runs simple provisioning with the configuration living in Entra rather than on a server. The full decision is its own article — Entra Connect Sync vs Cloud Sync: the architecture decision — but here is the essential fork:
| Dimension | Entra Connect Sync | Entra Cloud Sync |
|---|---|---|
| Where config lives | On the Connect server (rules, filtering) | In the cloud (Entra portal) |
| Footprint | Full Windows server + SQL/LocalDB | Lightweight provisioning agents only |
| Custom sync rules | Full (Rules Editor, expressions, joins) | Limited attribute mapping and scoping |
| Multi-forest | Yes (single metaverse across forests) | Yes — and handles disconnected forests well |
| Device sync / Hybrid Azure AD Join writeback | Yes | No (not supported) |
| Group writeback / Exchange hybrid writeback | Yes | No / limited |
| Pass-through Authentication support | Yes | Yes (shares the agent) |
| Filtering | OU + attribute (rich) | OU + attribute scoping (simpler) |
| Best for | Complex estates, Exchange hybrid, device writeback, big custom-rule needs | Simple/greenfield, disconnected forests, low-footprint, M&A stopgaps |
| Can they coexist? | Yes — Connect for some forests, Cloud Sync for others (with care) | Yes |
The rule of thumb: Connect Sync when you need custom rules, device writeback, or Exchange hybrid; Cloud Sync when you want a low-footprint, cloud-managed engine and can live inside its feature set — especially for onboarding a disconnected acquisition forest quickly.
High availability: staging mode, failover, and upgrades
Entra Connect Sync is active/passive, not active/active — only one server may export to a given tenant at a time. High availability is a second server in staging mode: it runs imports and synchronization (so its metaverse stays warm and current) but does not export to Entra and does not perform password writeback. That staging server is simultaneously your DR box, your safe place to test rule changes, and the target for swing upgrades.
# Confirm a server's role
(Get-ADSyncScheduler).StagingModeEnabled # True on the standby box, False on the active box
# Failover: promote staging to active, then demote the old primary
# On the OLD primary: Set-ADSyncScheduler -StagingModeEnabled $true
# On the NEW primary: Set-ADSyncScheduler -StagingModeEnabled $false
Because both servers must use the same sourceAnchor and identical connector/filtering configuration, the safest way to keep them in lockstep is to export the active server’s configuration and import it when building or refreshing staging:
# On the active server: snapshot the full configuration
Get-ADSyncServerConfiguration -Path C:\ADSyncExport
# (then apply that snapshot when building/refreshing the staging server)
| Server role | Imports | Runs sync rules (warm MV) | Exports to Entra | Password writeback | Purpose |
|---|---|---|---|---|---|
| Active (primary) | Yes | Yes | Yes | Yes | The live sync source |
| Staging | Yes | Yes | No | No | Warm standby, DR, test rule changes, upgrade target |
Run a failover drill every quarter. A staging server you have never promoted is a hope, not a plan.
Upgrade strategy has two paths. For in-place minor updates, prefer automatic upgrade (Get-ADSyncAutoUpgrade shows the state). For major version jumps, do a swing migration: stand up the new version on the staging server, validate its metaverse and a pending-export preview against production, then flip staging to active — which gives you an instant rollback by flipping back. Connect builds expire (older builds get deprecated and eventually blocked from syncing), so treat staying current as part of the operational baseline, not an optional chore.
| Upgrade method | Use for | Rollback | Downtime |
|---|---|---|---|
| Automatic upgrade | Minor/patch builds | Reinstall prior build (harder) | Brief; auto-managed |
| In-place manual | Minor builds you want to control | Manual; risky | Brief sync pause |
| Swing migration | Major version jumps | Instant (flip staging back) | Near-zero (failover flip) |
Architecture at a glance
There is no diagram for this article — the architecture is best held as a mental model of the five stores and the run-profile clock, so read this section as the map you keep in your head during an incident.
Picture the pipeline left to right in three bands. On the left, one or more on-premises AD forests hold the authoritative objects; a per-forest connector space is a staging mirror of each forest’s in-scope objects. In the centre sits the single metaverse — the consolidated person view keyed by the sourceAnchor (ms-DS-ConsistencyGuid); inbound rules flow attributes into it from each forest CS, and outbound rules flow out of it toward the Entra CS. On the right, the Entra connector space stages changes for the tenant, and Export pushes them to Entra ID, followed by a confirming import that reads back acceptance and surfaces any export errors. Overlay three vertical concerns on this pipeline: the run-profile clock (delta import → delta sync → export → confirming import, every 30 minutes), the PHS lane (a separate ~2-minute loop streaming password hashes straight from AD to the tenant, bypassing the object-sync path), and the authentication plane which is not part of sync at all — at sign-in, PHS validates in the cloud, PTA hops out through an agent to a DC, or federation redirects to AD FS.
Two features hang off the sides of this picture. Seamless SSO lives on the on-prem side as the AZUREADSSOACC computer account whose Kerberos key is shared with Entra, letting corporate-network browsers sign in silently. Staging mode is a second copy of the entire left-and-centre pipeline on a standby server that imports and syncs (keeping a warm metaverse) but never exports — the failover target. The whole diagnostic method falls out of this map: when something is wrong in the cloud, ask which store the object is in (AD, AD CS, MV, Entra CS, or tenant), which run profile was supposed to move it, and which rule governs that hop — and the connector-space search in the Synchronization Service Manager shows you the answer for any single object.
Real-world scenario
Meridian Retail runs Entra Connect Sync for ~28,000 users across two AD forests — the original meridian.local and an acquired harborline.local onboarded eight months earlier. They authenticate with PTA (a compliance mandate: “passwords are validated on-prem”) plus Seamless SSO, and they had done the right things: three PTA agents, ms-DS-ConsistencyGuid as the sourceAnchor, OU-based filtering. The identity team is three engineers; the estate is considered “stable and boring,” which is exactly when it bites.
The incident began quietly. Over a weekend, the service desk logged a trickle of “cannot sign in” tickets — all from users in one business unit recently reorganised between OUs in the acquired forest as post-merger cleanup. By Monday it was ~600 users with the same symptom: their account simply did not exist in Entra anymore. Not disabled — gone. Mailboxes inaccessible, Teams signed out, PTA sign-in failing because there was no cloud object to authenticate against. Because PTA was the auth method, the first (wrong) instinct on the bridge was “the agents are down” — but the portal showed all three agents Active and other users signed in fine. Authentication was healthy; the objects were missing.
The breakthrough came from asking which store the objects were in. A connector-space search for one affected user showed the object present in the harborline.local connector space and projected into the metaverse — but with cloudFiltered = True on the metaverse person and a pending export: delete staged into the Entra connector space. The engine had imported and synced correctly, then correctly filtered the object out and deleted it, exactly as configured. The question was why the filter flipped.
The root cause was a classic edited default rule. Eleven months earlier, an admin had edited the default In from AD - User Join rule in place to flow a custom employeeID into an extension attribute. During the acquired forest’s onboarding, a minor auto-upgrade silently recreated that default rule, dropping the inline edit. The downstream custom rule that computed cloudFiltered depended on an attribute the reverted default no longer populated for objects that had moved OUs. So when the reorg moved those 600 objects between OUs, a Full Synchronization re-evaluated the rules, cloudFiltered computed to True for exactly those objects, and the next export deleted them.
The recovery and the permanent fix, in order:
| Time | State | Action | Effect |
|---|---|---|---|
| Sat–Sun | Trickle of “cannot sign in” | (tickets accumulate) | Missed as noise |
| Mon 09:00 | ~600 users, objects gone | Assumed PTA agents down | Wrong — agents Active |
| Mon 10:30 | Auth confirmed healthy | Connector-space search on one user | Found cloudFiltered=True + pending delete |
| Mon 11:15 | Root cause found | Diffed live rules vs source-control baseline | Default rule reverted by auto-upgrade |
| Mon 12:00 | Stop the bleeding | Set-ADSyncScheduler -SyncCycleEnabled $false |
Halt further deletes/exports |
| Mon 13:00 | Restore objects | Restore from Entra recycle bin (30-day soft-delete window) | ~600 objects and mailboxes back |
| Mon 14:00 | Fix the rule | Disable the default; clone at precedence 90 with the employeeID flow |
Correct, upgrade-safe behaviour |
| Mon 15:00 | Re-sync safely | Start-ADSyncSyncCycle -PolicyType Initial, verify no pending deletes |
Clean cycle, no deletions |
| +1 week | Prevent recurrence | Added a pre/post-upgrade Get-ADSyncRule diff to the change runbook and CI |
An upgrade can never silently revert a rule again |
Two facts saved them: Entra keeps deleted synced users in a 30-day recycle bin (so the deletions were recoverable), and their sourceAnchor was ms-DS-ConsistencyGuid (so restored objects re-matched cleanly on re-sync). The lesson written on the wall: “Any edit to a Microsoft-authored rule is a time bomb that detonates on the next upgrade. Clone, never edit in place, and diff the rule set on every upgrade.”
Advantages and disadvantages
The metadirectory model — full sync engine on a server, declarative rules, active/passive HA — is powerful and precise, and that power is exactly what makes it dangerous in unpracticed hands. Weigh it honestly:
| Advantages (why this engine is worth it) | Disadvantages (why it bites) |
|---|---|
| Full custom sync rules — join, scope, transform any attribute with an expression language | Rule complexity is real; a wrong precedence or a bad cloudFiltered deletes objects |
| Multi-forest into one metaverse — resource forests, acquisitions, consolidations all handled | Every forest adds a connector space and matching complexity |
| Device writeback, group writeback, Exchange hybrid writeback supported (Cloud Sync is not) | Heavier footprint: a Windows server, SQL/LocalDB, patching, the version-expiry treadmill |
| PHS gives outage-resilient auth and enables ID Protection leaked-credential detection | Defaults are traps: editing a default rule, wrong sourceAnchor, single PTA agent |
| Staging mode is a warm DR box, a rule-test sandbox, and an instant swing-upgrade target | Active/passive only — no active/active; failover is a manual flip you must rehearse |
| Deep observability: connector-space search, run history, per-object lineage tells you exactly where an object is stuck | The learning curve is steep; the engine is opaque until you learn the five stores |
| Password writeback closes the SSPR loop back to on-prem AD | Writeback needs P1 and correctly-delegated reset rights on target OUs |
The engine is right for complex enterprises: multiple forests, Exchange hybrid, device writeback, real custom-attribute needs, and teams that will operate it properly (source-controlled rules, a rehearsed failover, PHS on). It is over-engineered for a simple single-forest greenfield tenant with no writeback needs — where Cloud Sync’s low footprint wins — and actively dangerous for a team that treats it as a black box: the same power that scopes 28,000 users precisely lets you delete 600 with one reverted rule. The disadvantages are all manageable — but only through discipline, which is the point of this article.
Hands-on lab
This lab builds a hardened Entra Connect Sync deployment on a dedicated server, confirms the engine internals, and validates PHS + Seamless SSO — without any destructive operations against a production tenant. It assumes a non-production Entra tenant, one AD forest, and a Windows Server domain-joined member you will use as the Connect server. All commands run on that server unless noted.
Step 1 — Pre-flight hygiene on a domain controller. Confirm routable UPN suffixes and run IdFix mentally first (add a routable suffix, re-stamp any .local users):
# On a DC: ensure a routable UPN suffix exists and re-stamp users off .local
Get-ADForest | Format-List UPNSuffixes
Set-ADForest -Identity contoso.local -UPNSuffixes @{Add="contoso.com"}
Get-ADUser -Filter "UserPrincipalName -like '*@contoso.local'" -SearchBase "OU=Staff,DC=contoso,DC=local" |
ForEach-Object {
$new = ($_.UserPrincipalName -replace '@contoso\.local$','@contoso.com')
Set-ADUser $_ -UserPrincipalName $new
}
Expected: every synced user’s UPN suffix matches a verified domain in Entra. (Run IdFix from a workstation to clean duplicate proxyAddresses/mail before the first sync — this prevents the export errors in the troubleshooting section.)
Step 2 — Create a gMSA for the sync service. Automatic credential rotation, no stored password:
# On a DC (KDS root key must already exist in the forest)
New-ADServiceAccount -Name svc-aadsync -DNSHostName connect01.contoso.com `
-PrincipalsAllowedToRetrieveManagedPassword "CONTOSO\ConnectServers"
Step 3 — Install with Customize, not Express. Choose PHS, enable Seamless SSO, use the gMSA, and OU-filter to real identities:
Entra Connect -> Customize -> Install required components
[x] Use an existing service account -> gMSA: CONTOSO\svc-aadsync$
User sign-in:
(o) Password Hash Synchronization
[x] Enable single sign-on (Seamless SSO)
Connect your directories:
+ Add AD forest -> account with Replicate Directory Changes (+ All) for PHS
Domain/OU filtering:
(o) Sync selected OUs -> [x] OU=Staff [x] OU=Groups [ ] OU=Disabled [ ] OU=Computers-Lab
Identifying users:
(o) ms-DS-ConsistencyGuid as the source anchor
Optional features:
[x] Password hash synchronization
[x] Password writeback (requires Entra ID P1)
[ ] Group writeback
[ ] Start the synchronization process <-- LEAVE UNCHECKED so you can inspect first
Step 4 — Confirm the engine internals before enabling the scheduler. Read the sourceAnchor, the connectors, and the rule set:
Import-Module ADSync
# Source anchor is what you chose
Get-ADSyncGlobalSettings | Select-Object -ExpandProperty Parameters |
Where-Object { $_.Name -like '*SourceAnchor*' } # expect mS-DS-ConsistencyGuid
Get-ADSyncConnector | Select-Object Name, Type # one AD connector + one Extensible2 (Entra)
Get-ADSyncRule | Sort-Object Precedence |
Select-Object Precedence, Name, Direction, Disabled | Format-Table -AutoSize
Expected: SourceAnchorAttribute = mS-DS-ConsistencyGuid, two connectors, and dozens of default rules — all Disabled = False.
Step 5 — Enable the scheduler and run an initial cycle. Full import + full sync + export:
Set-ADSyncScheduler -SyncCycleEnabled $true
Start-ADSyncSyncCycle -PolicyType Initial
Get-ADSyncConnectorRunStatus # watch until idle (not "Running")
Step 6 — Validate PHS and Seamless SSO. Confirm the hash sync and the SSO status:
# PHS flowing?
$fwd = (Get-ADSyncConnector | Where-Object { $_.Type -ne 'Extensible2' }).Name
Get-ADSyncAADPasswordSyncConfiguration -SourceConnector $fwd # Enabled = True
# Seamless SSO enabled for the forest?
Import-Module 'C:\Program Files\Microsoft Azure Active Directory Connect\AzureADSSO.psd1'
New-AzureADSSOAuthenticationContext
Get-AzureADSSOStatus | ConvertFrom-Json # domain listed, enabled
Then, from a domain-joined client on the corporate network with the two SSO URLs in the Intranet zone (Step 8), browse to https://myapps.microsoft.com — a synced user should sign in without a password prompt.
Step 7 — Practise the disable-and-clone pattern (read-only rehearsal). Export the rules, then disable-and-clone one default in the editor (do not save a destructive change in a shared tenant):
Get-ADSyncRule | ConvertTo-Json -Depth 10 | Out-File C:\ADSync\rules-baseline.json
# In the Synchronization Rules Editor: select 'In from AD - User Join' -> Disable -> Clone -> set precedence 90
# This is the muscle memory that prevents the real-world scenario above.
Step 8 — Push the Seamless SSO Intranet-zone GPO. Add both URLs to the Local Intranet zone via Site to Zone Assignment List so Kerberos tickets are released. Then re-test silent sign-in from Step 6.
Step 9 — Stand up staging (optional but recommended). On a second server, install Connect the same way but check “Enable staging mode.” Confirm and rehearse the flip:
(Get-ADSyncScheduler).StagingModeEnabled # True on the standby
# Rehearse (do NOT leave both active): old primary -> True, then new primary -> False
Teardown. This lab creates no billable Azure resources; the cost is the server(s). To fully unwind: uninstall Entra Connect from Programs and Features (choose to remove the sync service and the LocalDB), which also cleans up the Entra-side sync configuration; delete the AZUREADSSOACC computer account only after disabling Seamless SSO via Disable-AzureADSSOForest; and remove the gMSA (Remove-ADServiceAccount) and the routable-UPN test changes if they were lab-only.
Common mistakes & troubleshooting
The sync engine tells the truth if you know where to look. The universal method: find which store the object is in (connector-space search in the Synchronization Service Manager), read its pending export/import and lineage (which rules touched it), then fix the source (AD attribute) or the rule, never the symptom. Below is the playbook — symptom → root cause → confirm (exact path/cmdlet) → fix.
| # | Symptom | Root cause | Confirm (exact command / path) | Fix |
|---|---|---|---|---|
| 1 | User missing from the cloud | cloudFiltered = True (filtering) or out-of-scope OU |
Connector-space search → object shows pending delete / cloudFiltered=True; check OU filtering in wizard |
Fix the rule that set cloudFiltered; re-include the OU; restore from Entra recycle bin (30 days) |
| 2 | Duplicate user in the cloud | Soft-match failed; two objects, no shared SMTP/UPN | Two cloud objects, one synced one cloud-only, no ImmutableID link |
Hard-match: stamp the cloud object’s ImmutableID to the on-prem anchor |
| 3 | Export error: AttributeValueMustBeUnique (proxyAddresses) |
Duplicate proxyAddresses/mail across objects |
Run history → export → per-object error names the duplicate value | Run IdFix; remove the duplicate address on the source; re-run export |
| 4 | Export error: InvalidSoftMatch |
Two objects contend for the same SMTP/UPN | Per-object export error names both contenders | De-duplicate SMTP/UPN on the source; re-sync |
| 5 | Attribute won’t flow (e.g., mail never updates) |
A default rule (lower precedence) wins the attribute | Object lineage shows which rule set the value | Disable-and-clone; set your clone to a lower precedence than the default |
| 6 | Your custom rule edit vanished after upgrade | You edited a default rule in place; upgrade recreated it | Diff Get-ADSyncRule against your source-controlled baseline |
Re-implement as disable-and-clone; add a pre/post-upgrade rule diff to the runbook |
| 7 | PHS not working (cloud password stale) | PHS not enabled, or Replicate perms missing | Get-ADSyncAADPasswordSyncConfiguration → Enabled=False; event log 611/615 |
Enable PHS; grant Replicate Directory Changes (+ All); Set-ADSyncAADPasswordSyncConfiguration ... -Enable $true |
| 8 | Some users can’t sign in (PTA) | An agent down, or agents can’t reach a DC | Portal → PTA agents not all Active; agent server event log | Restore/add agents; verify DC line of sight; flip to PHS as emergency backstop |
| 9 | Seamless SSO prompts for a password | SSO URLs not in Intranet zone, or key stale/absent | Get-AzureADSSOStatus; check GPO Site-to-Zone list on client |
Push the two URLs via GPO; roll the key with Update-AzureADSSOForest |
| 10 | Export error: LargeObject / attribute too big |
An attribute (e.g., huge member, thumbnailPhoto) exceeds cloud limits |
Per-object export error names the attribute | Trim the source value; filter the attribute out via a rule |
| 11 | Run result stopped-connectivity |
Outbound 443 blocked, proxy breaks modern auth, or DC unreachable | Run history result; Test-NetConnection to Entra endpoints on 443 |
Open outbound 443; bypass authenticating proxy for Connect; fix DC reachability |
| 12 | UPN wrong in the cloud (.onmicrosoft.com) |
On-prem UPN suffix not a verified domain | Cloud UPN falls back to <user>@<tenant>.onmicrosoft.com |
Add + verify the domain; re-stamp on-prem UPN suffix; re-sync |
| 13 | AttributeValueMustBeUnique on UPN |
Two on-prem users share a UPN | Export error names the duplicate UPN | Make UPNs unique on-prem; re-sync |
| 14 | Both sync servers exporting (config drift) | Staging server accidentally set active | (Get-ADSyncScheduler).StagingModeEnabled = False on both |
Set the standby back to -StagingModeEnabled $true; reconcile config from the true primary |
| 15 | Object deletes not flowing / re-appearing | Accidental-deletion threshold tripped, blocking the export | Export blocked with a deletion-threshold warning | Review the deletions; if legitimate, Enable-ADSyncExportDeletionThreshold override for one run |
Three high-value confirmation snippets referenced above:
# The single most useful diagnostic: open the Synchronization Service Manager (miisclient.exe),
# choose the connector, "Search Connector Space", find the object, and read:
# - its pending export (Add / Update / Delete)
# - its metaverse projection (Lineage tab shows which rules set which attributes)
# Confirm PHS end to end
Get-ADSyncAADPasswordSyncConfiguration -SourceConnector "<forest connector name>" # Enabled = True
# Deletion threshold protects you from mass-delete accidents (like the real-world scenario)
Get-ADSyncExportDeletionThreshold # current threshold
# If a legitimate bulk delete is being blocked, allow it for a single run:
Enable-ADSyncExportDeletionThreshold -DeletionThreshold 700
A quick decision table for the “object is wrong in the cloud” family — the fastest triage:
| If the object is… | It’s probably stuck in… | Do this |
|---|---|---|
| Missing entirely | Metaverse with cloudFiltered=True, or never in scope |
Check filtering/OU; restore from recycle bin |
| Duplicated | Soft-match failed | Hard-match via ImmutableID |
| Present but attribute wrong | A lower-precedence rule wins the attribute | Read lineage; disable-and-clone |
| Present but disabled unexpectedly | userAccountControl disabled bit (0x2) |
Fix the AD account state |
| Failing to export at all | Duplicate/unique/large-object error | Read the per-object export error; fix source |
Best practices
- Default to PHS, always enable it as a backstop. Even behind PTA or federation, PHS gives you an instant sign-in failover and unlocks ID Protection leaked-credential detection. Turn it off only for a hard compliance mandate.
- Decide the sourceAnchor once, and pick
ms-DS-ConsistencyGuid. Never change it after objects exist in the cloud. This is the most expensive decision to get wrong in the entire product. - Never edit or delete a default sync rule. Use disable-and-clone for every change to default behaviour. Upgrades resurrect defaults and silently wipe inline edits.
- Treat the rule set as source-controlled code. Export
Get-ADSyncRuleto JSON/CSV, commit it, and diff it before and after every upgrade as a mandatory runbook step. - Run IdFix and clean
proxyAddresses/UPN before the first sync. Duplicate addresses are the number-one export error and the cause ofInvalidSoftMatch— eliminate them up front. - Filter carefully; remember
cloudFiltered=Truedeletes existing objects. Use OU filtering as the coarse primary scope and attribute filtering only for exceptions, and always run a Full Sync on a staging server first to preview the impact. - Use a gMSA for the sync service so credential rotation is automatic and no password is stored.
- Run at least three PTA agents on separate failure domains (only if you use PTA). One agent is a single point of failure in authentication itself.
- Automate the
AZUREADSSOACCKerberos key roll every ≤30 days. Seamless SSO keeps working past 30 days, so this becomes a silent security finding unless you schedule it. - Build a staging server and rehearse failover quarterly. Keep it configuration-identical via
Get-ADSyncServerConfigurationsnapshots, and use it as your swing-upgrade target for major versions. - Keep the build current. Old Connect builds get deprecated and eventually blocked; leave auto-upgrade on for minors and swing-migrate majors.
- Verify UPN suffixes are verified domains before syncing so no user lands on a
.onmicrosoft.comfallback UPN.
Security notes
Hybrid identity is a Tier-0 concern: the sync server, its service account, and the Seamless SSO object are all effectively keys to your directory. Harden them accordingly.
| Asset | Risk if compromised | Hardening |
|---|---|---|
| Connect server | Full read of AD + ability to write the tenant | Treat as Tier-0: dedicated, hardened, no inbound internet, restricted admin, patched |
| Sync service account (gMSA) | Directory-wide read; PHS replication rights | gMSA (auto-rotated password); grant only the rights each feature needs |
| PHS replication rights | Reading directory changes | Grant Replicate Directory Changes (+ All) to the sync account only |
AZUREADSSOACC account |
Silent sign-in for the tenant | Tier-0 object; restrict management; roll key ≤30 days; monitor for changes |
| PTA agents | Sit in the credential-validation path | Domain-joined, hardened, outbound-only 443; patch; ≥3 for HA |
| Password writeback delegation | Ability to reset on-prem passwords | Delegate reset rights narrowly to the sync account on target OUs only |
| Rule set | Silent mass deletions / attribute tampering | Source-control it; diff on upgrade; change control on rule edits |
Additional posture points: keep the Connect server off domain controllers and out of the DMZ; use TLS 1.2 and a supported OS/.NET build; do not place the server behind an authenticating proxy that breaks WS-Trust/modern auth (bypass it for the Connect and PTA agent traffic); enable accidental-deletion protection (the deletion threshold) so a bad filter cannot silently empty your tenant; and layer Conditional Access on top so that how identities sync and how they are allowed to sign in are governed as one design. Because a corrupted source forest poisons the whole pipeline, keep the forest recovery runbook current as the ultimate backstop.
Cost & sizing
Entra Connect Sync itself is free — there is no per-object or per-server licence for the sync engine or Seamless SSO. The costs are indirect: the Windows Server(s) you run it on, and the Entra licences some features require.
| Cost driver | What it is | Rough figure | Notes |
|---|---|---|---|
| Sync engine / Seamless SSO / PHS / PTA | The core sync and auth mechanics | Free | No licence for the engine itself |
| Connect server (primary) | 1 Windows Server VM/host | Small server cost | 4 vCPU / 8–16 GB handles most estates |
| Staging server | 1 more Windows Server for HA/DR | Same again | Strongly recommended, not free |
| Password writeback | Cloud→AD SSPR round-trip | Needs Entra ID P1 (~₹550/user/mo list) | P1 is usually already licensed for CA |
| Group writeback (M365 groups) | Cloud→AD group provisioning | Needs Entra ID P1 | Same licence as above |
| ID Protection leaked-credential detection | Needs PHS on | Needs Entra ID P2 | The reason to keep PHS on even behind PTA |
| SQL Server (very large tenants) | Beyond ~100k objects, full SQL vs LocalDB | SQL licence | LocalDB suffices below the threshold |
Sizing rules of thumb: the built-in LocalDB supports up to roughly 100,000 objects; beyond that, point Connect at a full SQL Server. A single 4 vCPU / 8–16 GB server comfortably handles tens of thousands of users; the metaverse and connector-space databases grow with object and attribute count, so filter out what you do not need. The real “cost” of a bad design is not the bill — it is the 2 a.m. re-sync — so spend the money on the staging server and the design discipline, not on oversized VMs.
Interview & exam questions
Q1. What is the difference between the connector space and the metaverse? The connector space is a per-connector staging copy of a connected system’s objects (one CS per AD forest, one for Entra); the metaverse is the single, consolidated, authoritative view keyed by the sourceAnchor. Inbound rules flow attributes CS→MV; outbound rules flow MV→CS. (Maps to SC-300, MS-100/MS-102.)
Q2. What actually gets synced with Password Hash Sync — and is it a security risk? Not the cleartext password and not the NTLM hash, but a PBKDF2(HMAC-SHA256) hash of the NTLM hash, salted per user. It is not reversible and not usable against on-prem AD, and it enables ID Protection leaked-credential detection. It is Microsoft’s recommended default. (SC-300.)
Q3. Why default to PHS even if you deploy PTA or federation? PHS gives an instant sign-in failover if agents/AD FS go down and unlocks leaked-credential detection. Flipping to PHS-only is a supported emergency procedure. Turn PHS off only for a hard compliance mandate. (SC-300.)
Q4. What is the sourceAnchor, why ms-DS-ConsistencyGuid, and what is ImmutableID? The sourceAnchor is the immutable on-prem→cloud key. ms-DS-ConsistencyGuid is preferred over objectGUID because it survives cross-forest migration (it is a writable attribute you carry with the object). ImmutableID is the Base64 form of the sourceAnchor stored on the cloud object. (SC-300, MS-102.)
Q5. How do you change a default sync rule’s behaviour safely? Never edit or delete the default — use disable-and-clone: disable the Microsoft-authored rule, clone it, set the clone’s precedence to win where needed, edit the clone. On upgrade, defaults can be recreated and inline edits silently lost. (SC-300.)
Q6. How does sync-rule precedence resolve conflicts? Each rule has a precedence number; when two rules would set the same attribute, the lower number wins. Author custom rules at a precedence that beats the default only where you intend to override it. (SC-300.)
Q7. What does cloudFiltered = True do, and why is it dangerous? It marks a metaverse object to not be exported. If set on an object that already exists in the cloud, the next export deletes it. It is the number-one cause of accidental mass deletions when a filtering rule scopes incorrectly. (SC-300.)
Q8. What is staging mode and what does it not do? A second Connect server in staging mode imports and runs sync rules (keeping a warm metaverse) but does not export to Entra and does not perform password writeback. It is the DR box, the rule-test sandbox, and the swing-upgrade target. Only one server may be active per tenant. (SC-300, MS-102.)
Q9. How does Seamless SSO work and what is the AZUREADSSOACC account? Enabling Seamless SSO creates the AZUREADSSOACC computer account in AD and shares its Kerberos decryption key with Entra; corporate-network browsers request a Kerberos ticket for it and Entra decrypts it to sign the user in silently. The key must be rolled at least every 30 days. (SC-300.)
Q10. When would you choose Cloud Sync over Connect Sync? When you want a low-footprint, cloud-configured engine and can live within its feature set — simple/greenfield tenants, or onboarding a disconnected acquisition forest quickly. Choose Connect Sync when you need custom sync rules, device writeback, group writeback, or Exchange hybrid. (SC-300, MS-102.)
Q11. A synced user is missing from the cloud. Walk through the diagnosis. Do a connector-space search: is the object present and projected to the metaverse? Check cloudFiltered and any pending delete. If filtered, find the rule that set cloudFiltered=True; if out of scope, check OU filtering. Restore from the Entra 30-day recycle bin, then fix the rule/scope and re-sync. (SC-300.)
Q12. What is the difference between soft-match and hard-match? Soft-match links a synced object to a pre-existing cloud object automatically by shared primary SMTP (or UPN). Hard-match is manual — you stamp the cloud object’s ImmutableID to the on-prem anchor. InvalidSoftMatch means two objects contend for the same address; de-duplicate the source. (SC-300.)
Quick check
- In which of the five stores is the authoritative consolidated view of an identity held, and how are attributes flowed into and out of it?
- What exactly does Password Hash Sync send to the cloud, and can it be replayed against on-prem AD?
- You need to change how the default
In from AD - User Joinrule flows an attribute. What is the supported procedure, and why? - A filtering change caused 600 users to disappear from the tenant. Which attribute flipped, what did the export do, and how do you recover the users?
- What are the two operational obligations unique to Seamless SSO’s
AZUREADSSOACCaccount?
Answers
- The metaverse holds the authoritative consolidated view, keyed by the sourceAnchor. Inbound sync rules flow attributes from a connector space into the metaverse (CS→MV); outbound rules flow out toward the Entra connector space (MV→CS). Objects live in connector spaces on either side; the tenant and AD are the endpoints.
- It sends a PBKDF2 (HMAC-SHA256), per-user-salted hash of the NTLM hash — a hash of a hash. It is not the cleartext or the NTLM hash, is not reversible, and cannot be replayed against on-prem AD (which authenticates against the NTLM hash directly). It also enables ID Protection leaked-credential detection.
- Disable-and-clone: disable the Microsoft default (do not delete it), clone it, set the clone’s precedence to win where needed, and edit the clone. This is supported because upgrades can recreate default rules and silently discard inline edits to them.
cloudFilteredflipped toTrueon those metaverse persons; the next Export staged and pushed deletes, removing them from the tenant. Recover them from the Entra 30-day recycle bin (restore the soft-deleted users), then fix the filtering rule and runStart-ADSyncSyncCycle -PolicyType Initial, verifying no pending deletes remain.- (a) Protect it as a Tier-0 object — its Kerberos key is a key to silent sign-in for the tenant; (b) roll its Kerberos decryption key at least every 30 days with
Update-AzureADSSOForest, ideally on a schedule, or it becomes a stale-credential security finding.
Glossary
- Connector space (CS): A per-connector staging copy of a connected system’s objects — one for each AD forest and one for Entra — holding holograms plus pending changes.
- Metaverse (MV): The single, consolidated, authoritative view of every identity, keyed by the sourceAnchor; inbound rules flow attributes in, outbound rules flow them out.
- Run profile: A named engine operation (Delta/Full Import, Delta/Full Synchronization, Export) — nothing moves until one runs.
- Sync rule: A declarative rule with a direction, scope, join, and transformations that governs how objects and attributes flow; ordered by precedence.
- Precedence: A rule’s priority number; when two rules would set the same attribute, the lower number wins.
- Join: How a connector-space object matches its metaverse object (inbound), and how a metaverse object matches its cloud object (outbound).
- sourceAnchor: The immutable value linking one on-prem object to one cloud object for life; modern default is
ms-DS-ConsistencyGuid. - ImmutableID: The Base64-encoded form of the sourceAnchor stored on the cloud object; used in hard-matching.
cloudFiltered: A computed metaverse attribute; whenTrue, the object is not exported (and an existing cloud object is deleted).- PHS (Password Hash Sync): Validates passwords in the cloud against a PBKDF2-of-NTLM hash synced from AD; resilient default that enables leaked-credential detection.
- PTA (Pass-through Authentication): Validates passwords on-prem via lightweight agents; a runtime dependency at every sign-in requiring ≥3 agents for HA.
- Federation (AD FS): Redirects authentication to an on-prem AD FS farm that issues a trusted token; most capable, most operationally heavy.
- Seamless SSO: Silent Kerberos sign-in for domain-joined, corporate-network users via the shared
AZUREADSSOACCaccount key. AZUREADSSOACC: The AD computer account whose Kerberos decryption key backs Seamless SSO; a Tier-0 object whose key must be rolled every ≤30 days.- Staging mode: A second Connect server that imports and syncs (warm metaverse) but does not export or write back — the DR box, rule-test sandbox, and swing-upgrade target.
- Soft-match / hard-match: Automatic linking of a synced object to a pre-existing cloud object by shared SMTP/UPN (soft) vs manual linking via ImmutableID (hard).
Next steps
- Commit to the right engine first: Entra Connect Sync vs Cloud Sync: the architecture decision.
- Layer authentication policy on your synced identities with Conditional Access at scale: personas and authentication context.
- Turn on the leaked-credential and risk-based protections that PHS unlocks in Entra ID Protection: risk-based policies, tuning, and investigation.
- Extend identity flow across tenant boundaries with Entra cross-tenant synchronization for the multi-tenant org.
- Keep the source of truth recoverable with the Active Directory forest recovery runbook: backup and isolation.
- Give your automation and services cloud identities with the Entra managed identities deep dive.