← Back to articles Intune

Mastering Usage Location: Syncing On-Premises Active Directory Countries to Microsoft Entra ID

Mastering Usage Location: Syncing On-Premises Active Directory Countries to Microsoft Entra ID

In mature hybrid environments, the usageLocation attribute is the silent gatekeeper of the Microsoft 365 license lifecycle. Without a valid ISO 3166-1 alpha-2 country code assigned to a user object, Entra ID prevents license assignment, resulting in provisioning failures during automated workflows. Relying on manual cloud-side updates is a recipe for drift; the source of truth must reside in your on-premises Active Directory.

Critical Dependency Licensing and compliance policies (e.g., Data Residency) fail silently when usageLocation is null. Intune enrollment and Exchange Online mailbox creation can stall if this attribute is missing, regardless of your Group-Based Licensing configuration.
On-Prem AD Attribute: 'c' Entra Connect Sync Rules Engine Entra ID usageLocation
Data pipeline from local Active Directory 'c' attribute to Entra ID 'usageLocation'.

Architectural Implementation

To automate this, we modify the In from AD - User Common synchronization rule. We transform the c (Country) attribute into usageLocation using a direct mapping expression. If your AD c attribute stores full country names (e.g., "United States") instead of ISO codes ("US"), you must implement a lookup transformation in the sync rule.

  • Open Sync Rules Editor Launch the Synchronization Rules Editor on your Entra Connect server. Create a new "Inbound" rule with a higher precedence than the default "In from AD - User Common".
  • Define Transformation In the Transformations tab, add a direct flow:
    Target Attribute: usageLocation
    Source: c
    Merge Type: Update
  • Apply and Provision Run a delta synchronization cycle to apply the new rule without a full initial re-sync of every object: Start-ADSyncSyncCycle -PolicyType Delta. Use -PolicyType Initial only if the rule scoping filter itself has changed and existing connector space data must be re-evaluated.
  • Auditing and Remediation

    Before applying the sync rule, identify users currently missing the usageLocation attribute to avoid mass-triggering license assignment failures or compliance flags. This requires the Microsoft.Graph.Users module and a connection scoped with User.Read.All.

    try {
        # Ensure required module is available
        if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Users)) {
            throw "Required module 'Microsoft.Graph.Users' is not installed. Run: Install-Module Microsoft.Graph -Scope CurrentUser"
        }
    
        # Connect with the required read scope (uses existing context if already connected with sufficient scope)
        $context = Get-MgContext
        if (-not $context -or ($context.Scopes -notcontains "User.Read.All")) {
            Connect-MgGraph -Scopes "User.Read.All" -NoWelcome -ErrorAction Stop
            $context = Get-MgContext
        }
    
        if (-not $context -or ($context.Scopes -notcontains "User.Read.All")) {
            throw "Unable to establish a Microsoft Graph session with the required 'User.Read.All' scope."
        }
    
        # Audit enabled users with a missing usageLocation attribute
        $usersMissingLocation = Get-MgUser -Filter "usageLocation eq null and accountEnabled eq true" `
            -ConsistencyLevel eventual -CountVariable userCount `
            -Property "displayName,userPrincipalName,usageLocation" `
            -All `
            -ErrorAction Stop |
            Select-Object DisplayName, UserPrincipalName, UsageLocation
    
        if (-not $usersMissingLocation) {
            Write-Output "No enabled users found with a missing usageLocation attribute."
        }
        else {
            $count = @($usersMissingLocation).Count
            Write-Output "Found $count enabled user(s) with a missing usageLocation attribute:"
            $usersMissingLocation
        }
    }
    catch {
        Write-Error "Failed to audit users for missing usageLocation: $($_.Exception.Message)"
    }
    Pro Tip Filtering on a null property requires -ConsistencyLevel eventual combined with -CountVariable, otherwise Graph will reject the advanced query. If you are moving to a Cloud-Only lifecycle for specific identities, ensure your sync rules are scoped to exclude them, otherwise Entra Connect will overwrite any manual usageLocation changes you make via Graph API on the next sync cycle.

    API Reference: Property Mapping

    Attribute Source Requirement
    c On-Prem AD Required
    usageLocation Entra ID Required
    co On-Prem AD Optional

    Troubleshooting Sync Failures

    If the attribute isn't flowing, check the Metaverse object via the Synchronization Service Manager. If the Metaverse attribute usageLocation is populated but the cloud attribute is not, you have a connector-space permission issue or a throttling event on the Azure AD Connector export step.

    Warning: Synchronization Loops Do not map usageLocation back to on-premises AD via Writeback unless you have a strict schema governance policy. Writing cloud values back to AD often triggers a circular sync loop if the AD attribute is used as the authoritative source for other internal systems.

    For large-scale remediation of existing users whose synchronization rule has not yet been deployed, use the following interim script. This bridges the gap by reading the AD c attribute directly and writing it to Entra ID via Graph, and should be retired once the sync rule transformation is live:

    # Interim bulk remediation: set usageLocation for a specific regional OU/value
    # Requires the ActiveDirectory module (RSAT) and Microsoft.Graph.Users
    
    function Invoke-BulkUsageLocationRemediation {
        [CmdletBinding()]
        param(
            [string]$CountryCode = "US"
        )
    
        try {
            # Ensure ActiveDirectory module (RSAT) is available
            if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
                Write-Error "Required module 'ActiveDirectory' is not installed. Install RSAT with: Add-WindowsCapability -Online -Name 'Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0'"
                return
            }
            Import-Module ActiveDirectory -ErrorAction Stop
    
            # Ensure Microsoft.Graph.Users module is available
            if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Users)) {
                Write-Error "Required module 'Microsoft.Graph.Users' is not installed. Run: Install-Module Microsoft.Graph -Scope CurrentUser"
                return
            }
            Import-Module Microsoft.Graph.Users -ErrorAction Stop
    
            # Connect with the required write scope, avoiding WAM interactive issues in headless/embedded terminals
            $context = Get-MgContext
            if (-not $context -or ($context.Scopes -notcontains "User.ReadWrite.All")) {
                Connect-MgGraph -Scopes "User.ReadWrite.All" -UseDeviceCode -NoWelcome -ErrorAction Stop
                $context = Get-MgContext
            }
    
            if (-not $context -or ($context.Scopes -notcontains "User.ReadWrite.All")) {
                throw "Unable to establish a Microsoft Graph session with the required 'User.ReadWrite.All' scope."
            }
    
            # Retrieve on-prem AD users in the target region (country code parameterized)
            $users = Get-ADUser -Filter "c -eq '$CountryCode'" -Properties c, UserPrincipalName -ErrorAction Stop
    
            if (-not $users) {
                Write-Output "No on-premises AD users found matching country code '$CountryCode'."
                return
            }
    
            foreach ($user in $users) {
                if ([string]::IsNullOrWhiteSpace($user.UserPrincipalName)) {
                    Write-Warning "Skipping user '$($user.SamAccountName)': missing UserPrincipalName."
                    continue
                }
    
                try {
                    Update-MgUser -UserId $user.UserPrincipalName -UsageLocation $CountryCode -ErrorAction Stop
                    Write-Output "Updated usageLocation for $($user.UserPrincipalName)."
                }
                catch {
                    Write-Error "Failed to update $($user.UserPrincipalName): $($_.Exception.Message)"
                }
            }
        }
        catch {
            Write-Error "Bulk remediation failed: $($_.Exception.Message)"
        }
    }
    
    Invoke-BulkUsageLocationRemediation -CountryCode "US"

    Was this article helpful?

    🎓 Ready to go deeper?

    Practice real MD-102 exam questions, get AI feedback on your weak areas, and fast-track your Intune certification.

    Start Free Practice → Book a Session
    Souhaiel Morhag
    Souhaiel Morhag
    Microsoft Endpoint & Modern Workplace Engineer

    Souhaiel Morhag is a Microsoft Intune and endpoint management specialist with hands-on experience deploying and securing enterprise environments across Microsoft 365. He founded MSEndpoint.com to share practical, real-world guides for IT admins navigating Microsoft technologies — and built the MSEndpoint Academy at app.msendpoint.com/academy, a dedicated learning platform for professionals preparing for the MD-102 (Microsoft 365 Endpoint Administrator) certification. Through in-depth articles and AI-powered practice exams, Souhaiel helps IT teams move faster and certify with confidence.

    Related Articles

    Popular on MSEndpoint