Every Exchange Administrator needs to maintain consistency between User Principal Names (UPNs) and email addresses (ProxyAddress attribute) is critical for proper identity management. This post details my journey in identifying and resolving discrepancies between UPNs and email addresses in Exchange.
The normal scenario is this:
UPN: lee.croucher@bythepowerofgreyskull.com
Mail : lee.croucher@bythepowerofgreyskull.com
I notice we had an issue where this was true:
UPN: lee.croucher@bythepowerofgreyskull.com
Mail : na_68443@<tenantid>.onmicrosoft.com
This was caused by a mailbox that was present on the mailbox or the mail attribute being set to something other than the authorised accepted domains from an Exchange point of view, if this is the case then the "ProxyAddress" attribute will fall back to the default domain which for Exchange Online is <tenantid>.onmicrosoft.com
The Process
This was a simple process to understand this involved taking the mailboxes that had incorrect "ProxyAddress" attributes due to a disconnected mailbox when the mailbox was a remote mailbox from Exchanges point of view and its was deleted locally, to fix this you need to creating that mailbox once again but do not migrate the mailbox to Exchange Online.
When the "mail" attribute is fixes you can simply disconnect the local mailbox from Exchange on-premises.
I recently encountered an issue where many users had mismatches between their UPN and their primary email address. This inconsistency created problems with authentication, mail routing, and user experience. The task seemed straightforward: find all mismatches and create or update mailboxes to align with the UPNs.
However, like many seemingly simple Exchange tasks, this proved more complex than anticipated and this post outlined how these addresses are correct to match the UPN.
The first step was to identify users with mismatches between their UPN and email address. I created a PowerShell script to query a specific OU and compare these values:
# Import required modules
Import-Module ActiveDirectory
Import-Module ExchangeOnlineManagement
# Define the OU path
$OUPath = "OU=Users,DC=bear,DC=local"
# Get current script directory for log file placement
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$LogFile = Join-Path -Path $ScriptPath -ChildPath "UPN_Email_Mismatch_$
(Get-Date -Format 'yyyyMMdd_HHmmss').log"
# Function to write to log file
function Write-Log {
param (
[string]$Message
)
Write-Host $Message
Add-Content -Path $LogFile -Value $Message
}
# Get users from the specified OU
$adUsers = Get-ADUser -Filter * -SearchBase $OUPath -Properties UserPrincipalName, Enabled
$totalUsers = $adUsers.Count
Write-Log "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Found $totalUsers users in the
specified OU"
# Create log file header
Write-Log "UPN and Email Address Mismatch Report"
Write-Log "Generated on: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Log "OU: $OUPath"
Write-Log "----------------------------------------"
Write-Log "UPN`tEmail Address`tDisplay Name"
Write-Log "----------------------------------------"
# Process each user to find mismatches
$mismatchCount = 0
foreach ($user in $adUsers) {
# Get the mailbox
$mailbox = Get-Mailbox -Identity $user.UserPrincipalName -ErrorAction SilentlyContinue
if ($mailbox) {
$upn = $user.UserPrincipalName
$email = $mailbox.PrimarySmtpAddress
# Check if UPN and email address match
if ($upn -ne $email) {
$mismatchCount++
$logEntry = "$upn`t$email`t$($mailbox.DisplayName)"
Write-Log $logEntry
}
}
}
# Write summary
Write-Log "----------------------------------------"
Write-Log "Summary:"
Write-Log "Total users processed: $totalUsers"
Write-Log "Total mismatches found: $mismatchCount"
Write-Log "----------------------------------------"
# Clean up
Remove-PSSession $ExchangeSession
This script generated a log file with all users whose UPN differed from their primary email address which can be a problem if your SAML application uses the "mail" attribute to sign people into the application.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$LogFilePath,
[Parameter(Mandatory=$false)]
[switch]$DisableConfirm
)
# Read the log file and extract UPNs
try {
Write-Host "Reading UPNs from log file..."
$logContent = Get-Content -Path $LogFilePath -Raw
# Extract UPNs using regex pattern matching
# Look for lines that start with an email address pattern followed by a tab
$upnMatches = [regex]::Matches($logContent, '(?m)^([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]
+\.[A-Za-z]{2,})\t')
if ($upnMatches.Count -eq 0) {
Write-Host "No UPNs found in the log file. Make sure the format is correct."
-ForegroundColor Red
exit
}
# Extract unique UPNs from matches
$upns = @()
foreach ($match in $upnMatches) {
$upn = $match.Groups[1].Value
if ($upn -match '@bythepowerofgreyskull\.com$' -and $upn -notmatch '^Summary:'
-and $upn -notmatch '^Total') {
$upns += $upn
}
}
$totalUpns = $upns.Count
Write-Log "Found $totalUpns UPNs in the log file"
}
catch {
$errorMessage = $_.Exception.Message
Write-Host "Error reading log file - $errorMessage" -ForegroundColor Red
exit
}
Before blindly updating email addresses, I needed to understand if there would be conflicts. My initial thought was to check for proxy address conflicts across the domain:
# For each mismatch, check if the UPN exists as a proxy address elsewhere
foreach ($mismatchUser in $mismatchUsers) {
$upn = $mismatchUser.UPN
# Search for accounts where this UPN exists as a proxy address
$filter = "proxyAddresses -like '*:$upn'"
$conflictingUsers = Get-ADUser -Filter $filter -Properties UserPrincipalName,
mail, proxyAddresses, Enabled
if ($conflictingUsers) {
# Found conflicts - this UPN is already in use as a proxy address
foreach ($conflictUser in $conflictingUsers) {
# Skip if it's the same user
if ($conflictUser.UserPrincipalName -eq $upn) {
continue
}
$accountType = if ($conflictUser.Enabled) { "Enabled" } else { "Disabled" }
Write-Log "$upn`tConflict detected`tAddress in use by: $($conflictUser.
SamAccountName) (Account Status: $accountType)"
}
}
}
This approach had limitations - it was slow and didn't accurately predict all potential conflicts that Exchange might encounter.
I realized Exchange itself would provide the most accurate information about conflicts. Instead of trying to predict them, I decided to directly attempt mailbox creation with the UPN as the email address and capture any errors:
try {
# Attempt to create/update the mailbox
$result = Enable-Mailbox -Identity $adUser.SamAccountName -Alias $alias
-Database "UserMBX1" -ErrorAction Stop
# Now set the primary SMTP address
Set-Mailbox -Identity $adUser.SamAccountName -PrimarySmtpAddress $upn
-EmailAddressPolicyEnabled $false
Write-Log "$upn`tSuccess`tMailbox created successfully"
}
catch {
$errorMessage = $_.Exception.Message
# Check if error is due to a proxy address conflict
if ($errorMessage -match "The proxy address '.*' is already being used by") {
Write-Log "$upn`tError`t$errorMessage"
# Extract conflicting account info
if ($errorMessage -match "The proxy address '.*' is already being used by
the proxy addresses or LegacyExchangeDN of '([^']+)'") {
$conflictingAccount = $Matches[1]
Write-Log "Conflicting Account: $conflictingAccount"
}
}
}
This approach immediately revealed conflicts and provided specific information about which accounts had conflicting addresses.
While implementing the direct approach, I ran into an unexpected challenge. Many users were failing with this error:
Could not convert property WindowsEmailAddress to type SmtpAddress. Error while
converting string 'n/a' to result type Microsoft.Exchange.Data.SmtpAddress:
The email address "n/a" isn't correct.
This occurred because some user accounts had invalid placeholder values ('n/a') in their email attributes.
Simply updating the AD mail attribute didn't solve the problem because Exchange was caching or referencing this value from another location.
The key insights that made this solution work:
- Update AD attributes first - Ensure the mail attribute matches the UPN before attempting mailbox creation
- Use a two-step process - First create the mailbox with minimal parameters, then set the primary SMTP address
- Have fallback strategies - For WindowsEmailAddress errors, using the mail-enable then convert approach worked well
- Always verify results - Exchange might report success but fail to create a mailbox, or report an error but still create one
- Detailed logging - Capture all errors and conflicts for further analysis