UPN’s are a nice way for our users to remember their usernames. A UPN essentially has the same format as an email address. Rather than having users login to their workstations or intranet resources as CLOUD\Username, they can login as user.lastname@cloud.com which can be the same as their email address.
Problem
When moving to Office 365 and are using DirSync with or without ADFS, your users need to have a UPN with a public routable domain in it. The easiest and most logical way to do that for your users sake is to keep UPN and primary email address the same.
Solution(s)
There are of course a lot of different solutions out there for achieveing the above, many of them include PowerShell and csv-files. My solution is based on PowerShell and are utilizing either Exchange Powershell cmdlets or Active Directory cmdlets.
Solution 1 (Exchange 2007 and above)
The below example is a very quick one that you run in Exchange Management Shell in Exchange 2007 and above. It simply copies the “WindowsPrimaryEmailAddress” for all your user mailboxes to the userPrincipalName attribute, without any question.
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox | ForEach { Set-Mailbox -Identity $_.Guid.ToString() -UserPrincipalName $_.WindowsEmailAddress.ToString() }
To verify that the change has been properly done, you can run the below command to list all mailboxes that have different primary email address and UPN:
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox | Where-Object {$_.UserPrincipalName -ne $_.WindowsEmailAddress.ToString() }
Solution 2 (Exchange 2003 and above)
I had a case where the customer was running Exchange 2003, but had 2008R2 domain controllers. The customer also wanted a log file with the old and the new UPN after the change had been done. The script utilizes the ActiveDirectory module for PowerShell and copies the primary email address from the proxyAddresses attribute.
Running the script without any switches makes it run in test mode and do the AD-changes with the -WhatIf, so no changes will be done here.
Running the script with the switch -Production makes it do the actual changes.
For backup purposes, the script are also creating a log file with the old and new attribute in the same folder where you run the script.
<# .SYNOPSIS Script that copies the primary emailaddress from proxyAddresses to the userPrincipalName attribute. It runs in test mode and just logs the changes that would have bee done without any parameters. It identifies an exchange user with the legacyExchangeDN-attribute. .PARAMETER Production Runs the script in production mode and makes the actual changes. .NOTES Author: Johan Dahlbom Blog: 365lab.net Email: johan[at]dahlbom.eu The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights. #> param( [parameter(Mandatory=$false)] [switch] $Production = $false ) #Define variables $PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition $DateStamp = Get-Date -Format "yyyy-MM-dd-HH-mm-ss" $Logfile = $LogFile = ($PSScriptRoot + "\ProxyUPNSync-" + $DateStamp + ".log") Function LogWrite { Param ([string]$logstring) Add-content $Logfile -value $logstring Write-Host $logstring } try { Import-Module ActiveDirectory -ErrorAction Stop } catch { throw "Module ActiveDirectory not Installed" } #For each AD-user with a legacyExchangeDN, look up primary SMTP: in proxyAddresses #and use that as the UPN $CollObjects=Get-ADObject -LDAPFilter "(&(legacyExchangeDN=*)(objectClass=user))" -Properties ProxyAddresses,distinguishedName,userPrincipalName foreach ($object in $CollObjects) { $Addresses = $object.proxyAddresses $DN=$object.distinguishedName foreach ($Address In $Addresses) { $ProxyArray=($ProxyArray + "," + $Address) If ($Address -cmatch "SMTP:") { $PrimarySMTP = $Address $UserPrincipalName=$Address -replace ("SMTP:","") #Found the object validating UserPrincipalName If ($object.userPrincipalName -notmatch $UserPrincipalName) { #Run in production mode if the production switch has been used If ($Production) { LogWrite ($DN + ";" + $object.userPrincipalName + ";NEW:" + $UserPrincipalName) Set-ADObject -Identity $DN -Replace @{userPrincipalName = $UserPrincipalName} } #Runs in test mode if the production switch has not been used else { LogWrite ($DN + ";" + $object.userPrincipalName + ";NEW:" + $UserPrincipalName) Set-ADObject -Identity $DN -WhatIf -Replace @{userPrincipalName = $UserPrincipalName} } } else { Write-Host "Info: User $($object.UserPrincipalName) are already OK!" } } } }
Hope the above was helpful to you, please let me know if you have any questions!
/Johan
Would it be possible to only apply this to a certain OU? (solution 1)
Thanks
Hi Dave,
That would absolutely be possible adding the “-OrganizationalUnit” parameter to the Get-Mailbox command. See more on https://technet.microsoft.com/en-us/library/bb123685%28v=exchg.150%29.aspx.