Clear OWA and Outlook 2010/2013 Auto-Complete Cache

 

The Auto-Complete List is a feature which displays suggestions for names and email addresses as you start to type them in the To, Cc, and Bcc boxes. These suggestions are possible matches from a list of names and email addresses from the email messages that you have sent.

The list also save the legacy exchange DN which is quite important for mail delivery on exchange organizations.

In some situations we might face some issues with the list and we have no other options rather than clearing the cache.

In Outlook 2010 and 2013 we have several options for clearing the autocomplete cache.

One of these methods is to run Outlook with the /cleanautocompletecache cmd line switch.

That could be a good solution if you have an issue with one client but in some catastrophic situations you might want to clear the cache for all users without interactions from end users.

Why I am not covering legacy outlook clients 2007/2003 ?

in the past we used to store the autocomplete cache on the client disk, old people might still remember the famous file n2k.

It was completely managed by outlook clients and the only solution was to deploy a vbs in a group policy to delete the file from the file system on each client pc.

Starting from outlook 2010, the cache is now part of the mailbox at the server side.

Prerequisites

1. The script allows you to connect to the mailboxes in your organization using full mailbox access or exchange impersonation.

a. In order to be able to access the mailboxes using impersonation you will need to use an account that has impersonation permissions on all the mailboxes. By default, the script will use the credentials of the user running the script. If you wish to use different credentials, please use the -UseDefaultCredentials $false parameter to be able to specify the credentials.

b. To grant impersonation permissions to a specific account, please follow the instructions in the following article: https://msdn.microsoft.com/en-us/library/exchange/bb204095(v=exchg.140).aspx

2. The script uses the EWS Managed API 2.0 to connect to the mailboxes so please make sure that you have downloaded and installed the API before launching the script: https://www.microsoft.com/en-us/download/details.aspx?id=35371 and make sure that the EWSManagedApiPath is correct in the script

 

Examples

1. If you wish to run the script on several mailboxes you can run a command similar to Get-Mailbox | foreach-object { .\Remove-AutocompleteCache.ps1 –EmailAddress $_.PrimarySmtpAddress.tostring() –Impersonate $true} from the windows Azure Active Directoyr module for windows powershell or exchange management shell

2. If you wish to run the script against one mailbox, you just need to specify the e-mail address as a value for the EmailAddress parameter.

3. If you wish to connect using diferent credentials please use the following syntax:.\Remove-AutocompleteCache.ps1 -EmailAddress EMAIL_ADDRESS -impersonate $false -usedefaultcredentials $false -username USERNAME -domain DOMAIN -password PASSWORD, where EMAIL_ADDRESS is the e-mail address of the mailbox you wish to connect to and USERNAME, DOMAIN and PASSWORD are the credentials of the account used to connect to the specified mailbox.

PowerShell

# Parameters

param (

[string]$EmailAddress,

[bool]$Impersonate = $false,

[bool]$UseAutodiscover = $true,

[bool]$UseDefaultCredentials = $true,

[bool]$TrustAllCertificates = $true,

[string] $Username,

[string] $Password,

[string] $Domain,

[string]$EwsUrl,

[string]$EWSManagedApiPath = "C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"

);

if ($TrustAllCertificates -eq $true)

{

## Code From https://poshcode.org/624

## Create a compilation environment

$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider

$Compiler=$Provider.CreateCompiler()

$Params=New-Object System.CodeDom.Compiler.CompilerParameters

$Params.GenerateExecutable=$False

$Params.GenerateInMemory=$True

$Params.IncludeDebugInformation=$False

$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

$TASource=@'

  namespace Local.ToolkitExtensions.Net.CertificatePolicy{

    public class TrustAll : System.Net.ICertificatePolicy {

      public TrustAll() {

      }

      public bool CheckValidationResult(System.Net.ServicePoint sp,

        System.Security.Cryptography.X509Certificates.X509Certificate cert,

        System.Net.WebRequest req, int problem) {

        return true;

      }

    }

  }

'@

$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)

$TAAssembly=$TAResults.CompiledAssembly

## We now create an instance of the TrustAll and attach it to the ServicePointManager

$TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")

[System.Net.ServicePointManager]::CertificatePolicy = $TrustAll

write-host -ForegroundColor Yellow "Trusting all certificates!"

}

write-host "Accessing mailbox" $EmailAddress

# Loading ManagedAPI dll

[Void] [Reflection.Assembly]::LoadFile($EWSManagedApiPath)

# Setting up the service

$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1);

# Setting up credentials

if ($UseDefaultCredentials -eq $true)

{

$Service.UseDefaultCredentials = $true;

}

else

$Service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($UserName, $Password, $Domain);

}

# Setting Autodiscover settings

if ($UseAutodiscover -eq $true)

{

$service.AutodiscoverUrl($EmailAddress, {$True});

}

else

{

$Service.Url = new-Object Uri($EwsUrl);

}

# If we are using impersonation then setup impersonation

if ($Impersonate)

{

$Service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);

}

$PidTagRoamingBinary = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x7C09, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)

$propertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, $PidTagRoamingBinary)

try

    {

#Get root folder

$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$EmailAddress)

$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)       

#Clear the outlook cache

$SearchFilterCollection = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)

$SearchFilter1 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass,"IPM.Configuration.Autocomplete")

$SearchFilterCollection.Add($SearchFilter1)

$itemView = new-object Microsoft.Exchange.WebServices.Data.ItemView(100)

$itemView.PropertySet = $propertySet

$itemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated       

$findResults = $folder.FindItems($SearchFilterCollection,$itemView)

if ($findResults.Items.Count -ne 0)

        {

foreach($item in $findResults.Items)

           {

$item.Load($propertySet)

if($item.RemoveExtendedProperty($PidTagRoamingBinary))

                {

write-host "Cached deleted!"

$item.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)   

                }

else

                {

write-host "No cache found!"

                }

            }

        }

#Clear the OWA Cache

$ContactsRootfolderID= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts,$EmailAddress)    

$ContactsRootfolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$ContactsRootfolderID)

$ContactsView = new-object Microsoft.Exchange.WebServices.Data.FolderView(5,0)

$Contactsview.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)

$findContactFolders = $ContactsRootfolder.FindFolders($Contactsview)

foreach ($Folder in $findContactFolders.folders)

              {

if($Folder.displayname -eq "Recipient Cache")

                     {

#Define ItemView to retrive just 1000 Items     

$ivItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000) 

$ivItemView.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)                          

$Cacheitmes = $service.FindItems($Folder.Id,$ivItemView)

$Cacheitmes

foreach($cachentry in $Cacheitmes.items)

                           {

$cachentry.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)

                           }

                     }

              }

       }

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: $($EmailAddress) Error $($error[0])" -ForegroundColor Red

                }

   }

 

Disclaimer The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.