HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links Subscribe free
← Back to Blog
Entra ID Entra Connect SyncAzure AD ConnectADSyncHybrid IdentityPowerShell

Your Classic Entra Connect Sync Server Stopped Exporting — and Cloud Sync Monitoring Won't Catch It

IA
Imran Awan
31 July 2026

A quick scope note first, because there are two products with confusingly similar names. This post is about classic Microsoft Entra Connect Sync — the older, heavyweight on-premises sync engine formerly called Azure AD Connect, the one with a full SQL database, the Synchronization Service Manager desktop tool, and the ADSync PowerShell module. It is not about modern Entra Cloud Sync, the lightweight agent Microsoft is steering everyone toward. The sibling post on this blog, Your Entra Cloud Sync Job Has Been Failing Quietly for Three Weeks, covers the modern engine, and it can lean on a clean Microsoft Graph API to read job health. Classic Connect Sync has no such surface. That difference is the entire reason this post needs a different approach.

Here is the situation this is really about. Your team did the modern thing: your primary forest moved to Entra Cloud Sync, and you built exactly the Graph-based monitoring from that sibling post, and the Cloud Sync dashboard is a reassuring wall of green. But there is a second directory — an acquired company, a legacy resource forest, a domain nobody wants to touch — and it still syncs through a classic Entra Connect Sync server that predates the Cloud Sync rollout. Nobody monitors that box, because there is no dashboard for it in the place everyone looks. And one quiet afternoon, it stops exporting.

The problem — imports keep running, the portal looks fine, and nothing reaches Entra ID

An engineer RDPs into that ageing Connect Sync server to check a setting, opens the Microsoft Entra Connect wizard, clicks through a couple of screens, and closes it. Or a scheduled version upgrade half-completes and rolls back. Or, months ago, someone stood the box up as a standby during a migration and ticked staging mode, intending to promote it later, and then the project ended and the ticket was closed. Any of these can leave the server in a state where the scheduler is still running — still importing from Active Directory, still running synchronisation — but no longer exporting anything to Entra ID.

Nothing about this looks broken from the cloud side. The tenant is healthy. Sign-ins work. Licensing is untouched. The Cloud Sync dashboard for your primary forest is still green, because that is a completely different engine. Meanwhile, in the legacy domain, a manager gets a new job title in HR, it flows into Active Directory that night, Connect Sync imports it, synchronises it internally… and then it sits there. It is never written up to Entra ID, because exports are not running. Three weeks later a helpdesk ticket lands: "Why does the org chart in Teams still show my old title?" and the agent who picks it up has no idea that an on-premises sync engine two acquisitions removed from their daily work has quietly gone read-only.

Why the portal can't warn you: classic Entra Connect Sync keeps its scheduler configuration, connector state, and run history in an on-premises SQL database and surfaces them through the Synchronization Service Manager desktop app and the ADSync PowerShell module. Unlike Cloud Sync, there is no documented Graph job-status endpoint to query, script, or alert on centrally. If you want to know whether Connect Sync is genuinely exporting, you have to ask the server itself. That constraint shapes everything below — it is why this audit runs locally on the sync server rather than against Graph.

Why it happens — the scheduler is always running, but "running" doesn't mean "exporting"

Microsoft Entra Connect Sync drives synchronisation through a built-in scheduler that, by default, runs a cycle every 30 minutes. The critical thing to understand is a line straight from Microsoft's documentation: "The scheduler itself is always running, but it can be configured to only run one or none of these tasks." A synchronisation cycle is three phases — import, sync, export — and the scheduler can be in a state where the first two happen and the third does not. That is exactly the failure that hides so well: the process is alive, the server is busy, CPU graphs look normal, and yet the one phase that actually changes anything in Entra ID is switched off.

You read the scheduler's real state with a single cmdlet, Get-ADSyncScheduler. Four of its properties are where silent failures live:

There is a second class of failure that happens even when exports are running: the export completes, but with errors. A connector account that lost a permission after an AD delegation change, a duplicate proxyAddresses value, an object that fails validation — each produces a run that finishes with a result like completed-export-errors rather than success. Those errors pile up in the Operations tab of the Synchronization Service Manager, which is precisely the tool nobody opens on a server nobody monitors. The diagram below is the whole problem in one picture.

A sync cycle when the server is in staging mode
On-prem AD Import running Sync running Export SUPPRESSED Entra ID never updated StagingModeEnabled = True stops here
The staging-mode gotcha that compounds it: Microsoft's guidance is that a delta sync must run at least once every 7 days, "This also applies to servers in Staging mode." A box that has sat in staging mode for weeks is doubly bad: it exported nothing the whole time, and when you finally promote it you will likely need a full synchronisation to recover, because the 7-day window lapsed. Staging mode is a legitimate, supported feature for standby and disaster recovery — the failure is a server left in it by accident with nobody watching.
Do not "just flip the switches back" blind. Disabling staging mode makes the server start exporting and resume password hash sync from its last watermark; if it has been idle a long time, that catch-up can run for hours, and Microsoft explicitly warns not to restart the sync services during catch-up. And remember the wider clock: Microsoft has stated that Entra Connect Sync must be on version 2.5.79.0 or later, or all synchronization services stop working on 30 September 2026. Understand the server's state, and its version, before you change anything.

How to verify — one command on the server, before you trust any script

Before running any audit tooling, prove the check by hand on one server you understand. RDP to the Entra Connect Sync server, open an elevated Windows PowerShell session, and run two cmdlets. If Get-ADSyncScheduler is not recognised, load the module first with Import-Module ADSync — Microsoft notes this is needed on a domain controller or a server with a higher PowerShell restriction level than default.

Windows PowerShell (Administrator) — on the Connect Sync server
# Load the module if the cmdlet isn't available, then read the scheduler state Import-Module ADSync Get-ADSyncScheduler AllowedSyncCycleInterval : 00:30:00 CurrentlyEffectiveSyncCycleInterval : 00:30:00 CustomizedSyncCycleInterval : NextSyncCyclePolicyType : Delta NextSyncCycleStartTimeInUTC : 31/07/2026 09:14:07 PurgeRunHistoryInterval : 7.00:00:00 SyncCycleEnabled : True MaintenanceEnabled : True StagingModeEnabled : True # <-- exports are suppressed SchedulerSuspended : False

That one highlighted line is the whole story. The scheduler is enabled, maintenance is enabled, the interval is the healthy default of 30 minutes, the next cycle is scheduled — everything screams "healthy" except StagingModeEnabled : True, which quietly means this server has not written a single change to Entra ID since it entered that state. You can confirm the engine is genuinely ticking over with Get-ADSyncConnectorRunStatus, which returns nothing when the engine is idle and the running connector's name when a cycle is in progress.

The second thing to check by hand is the run history, because a server can be exporting and still failing. In the Synchronization Service Manager, the Operations tab is where every run and its result is listed. This is what a connector that is exporting with errors looks like — the run finished, but not with success:

Synchronization Service Manager — Operations tab (recent runs)
ConnectorProfileStatusSync Errors
contoso-legacy.localDelta Importsuccess0
contoso-legacy.localDelta Syncsuccess0
contoso.com – Microsoft Entra IDExportcompleted-export-errors3
Import and sync are clean; the Export to Entra ID keeps completing with 3 object errors. Those objects are silently stale until the underlying cause (often a connector-account permission or a duplicate attribute) is fixed.
Everything here is read-only. Get-ADSyncScheduler, Get-ADSyncConnectorRunStatus, and the Operations tab only report state. None of them change the scheduler, promote the server, or touch a single object. The companion script below holds to the same rule: it audits and reports, and it never remediates.

The fix — Get-EntraConnectSyncHealth.ps1

Manually opening PowerShell and the Operations tab on every legacy Connect Sync server, on every check-in, does not scale and does not survive being forgotten. The companion script does the same two checks programmatically and returns a clear exit code you can wire into your own scheduled task or monitoring. Because classic Connect Sync has no Graph surface, this script runs locally on the sync server itself, using the ADSync module. It needs that module present (it installs with Entra Connect Sync) and an elevated, local-administrator session. There is no tenant authentication and no Graph scope, because there is nothing in Graph to authenticate to.

Download the script — GitHub

Download Get-EntraConnectSyncHealth.ps1 from the Imran76Awan/Daily-Tasks repository on GitHub — no sign-in required. It is read-only and cannot change anything in your tenant — but always validate any script in your own environment before you rely on it.

Get-EntraConnectSyncHealth.ps1 View full repo →

The script does two things and reports. First it reads Get-ADSyncScheduler and flags a disabled sync cycle, a suspended scheduler, a server in staging mode (unless you pass -AllowStagingMode for a deliberate standby), and an over-long effective interval. Then it walks each connector from Get-ADSyncConnector and inspects the recent runs from Get-ADSyncRunProfileResult, flagging any run whose Result is not success. Here is the scheduler-check core:

Get-EntraConnectSyncHealth.ps1 — scheduler evaluation (excerpt)
$sched = Get-ADSyncScheduler -ErrorAction Stop if ($sched.SyncCycleEnabled -eq $false) { Add-Finding -Check 'SyncCycleEnabled' -Severity 'High' ` -Detail 'Sync cycle is DISABLED. Import, sync and export are not running.' } if ($sched.SchedulerSuspended -eq $true) { Add-Finding -Check 'SchedulerSuspended' -Severity 'High' ` -Detail 'Scheduler is SUSPENDED - a half-finished upgrade can leave it here.' } if ($sched.StagingModeEnabled -eq $true -and -not $AllowStagingMode) { Add-Finding -Check 'StagingModeEnabled' -Severity 'High' ` -Detail 'Server is in STAGING MODE - imports and syncs run but NOTHING exports to Entra ID.' }

The connector check is where a naive script quietly lies to you. Get-ADSyncRunProfileResult returns run objects whose status lives on a Result property; the script reads that property defensively, and if the object shape is not what it expects it raises an error and refuses to declare the server healthy rather than guessing. Anything that is not the literal string success is surfaced, with results containing error treated as high severity. Two switches tune it for real estates: -AllowStagingMode tells it that a given box is a deliberate, documented standby so staging mode is expected rather than a finding, and -LookbackRuns controls how many recent runs per connector it inspects. -ExportCsv writes every finding to a timestamped CSV, so you have evidence to attach to a change ticket rather than a console screenful you have to retype.

Run it on the drifted server and it reads the scheduler, walks the connectors, and prints a verdict. On the box that slipped into staging mode and is also carrying export errors, it returns exit code 2:

Get-EntraConnectSyncHealth.ps1 — unhealthy server
[09:14:07] [INFO ] Entra Connect Sync health audit starting on ADCONNECT-LEG01 [09:14:07] [INFO ] ADSync module loaded (querying the local sync engine, not Microsoft Graph). [09:14:07] [INFO ] --- Scheduler configuration (Get-ADSyncScheduler) --- [09:14:07] [INFO ] SyncCycleEnabled : True [09:14:07] [INFO ] StagingModeEnabled : True [09:14:07] [INFO ] SchedulerSuspended : False [09:14:07] [INFO ] CurrentlyEffectiveSyncCycleInterval : 00:30:00 [09:14:07] [PASS ] SyncCycleEnabled is True [09:14:07] [PASS ] SchedulerSuspended is False [09:14:07] [FAIL ] StagingModeEnabled: Server is in STAGING MODE (StagingModeEnabled=True). Import and sync run but NOTHING is exported to Entra ID. [09:14:08] [INFO ] --- Connector run-profile results (last 5 runs per connector) --- [09:14:08] [PASS ] contoso-legacy.local / Delta Import: success [09:14:08] [PASS ] contoso-legacy.local / Delta Synchronization: success [09:14:08] [FAIL ] ConnectorRunResult: contoso.com - Microsoft Entra ID / Export last result 'completed-export-errors'. [09:14:08] [INFO ] --- RESULT --- [09:14:08] [FAIL ] UNHEALTHY - 2 finding(s). Classic Connect Sync may be importing and syncing while exporting nothing, or accumulating run errors. # Exit code: 2

The exit codes are deliberately simple so you can act on them from a scheduled task or a monitoring probe: 0 means healthy with no findings, 2 means findings were detected, and 1 is reserved for the script failing to do its job — not elevated, the ADSync module missing, or a query throwing. That last distinction matters. The script never prints a clean bill of health after a query failed; if it could not read the scheduler or a connector's runs, it says so and exits 1 rather than misleading you with a reassuring "0 findings". A monitoring script that can go quiet in exactly the situation you built it to catch is worse than no script at all.

Proof it worked — disable staging, run a full sync, and confirm the actual object

Remediation for the staging-mode case is not a PowerShell one-liner — it is done through the Microsoft Entra Connect wizard's "Configure staging mode" flow, unticking staging mode after confirming no other server is actively syncing that forest (only one active Connect Sync server is supported per configuration). Because this box sat in staging longer than the 7-day window, the safe follow-up is a full cycle rather than a delta, which you trigger from PowerShell:

Windows PowerShell (Administrator) — after disabling staging mode
# A full cycle is prudent because the 7-day delta window had lapsed in staging Start-ADSyncSyncCycle -PolicyType Initial # then re-run the audit .\Get-EntraConnectSyncHealth.ps1 [15:02:11] [INFO ] Entra Connect Sync health audit starting on ADCONNECT-LEG01 [15:02:11] [PASS ] StagingModeEnabled is False [15:02:11] [PASS ] SyncCycleEnabled is True [15:02:11] [PASS ] SchedulerSuspended is False [15:02:12] [PASS ] contoso.com - Microsoft Entra ID / Export: success [15:02:12] [PASS ] HEALTHY - scheduler is enabled, not suspended, not stuck in staging mode, interval is sane, and recent connector runs succeeded. # Exit code: 0

As with the Cloud Sync sibling post, a green run is necessary but not sufficient. The scheduler being healthy tells you the engine is exporting again; it does not by itself prove the specific object that was stuck — the manager's title change — actually made it across. Close the loop by checking that object directly in Entra ID:

PowerShell 7 — confirming the specific object updated in Entra ID
Get-MgUser -UserId "j.okafor@contoso.com" -Property displayName,jobTitle | Format-List DisplayName : Jhalak Okafor JobTitle : Head of Logistics (updated)
Make it continuous, not a one-off. Schedule Get-EntraConnectSyncHealth.ps1 as a daily Windows Task on each legacy Connect Sync server and act on exit code 2, and pair it with Microsoft Entra Connect Health for sync, the native service that alerts on sync errors and, from client version 2.5.79.0 and later, produces an object-level synchronization error report categorised by cause (duplicate attribute, data mismatch, and so on). The script is your on-server, no-dependencies point check; Connect Health is your tenant-side alerting. Until this forest is migrated to Cloud Sync, run both.

References

The irony worth naming: the sync engine Microsoft is retiring is the one with the worst native central visibility. Classic Connect Sync will keep running many hybrid estates for a while yet, and every one of those servers is a place where exports can quietly stop with nothing in the cloud to warn you. Audit them locally until they are gone.
Share this post
LinkedIn X / Twitter Reddit Bluesky

More from EndpointWeekly

Entra ID
Your Entra Cloud Sync Job Has Been Failing Quietly for Three…
Hybrid sync errors pile up silently until a helpdesk ticket arrives weeks later. Here's…
Entra ID
Zero Reviewers Responded, So Entra Auto-Approved a Departed Admin
An Entra access review whose deadline passes with no responses can auto-apply a default…
Entra ID
Group-Based Licensing Fails Silently for Some Users — Here's How…
Assign Microsoft 365 licences to a security group and for some members the assignment…