M365 ● Sealed v1.0

CloudSync

Entra Cloud Sync Discovery - enumerates the modern lightweight provisioning

What it does

Microsoft ships two architecturally distinct directory-sync products that both set onPremisesSyncEnabled = true on user objects: - Azure AD Connect Sync (legacy) -> on-prem ADSync service (AADConnectHealthDiscovery) - Entra Cloud Sync (modern) -> lightweight provisioning agent (THIS module) Calls documented MS Graph endpoints and writes three CSVs: 1. GET /beta/onPremisesPublishingProfiles('provisioning')/agents?$expand=agentGroups -> CloudSyncAgents.csv (ProvisioningAgent rows) 2. GET /v1.0/servicePrincipals?$filter=applicationTemplateId eq '{AD2AAD|AAD2AD}' -> (pivot: SyncServicePrincipal rows; drives 3 & 4) 3. GET /beta/servicePrincipals/{id}/synchronization/jobs -> CloudSyncJobs.csv (SyncJob rows) 4. GET /beta/servicePrincipals/{id}/synchronization/templates -> CloudSyncTemplates.csv (SyncTemplate rows) Cloud Sync configuration service principals use fixed application templates: - AD -> Entra ID : 1a4721b3-e57f-4451-ae87-ef078703ec94 - Entra ID -> AD : fb81332f-3eca-4ecf-a939-4278e501d330 Pattern: identical to AzureIdentityDiscovery.psm1 (SPEC-106, shipped). Pagination, retry, and beta-URL handling are provided by Invoke-GraphAPIWithPaging (DiscoveryBase.psm1). Agents API is delegated-only per Graph docs (Policy.Read.HybridAuthentication); under app-only auth a 401/403 is recorded as AUTH_FAILURE for that section, and discovery continues with service-principal + sync-job enumeration (app permissions). Empty value arrays after a successful Graph call are honest EMPTY_RESULT ΓÇö never invented rows. Required Graph application permissions (primary path): - Application.Read.All / Directory.Read.All for Cloud Sync service principals - Synchronization.Read.All for synchronization jobs + templates Agents (optional / delegated): Policy.Read.HybridAuthentication Token acquisition scope: https://graph.microsoft.com/.default

How the app exposes it

The module runs through the ACQI discovery orchestrator and writes its rows into a dedicated results view. From there, conflicts, dependencies, and readiness scores feed the deal-wide consolidation layer.

Route in app:
/discovered/cloud-sync

Outputs

Each module emits a normalised CSV keyed by entity ID with readiness and risk scores, evidence-source counts, and last-seen timestamps. The exact column set varies by module — the app's results view shows the live schema.