Exchange Online Get-Contact and Set-Contact Updates: Admin Guide for Non Mail Contacts

  • Thread Author
Headline
Updates to Get-Contact and Set-Contact in Exchange Online — What admins must know (announcement, impact, detection, remediation, and migration guidance)
Summary (TL;DR)
  • Microsoft announced on Oct 7, 2025 that Exchange Online will stop returning or allowing management of Contact (non-mail‑enabled) recipient type objects via Get-Contact and Set-Contact starting December 15, 2025.
  • MailContact (mail‑enabled contacts with SMTP/external addresses) are NOT affected and will continue to be managed as before.
  • Impact is limited to organization-level Contact recipient objects (often legacy objects synced from on‑premises AD). Personal Outlook contacts are unaffected.
  • Action for most tenants: none. Action for a small set of tenants that still have Contact recipient type objects: audit, update scripts (to explicitly target MailContact), and choose a remediation path (mail-enable, convert, delete, or manage on‑prem).
  • This article explains detection methods, real-world admin guidance, safe PowerShell examples (audit, export, migration helpers), on‑prem sync considerations, and recommended timelines and testing steps.
Background — what Microsoft announced and why it matters
On October 7, 2025 the Exchange Online team published an announcement that, effective December 15, 2025, the Get-Contact and Set-Contact cmdlets in Exchange Online will no longer return or allow management of recipient objects whose RecipientType is Contact (that is, “vanilla” contacts without SMTP/external email). The announcement clarifies:
  • The change is limited to organization-level Contact recipient objects managed by Exchange Online cmdlets.
  • MailContact recipient objects (mail‑enabled contacts with an external SMTP address) are not affected and remain fully supported.
  • The Exchange team views Contact recipient objects as legacy and nonfunctional in Exchange Online (they are not mail‑enabled, have no SMTP address, cannot be created directly in Exchange Online, and typically exist due to historical on‑premises syncs).
  • Microsoft’s analysis shows very few tenants use the cmdlets to manage Contact (non‑mail) objects; however, tenants that do will need to take steps if they require these objects beyond Dec 15, 2025.
Why Microsoft is making this change (brief)
  • Simplification/modernization of the Exchange Online directory and cmdlet surface.
  • Contact recipient objects without SMTP have no functional mail role in Exchange Online.
  • Low usage by tenants, and large majority unaffected.
Important dates (absolute)
  • Announcement published: October 7, 2025.
  • Change effective / enforcement in Exchange Online: December 15, 2025.
    (If you are reading this after those dates, treat them as the public schedule Microsoft announced.)
High-level impact summary for admins
  • Get-Contact and Set-Contact will continue to work for MailContact objects (contacts with SMTP / mail-enabled).
  • Get-Contact | Where-Object { $_.RecipientType -eq "Contact" } will return nothing after Dec 15, 2025; Set-Contact will not be able to manage such Contact objects in Exchange Online after that date.
  • Automation or scripts that specifically expect RecipientType "Contact" from Get-Contact will break/return no objects.
  • Objects synced from on‑premises AD (via Azure AD Connect / hybrid) that are authoritative on-prem must be handled at the on‑prem source to remain manageable.
  • Personal user contacts stored in Outlook clients (user contact folders) are unaffected.
Who needs to care
  • Tenants that have organization-level Contact recipient objects (i.e., contact objects in Azure AD / Exchange where RecipientType = Contact and no SMTP address exists).
  • Administrators who have scripts or tooling that enumerate or modify Contact recipient type objects using Get-Contact/Set-Contact.
  • Hybrid environments where contact objects are synchronized from on‑premises and are intentionally non-mail-enabled for an internal purpose (rare).
How to identify whether your tenant is affected — detection and inventory
Run these audits in Exchange Online PowerShell (connect first to Exchange Online):
1) Quick check — show any non-mail-enabled Contacts
Get-Contact | Where-Object { $_.RecipientType -eq "Contact" }
  • If this returns nothing, you do not have organization-level Contact recipient objects and you’re not impacted.
  • If it returns objects, collect details and proceed with inventory and plan.
2) More complete inventory and export to CSV

On-prem to cloud Exchange Online sync with a safety checklist and MailContact objects.connect to Exchange Online PowerShell first​

$contacts = Get-Contact | Where-Object { $_.RecipientType -eq "Contact" }
$contacts | Select-Object Name, DisplayName, Identity, RecipientType, DistinguishedName, ExternalEmailAddress, WhenCreated | Export-Csv -Path "C:\temp\ContactRecipientTypeInventory.csv" -NoTypeInformation
Notes:
  • ExternalEmailAddress for Contact objects is expected to be $null (they are non‑mailable). MailContact objects will show ExternalEmailAddress.
  • The Identity and DistinguishedName help you determine whether the object is cloud-only or synced from on‑prem.
3) Cross-check with Get-Recipient / Get-MailContact
  • If you want a list of mail-enabled contacts:
    Get-MailContact
    or
    Get-Recipient -RecipientType MailContact
  • You can use that to compare MailContact vs Contact sets.
4) If you are a hybrid tenant (Azure AD Connect)
  • Query Azure AD to see if the objects are present there and whether they are synchronized from on‑prem:
    (Get-MsolContact or Get-AzureADContact / Microsoft Graph queries) depending on your modules. (If you use Azure AD Connect, authoritative changes should typically be done on-prem.)
Practical detection script (audit + dry run report)
This script enumerates Contact recipient objects and summarizes counts by source; it writes a CSV and a short report.

Audit script (run in Exchange Online PowerShell)​

$report = [System.Collections.Generic.List[psobject]::new()
$contacts = Get-Contact | Where-Object { $_.RecipientType -eq "Contact" }
foreach ($c in $contacts) {
$isSynced = if ($c.DirectoryObjectId -and $c.IsDirSynced) { $true } else { $false } # property availability varies
$report.Add([pscustomobject]@{
Name = $c.Name
Identity = $c.Identity
DisplayName = $c.DisplayName
RecipientType = $c.RecipientType
ExternalEmailAddress = $c.ExternalEmailAddress
IsSynchronizedFromOnPrem = $isSynced
WhenCreated = $c.WhenCreated
})
}
$report | Export-Csv -Path 'C:\temp\ContactRecipientTypeInventory.csv' -NoTypeInformation
$report.Count
Write-Output "CSV written to C:\temp\ContactRecipientTypeInventory.csv"
(Adapt $c.IsDirSynced / DirectoryObjectId checks to the properties returned in your environment.)
Assessment and decision matrix
For each Contact object discovered, decide which of these applies:
A) Unused / orphan / legacy — safe to delete in Exchange Online (or remove on‑prem if synced).
B) Used only for directory/reference but should be mail‑enabled — convert to MailContact (i.e., give it an external SMTP/ExternalEmailAddress) or recreate it as MailContact and remove the Contact.
C) Authoritative on‑prem — make planned changes on-prem and let Azure AD Connect replicate (do not modify cloud-only if the object is on‑prem authoritative).
D) Required for a custom app or unique scenario — document and raise feedback with Microsoft (Exchange team invited feedback in the announcement).
Remediation options — pros/cons and examples
Option 1 — Convert or replace with MailContact (recommended when the object should be mail‑enabled)
  • If a Contact should be mail‑enabled, create a MailContact (New-MailContact) with a valid ExternalEmailAddress, preserve attributes, move any references, then remove the Contact (or disable it).
  • If the Contact came from on‑prem, perform the change on-prem (mail-enable the on‑prem contact or create on‑prem mail contact) and let sync flow.
Example: create MailContact from Contact inventory CSV (safe pattern)

Read CSV created during inventory​

$csv = Import-Csv -Path 'C:\temp\ContactRecipientTypeInventory.csv'
foreach ($row in $csv) {

Ask for confirmation or map to a real external address first. This example assumes you have a mapping or the external address.​

Code:
$external = Read-Host "Provide external SMTP address for $($row.DisplayName) (or press Enter to skip)"
if ($external) {
    # Create MailContact (run with appropriate permissions)
    New-MailContact -Name $row.DisplayName -ExternalEmailAddress $external -OrganizationalUnit "Contacts" -FirstName "" -LastName "" -Alias ($row.Name -replace '\s','') -WhatIf
    # Remove -WhatIf after validating
} else {
    Write-Output "Skipping $($row.DisplayName) - no external address provided."
}
}
Caveats:
  • New-MailContact cannot “convert” an existing Contact in Exchange Online if the object is on‑prem authoritative; you must do the change on-prem.
  • Preserve attributes you need (custom attributes, notes) by exporting/importing or using Set-MailContact after creation.
Option 2 — Remove the Contact (if unused)
  • If a Contact is unused, remove it. If it’s coming from on‑prem, delete/modify it on‑prem instead to prevent reappearance after sync.
Example (CAUTION — destructive)

Delete cloud-only Contact (double-check Identity!)​

Remove-Contact -Identity "CN=LegacyContact,OU=Contacts,DC=contoso,DC=com" -Confirm:$true
Option 3 — Manage authoritative source on-premises
  • If the object is synchronized from on‑premises AD, change the on‑prem object to a MailContact (mail-enable it) or remove it; Azure AD Connect will then replicate the changed state.
  • Typical steps on an Exchange on‑prem server: use Enable-MailContact or other Exchange on‑prem cmdlets to mail‑enable the AD contact.
Option 4 — Keep object in on‑premises AD but stop using Exchange cmdlets for it
  • This is not recommended for long-term; if Exchange Online no longer surfaces Contact recipient types, those objects lose manageability via Exchange Online cmdlets and should be managed on-prem.
Script-safe patterns and recommended safeguards
  • Always run with -WhatIf / -Confirm on destructive commands.
  • Export current state to CSV before any changes (backup).
  • Test changes on a small subset or lab tenant before running wide-scale.
  • If objects are synced from on‑prem, do the work on-premine to avoid sync friction.
  • Keep a mapping CSV of original Contact identity -> new MailContact identity for rollback and auditing.
Update automation and scripts (what breaks and how to fix)
Common automation issues:
  • Scripts that use Get-Contact and assume some objects will be returned may find empty results after Dec 15, 2025.
  • Scripts that check RecipientType to find Contacts will be affected if they expect "Contact".
Recommended script changes:
  • If your script is meant to operate on mail-enabled contacts, switch to Get-MailContact or Get-Recipient -RecipientType MailContact.
    Example:

Previously:​

$contacts = Get-Contact | Where-Object { $_.RecipientType -eq "Contact" }

If you meant mail contacts, change to:​

$mailContacts = Get-MailContact
  • If your script is intended to find all directory contacts irrespective of mail status, change logic to check both MailContact and Contact (pre-change) and then adapt after enforcement:

Pre‑change (dual approach)​

$allContacts = @(Get-MailContact) + @(Get-Contact | Where-Object { $_.RecipientType -eq "Contact" })

After change (post‑Dec 15, 2025) you'll only get Get-MailContact results​

  • Defensive coding pattern:
    Try {
    $mailContacts = Get-MailContact -ResultSize Unlimited
    } Catch {
    Write-Warning "Unable to enumerate mail contacts: $_"
    }

Do not rely on Get-Contact for mail-enabled lists.​

On-premises + Azure AD Connect considerations
  • If the Contact objects are synchronized from on‑premises AD via Azure AD Connect, the authoritative location is on‑prem. You must update or remove the object on-prem to stop it being an issue in Exchange Online.
  • Typical on-prem remediation:
  • Mail-enable the AD contact (using on‑prem Exchange tools) so it becomes MailContact upon sync, or
  • Delete/disable the on‑prem object to remove it from the cloud, or
  • Update attributes to reflect desired state, then let Azure AD Connect replicate.
Testing plan (recommended)
1) Inventory stage (now): run detection scripts and export CSV.
2) Script review: identify any automation that relies on RecipientType == "Contact" or on Get-Contact returning non-mail objects.
3) Pilot: in a test tenant or a small group of non-production objects, perform remediation (convert to MailContact or remove).
4) Validation: update scripts to use Get-MailContact where appropriate; re-run automated tasks against pilot objects.
5) Rollout: run full remediation for chosen path (mail-enable, recreate as MailContact, delete) after backups and approvals.
6) Post-change monitoring: check Message center for any tenant-specific notices from Microsoft.
Migration recipes — practical examples
A) Bulk re-create Contact as MailContact using a CSV mapping
  • Use the inventory CSV to provide mapping from Name -> ExternalEmailAddress.
  • Create MailContact objects (New-MailContact) with -ExternalEmailAddress, verify, then Remove-Contact for the original (if cloud-only).
  • Keep a log of old Identity -> new MailContact Identity.
B) If no external address exists but a placeholder is needed
  • Avoid creating MailContact with fake addresses unless you have a legitimate external address. It’s better to document the object and delete or manage on-prem.
C) When objects are on-prem authoritative
  • Use on-prem Exchange to mail-enable the contact (Enable-MailContact) so that when Azure AD Connect syncs the object, it’s mail-enabled in Exchange Online as MailContact.
Impact analysis — what to expect after December 15, 2025
  • Get-Contact and Set-Contact: will no longer show or manage Contact recipient type objects in Exchange Online.
  • MailContact management: unaffected.
  • Admin scripts that explicitly target Contacts will either return no data or fail if they rely on attributes only present on Contact objects.
  • Directory-integrated apps that depend on organization-level Contact recipient objects should be reviewed.
  • Tenants with hybrid sync must ensure the authoritative source is updated to prevent objects from becoming unmanaged in the cloud.
Risk mitigation and rollback
  • Always export current state and create backups of any data you will change or delete.
  • Use -WhatIf when running New-MailContact/Remove-Contact to preview changes.
  • Keep a rollback plan: if MailContact creation is not successful, you can remove created MailContact and preserve the original Contact until verified (but be mindful of on-prem sync).
  • For on‑prem authoritative objects, do changes on-prem to avoid transient states in Azure AD.
Operational checklist (recommended steps for admins)
1) By Oct 31, 2025 — run inventory & CSV export for Contact recipient type objects.
2) By Nov 7, 2025 — review scripts and automation; update to explicitly reference MailContact if appropriate.
3) By Nov 21, 2025 — plan remediation per object (mail-enable, recreate, delete, or manage on-prem).
4) By Dec 8, 2025 — run pilot remediation in controlled set with validation and rollback checks.
5) Dec 15, 2025 — change enforced in Exchange Online; monitor automation and production systems.
6) Dec 16–31, 2025 — remediate any discovered breakage and report issues to Microsoft through normal support channels if needed.
Suggested PowerShell snippets (clean, production-ready patterns)
A) Detection + export (safe)
$inventory = Get-Contact | Where-Object { $_.RecipientType -eq "Contact" } | Select-Object Name,DisplayName,Identity,DistinguishedName,WhenCreated,ExternalEmailAddress
$inventory | Export-Csv -Path "C:\temp\ContactRecipientTypeInventory.csv" -NoTypeInformation
Write-Output "Found $($inventory.Count) Contact recipient type objects."
B) Update scripts to target MailContact only (example)
$mailContacts = Get-MailContact -ResultSize Unlimited
foreach ($mc in $mailContacts) {

perform intended operation for mail-enabled contacts​

}
C) Non-destructive preview of creating MailContact from inventory (WhatIf)

Example for one item (run with -WhatIf first)​

New-MailContact -Name "Contoso Legacy" -ExternalEmailAddress "legacy@example.com" -Alias "contosolegacy" -OrganizationalUnit "contoso.com/Contacts" -WhatIf
Frequently asked questions (FAQs)
Q: Will my users’ personal Outlook contact items be affected?
A: No. Contacts created in user mailboxes (personal address books) are not affected by this change.
Q: Will MailContacts be affected?
A: No. MailContact recipient objects (those with SMTP/external email addresses) will continue to be viewable and manageable with the same cmdlets.
Q: I have scripts using Get-Contact — what should I change?
A: If your scripts intended to manage mail-enabled contacts, switch to Get-MailContact. If they intentionally managed Contact (non‑mail) objects, you need to decide how to handle those objects (convert/delete/manage on-prem). Make scripts defensive (check for empty results, log and alert).
Q: How many customers are impacted?
A: Microsoft’s announcement says this affects only a handful of tenants based on their logs; most organizations will see no impact. Microsoft will also post Message Center notices to impacted tenants.
Q: If my contacts are synced from on‑prem, where should I make changes?
A: Change them on‑prem (authoritative directory) so Azure AD Connect replicates the new state into Azure AD / Exchange Online. Do not try to permanently manage synced objects only in the cloud.
Q: What if I have a unique scenario requiring Contact recipient type objects?
A: Microsoft requested feedback through the Comments on their announcement so they can review special scenarios. You should also log a support request describing the scenario and include examples.
References (sources used for this article — no hyperlinks)
  • Microsoft Exchange Team announcement (TechCommunity) — “Updates to Get-Contact and Set-Contact Cmdlets for ‘Contacts’ Recipient Type in Exchange Online,” published Oct 7, 2025. (Primary announcement describing the December 15, 2025 enforcement and the scope of change.)
  • Microsoft Docs / Exchange PowerShell documentation (Get-MailContact, Get-Recipient, Get-EXORecipient) — official cmdlet references and parameter lists for recipient management in Exchange Online. (Used to confirm differences between MailContact and other recipient types and to recommend using Get-MailContact when appropriate.)
  • Microsoft TechCommunity / Exchange Team blog posts on recipient types (historical context about Contact, MailContact, and hybrid sync behavior). (Used to explain legacy nature of Contact recipient type and hybrid considerations.)
  • PowerShell Gallery packages and community scripts (examples for contact handling) — used to check community patterns for contact manipulation and to ensure sample scripts align with usual practice.
Final notes and recommended next steps (short actionable list)
1) Run the inventory (Get-Contact | Where-Object { $_.RecipientType -eq "Contact" }) now and export results.
2) Review automation and scripts that use Get-Contact and update them to explicitly use Get-MailContact where mail-enabled objects were intended.
3) For any Contact objects found, determine whether to (a) mail-enable/convert to MailContact, (b) delete, or (c) update on-prem authoritative object. Document your chosen approach.
4) Pilot remediation on a small set and verify behavior, then proceed to bulk changes with backups and logging.
5) If you have a unique scenario that requires Contact recipient types, document it and provide feedback to Microsoft (Exchange Online team) as requested in their announcement.
If you want, I can:
  • Provide a ready-to-run audit script tailored to your tenant environment (I’ll include safety checks and dry-run modes).
  • Generate a CSV mapping template you can use to plan MailContact creation (fields: Identity, DisplayName, Suggested ExternalEmailAddress, OnPremAuthoritative?, ActionRecommended).
  • Help review any existing scripts you have that use Get-Contact and prepare a migration/patch plan for them.
Which of the above would you like me to generate next — an audit script, a CSV template for planned changes, or a script-checker for your existing automation?

Source: Microsoft Exchange Team Blog Updates to Get-Contact and Set-Contact Cmdlets for “Contacts” Recipient Type in Exchange Online | Microsoft Community Hub
 

Back
Top