Recently, I worked on an email migration from Lotus Notes to Office 365. There were some email addresses brought over that were non-routable and the client requested we help them clear these "bad" addresses.
I wanted to document this since there isn't much information out there (that I could find, at least)
I've used the script from Troy's Tech blog here as a starting point. I couldn't get his script to work, line for line, so it's been updated to connect to Exchange 2013, which is what O365 is currently using. This script will loop through all of your users and clean up Autofill Cache for any address ending in whateverdomainyouwant.com, just add that domain (or search string) in the "$badDomain" variable.
PreReqs:
This script requires EWS API 2.0 and using an Impersonated user. I have also only tested it using PowerShell 4 on Windows 8.1.
Link to EWS 2.0 API
For the impersonated user, here is the code I used to set it. (I used the admin user for this)
New-ManagementRoleAssignment –Name:impersonationAssignmentName Role:ApplicationImpersonation –User:(user email address)
Here's the script (make sure to change the $user and $badDomain variables)
###### =============================================================================== # Author: Mike Sweany # Date: 1/23/2014 # Version: 1.0 # Purpose: This script will delete any AutoFill addresses for Office365 Web App # if it matches the domain set for "$badDomain" # PreReqs: Office 365, Powershell 4 # PreReqs: EWS 2.0 Managed API ########## http://www.microsoft.com/en-us/download/details.aspx?id=35371 # PreReqs: Administrative user configured as Impersonated user ########## New-ManagementRoleAssignment –Name:impersonationAssignmentName Role:ApplicationImpersonation –User:(user email address) ###### =============================================================================== ###### Specify your administrative user credentials on the line below $User = "user@domain.onmicrosoft.com" $badDomain = "@baddomain.com" ###### This will pop-up a dialog and request your password $psCred = Get-Credential $User ###### Import the Local Microsoft Online PowerShell Module Cmdlets and Connect to O365 Online Connect-MsolService -Credential $psCred ###### Establish an Remote PowerShell Session to Exchange Online $msoExchangeURL = "https://ps.outlook.com/powershell/" $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $msoExchangeURL -Credential $psCred -Authentication Basic -AllowRedirection Import-PSSession $session write-host "Connected to O365" ###### Load EWS API dll Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll" ###### Set Exchange Version $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013 ###### Create Exchange Service Object $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion) ###### Credentials for EWS $creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString()) $service.Credentials = $creds $impersonationUser = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId $impersonationUser.IdType = [Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress write-host "Connected to EWS" ###### Create an xmlDoc object to store the auto complete cache. $xmlDoc = New-Object System.Xml.XmlDocument ###### Get a list of mailboxes you want to clear the cache for $mailboxes = Get-Mailbox | Select-Object PrimarySMTPAddress foreach($mailbox in $Mailboxes) { try { write-host $mailbox.PrimarySMTPAddress " processing" ###### Connect to users account using impersonation $service.AutodiscoverUrl($mailbox.PrimarySMTPAddress,{$true}) $impersonationUser.Id = $mailbox.PrimarySMTPAddress $service.ImpersonatedUserId = $impersonationUser ###### Get root folder $folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root) ###### Get OWA Autocomplete cache $config = [Microsoft.Exchange.WebServices.Data.UserConfiguration]::Bind($service, "OWA.RecipientCache", $folder.ParentFolderId, [Microsoft.Exchange.WebServices.Data.UserConfigurationProperties]::All) #At this point you could just use the folowing 2 lines to clear all entries #$config.Delete() #$config.Update() ###### Convert the byte array and store as xmldoc. There seems to be a special character at the beginning so I don't include it in the xml $stringData = [System.Text.Encoding]::UTF8.GetString($config.XmlData).Substring(1) $xmlDoc.LoadXml($stringData) $nodes = $xmlDoc.SelectNodes("/AutoCompleteCache/entry") #loop through each entry and remove if necessary foreach($node in $nodes) { if($node.smtpAddr -ne $null -and $node.smtpAddr.Contains($badDomain)) { $node.ParentNode.RemoveChild($node) | Out-Null write-host "`tRemoving: $($node.smtpAddr) from $($mailbox.PrimarySMTPAddress)" } } ###### Convert the xml back into a byte array $data = [System.Text.Encoding]::UTF8.GetBytes([System.Text.Encoding]::UTF8.GetString($config.XmlData).Substring(0,1) + $xmlDoc.OuterXml) $config.XmlData = $data ###### Save the config back to the users mailbox $config.Update() ###### Show progress on the screen write-host $mailbox.PrimarySMTPAddress " processed" } catch { ###### If the error is 'The specified object was not found in the store.' It means there are no entries in the Autocomplete cache. This error can be ignored if(!$error[0].ToString().contains("The specified object was not found in the store.")) { write-host "`tfailed: $($mailbox.PrimarySMTPAddress) Error $($error[0])" -ForegroundColor Red } } }
That's it, I hope it helps you.
ReplyDeleteExcellent Blog! I would like to thanks for the efforts you have made in writing this post.
I am hoping the same best work from you in the future as well. This is very beneficial to me.
I’m happy I came across this website. I still learn something new from your posts! It will give
you a great idea aboutupdate here