Identity Azure

Microsoft Entra Connect Sync Deep Dive: Designing Hybrid Identity with PHS, PTA, and Seamless SSO

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 the ADSync PowerShell 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:

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 ]
# 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:

  1. AZUREADSSOACC is 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.
  2. 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 precedencelower 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:

  1. Open the Synchronization Rules Editor.
  2. Find the default inbound rule (e.g., In from AD - User Join) and click Disable — do not delete it (the engine recreates deleted defaults).
  3. 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-ADSyncAADPasswordSyncConfigurationEnabled=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

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

  1. 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?
  2. What exactly does Password Hash Sync send to the cloud, and can it be replayed against on-prem AD?
  3. You need to change how the default In from AD - User Join rule flows an attribute. What is the supported procedure, and why?
  4. 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?
  5. What are the two operational obligations unique to Seamless SSO’s AZUREADSSOACC account?

Answers

  1. 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.
  2. 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.
  3. 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.
  4. cloudFiltered flipped to True on 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 run Start-ADSyncSyncCycle -PolicyType Initial, verifying no pending deletes remain.
  5. (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

Next steps

Entra IDHybrid IdentityEntra ConnectPHSPTASeamless SSOSync RulessourceAnchor
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading