Set-UpnWithMailAddress.ps1
<#PSScriptInfo
.VERSION 3.0 .GUID d043e608-c8b8-4336-ab34-01935201ac7a .AUTHOR Aaron Guilmette .COMPANYNAME Microsoft .COPYRIGHT 2020 .TAGS .LICENSEURI .PROJECTURI https://www.undocumented-features.com/2019/04/25/update-to-the-set-upnwithmailaddress-script/ .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .DESCRIPTION Replace UserPrincipalName with Mail attribute. .PRIVATEDATA #> <# .SYNOPSIS This script will replace the UPN of the target object with the value in its mail attribute. This can be useful if parity between the User Principal Name and email address is necessary (such as single sign-on scenarios with Office 365). .EXAMPLE .\Set-UpnWithMailAddress.ps1 -TargetUser testuser@contoso.com Replace UPN with mail attribute for user testuser@contoso.com. .EXAMPLE .\Set-UpnWithMailAddress.ps1 -TargetUser * Replace UPN with mail attribute for all users. .EXAMPLE .\Set-UpnWithMailAddress.ps1 -TargetUser * -SearchBase "OU=Test,DC=contoso,DC=com" -LogFile Log.txt Replace UPN with mail attribute for all users in organizational unit Test and log results to log.txt .EXAMPLE .\Set-UpnWithMailAddress.ps1 -TargetUser * -OnlyMailboxes Replace UPN with mail attribute for mailbox users only (exclude mail- enabled users). .PARAMETER ErrorLog Specify logfile for errors. Default is <date>_UPNUpdateError.txt. .PARAMETER Logfile Specify logfile for operations. Default is <date>_UPNUpdate.txt .PARAMETER OnlyMailboxes Ignore MailUser objects, based on msExchRecipientTypeDetails value. If the environment has MailUsers, it may not be desirable to overwrite the UserPrincipalName with the external mail attribute, since the external mail address will most likely be for a domain not bound to the current organization. .PARAMETER SearchBase Set the BaseDN for the search query. Defaults to the DN of the current domain. .PARAMETER SearchScope Set the search scope for Active Directory Operations. .PARAMETER TargetUser This parameter is used to identify the user or group of users on which the attributes will be updated. Can be a single UPN or a wildcard to select all users in current domain. .LINK http://aka.ms/thebookonit .NOTES All envrionments perform differently. Please test this code before using it in production. THIS CODE AND ANY ASSOCIATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK OF USE, INABILITY TO USE, OR RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER. 2020-04-21 Updated for PowerShell Gallery. 2019-04-25 Added objectGUID to log file. Reduced number of Get- calls to improve performance. Added on-screen progress meter for large batches. 2018-05-17 Updated logging parameters. 2016-08-30 Added -OnlyMailboxes parameter. 2014-08-02 Initial release. #> Param( [Parameter(Mandatory=$false,HelpMessage="Enter UPN for single user or * for all users")] [string]$TargetUser = "*", [Parameter(Mandatory=$false,HelpMessage="Only Mailboxes")] [switch]$OnlyMailboxes, [Parameter(Mandatory=$false,HelpMessage="Active Directory Base DN")] [string]$SearchBase = (Get-ADDomain).DistinguishedName, [Parameter(Mandatory=$false,HelpMessage="Active Directory Search Scope")] [ValidateSet("Base","OneLevel","Subtree")] [string]$SearchScope = "Subtree", [string]$Logfile = (Get-Date -Format yyyy-MM-dd) + "_UPNUpdate.txt", [string]$ErrorLog = (Get-Date -Format yyyy-MM-dd) + "_UPNUpdateError.txt" ) If (!(Get-Module ActiveDirectory)) { Import-Module ActiveDirectory } # Logging function function Write-Log([string[]]$Message, [string]$LogFile = $Script:LogFile, [switch]$ConsoleOnly,[switch]$ConsoleOutput, [ValidateSet("SUCCESS", "INFO", "WARN", "ERROR", "DEBUG")][string]$LogLevel) { If (!(Test-Path $LogFile)) { Out-File -Append -FilePath $LogFile -InputObject "`"DistinguishedName`",`"UPNBefore`",`"MailBefore`",`"UPNAfter`",`"MailAfter`",`"ObjectGuid`"" } $Message = $Message + $Input If (!$LogLevel) { $LogLevel = "INFO" } switch ($LogLevel) { SUCCESS { $Color = "Green" } INFO { $Color = "White" } WARN { $Color = "Yellow" } ERROR { $Color = "Red" } DEBUG { $Color = "Gray" } } if ($Message -ne $null -and $Message.Length -gt 0) { $TimeStamp = [System.DateTime]::Now.ToString("yyyy-MM-dd HH:mm:ss") if (!($ConsoleOnly)) { if ($LogFile -ne $null -and $LogFile -ne [System.String]::Empty) { Out-File -Append -FilePath $LogFile -InputObject "$Message" } } if ($ConsoleOutput -eq $true) { Write-Host "[$TimeStamp] [$LogLevel] :: $Message" -ForegroundColor $Color } } } switch ($OnlyMailboxes) { $true { Write-Log -ConsoleOutput -LogLevel INFO -Message "Processing mailbox objects." -ConsoleOnly [array]$TempUsers = Get-ADUser -LDAPFilter "(userPrincipalName=$($TargetUser))" -SearchBase $SearchBase -SearchScope $SearchScope -Properties mail, msExchRecipientTypeDetails | ? { $_.msExchRecipientTypeDetails -eq "1" } } $false { Write-Log -ConsoleOutput -LogLevel INFO -Message "Processing all object types." -ConsoleOnly [array]$TempUsers = Get-ADUser -LDAPFilter "(userPrincipalName=$($TargetUser))" -SearchBase $SearchBase -SearchScope $SearchScope -Properties mail } } $i = 1 $Users = @() foreach ($obj in $TempUsers) { if (!($obj.Mail -match $obj.UserPrincipalName)) { $Users += $obj } } Write-Log -ConsoleOutput -LogLevel INFO -Message "$($Users.Count) objects need to be updated." -ConsoleOnly ForEach ($User in $Users) { Write-Progress -Activity "Updating users [$($User.UserPrincipalName)]" -PercentComplete (($i / $Users.Count) * 100) -Status "$($Users.Count - $i) users remaining" -Id 1 $objBefore = $User If ($objBefore.Mail) { If (!($objBefore.Mail -match $objBefore.UserPrincipalName)) { Set-ADObject -Identity $User.DistinguishedName -Replace @{ userPrincipalName = $($User.mail) } $objAfter = Get-ADObject -Identity $User.DistinguishedName -Properties UserPrincipalName, Mail Write-Log -LogFile $Logfile -LogLevel INFO -Message "`"$($User.DistinguishedName)`",`"$($objBefore.UserPrincipalName)`",`"$($objBefore.mail)`",`"$($objAfter.UserPrincipalName)`",`"$($objAfter.Mail)`",`"$($User.objectGuid)`"" } } Else { Write-Log -ConsoleOutput -LogLevel ERROR -Message "$($objBefore.UserPrincipalName) does not have a valid mail attribute." -LogFile $ErrorLog } $objBefore = $null $objAfter = $null $i++ } |