Reporting and Clearing the SyncIssues, Conflicts, LocalFailures and ServerFailures using EWS and Powershell
The SyncIssues, Conflicts, LocalFailures and ServerFailures folders in a Mailbox are folders that "contain logs and items that Microsoft Outlook has been unable to synchronize with your Microsoft Exchange Server" which are described thoroughly in http://office.microsoft.com/en-us/outlook-help/synchronization-error-folders-HP001040042.aspx.
From a operational perspective over a period of time these folders can fill up with items for a number of reasons or because of certain problems or third party products. So in this post I'm going to look at how you can use EWS to report and delete the content in these folders.
Getting Access to the Folders
There are two ways you could access these folders in EWS the first would be to do a conventional search for the displayname of the folder's using a FindFolder operation and a couple of Shallow traversals starting at the MsgFolderRoot. Or the other way which can deal with Localized foldernames and also reduces the number of operations is to use the PR_ADDITIONAL_REN_ENTRYIDS property http://msdn.microsoft.com/en-us/library/cc842240.aspx on the Root folder (or the Non_IPM_Subtree).
The PR_ADDITIONAL_REN_ENTRYIDS is a multivalued Binary Array extended Mapi property which contains the HexEntryID for each of the Folders. To make use of these Id's you need to first convert the BinaryArray value to a String Hex value with BitConverter Class. Then use the EWS ConvertID operation to convert the Hexid to an EWSId the you can Bind to the Folder.
The Script as posted uses EWS Impersonation
If you want to customize which mailboxes it reports on then just change the Get-Mailbox line
Get-Mailbox -ResultSize Unlimited | ForEach-Object{
eg if you want to limit to only checking one server you could use
Get-Mailbox -ResultSize Unlimited -Server servernameblah | ForEach-Object{
You could do similar with other filter properties such as Database or OU
The script produces a CSV report of the Size and Item Count of each of these folders, if you want to delete all the Items within these folders you need to add one line to the script that will delete the Content of the folder that you want to effect eg for the SyncIssueFolder add
$SyncIssueFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true);
after the size report section. You need to add a separate Empty for Each folder you want to clear. On 2007 you can't use the Empty method so would need add code to enumerate the Items so you can do a batch delete I covered this in the Folders HowTo http://gsexdev.blogspot.com.au/2012/01/ews-managed-api-and-powershell-how-to_23.html
I've put a download of this script here the code itself looks like
From a operational perspective over a period of time these folders can fill up with items for a number of reasons or because of certain problems or third party products. So in this post I'm going to look at how you can use EWS to report and delete the content in these folders.
Getting Access to the Folders
There are two ways you could access these folders in EWS the first would be to do a conventional search for the displayname of the folder's using a FindFolder operation and a couple of Shallow traversals starting at the MsgFolderRoot. Or the other way which can deal with Localized foldernames and also reduces the number of operations is to use the PR_ADDITIONAL_REN_ENTRYIDS property http://msdn.microsoft.com/en-us/library/cc842240.aspx on the Root folder (or the Non_IPM_Subtree).
The PR_ADDITIONAL_REN_ENTRYIDS is a multivalued Binary Array extended Mapi property which contains the HexEntryID for each of the Folders. To make use of these Id's you need to first convert the BinaryArray value to a String Hex value with BitConverter Class. Then use the EWS ConvertID operation to convert the Hexid to an EWSId the you can Bind to the Folder.
The Script as posted uses EWS Impersonation
If you want to customize which mailboxes it reports on then just change the Get-Mailbox line
Get-Mailbox -ResultSize Unlimited | ForEach-Object{
eg if you want to limit to only checking one server you could use
Get-Mailbox -ResultSize Unlimited -Server servernameblah | ForEach-Object{
You could do similar with other filter properties such as Database or OU
The script produces a CSV report of the Size and Item Count of each of these folders, if you want to delete all the Items within these folders you need to add one line to the script that will delete the Content of the folder that you want to effect eg for the SyncIssueFolder add
$SyncIssueFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true);
after the size report section. You need to add a separate Empty for Each folder you want to clear. On 2007 you can't use the Empty method so would need add code to enumerate the Items so you can do a batch delete I covered this in the Folders HowTo http://gsexdev.blogspot.com.au/2012/01/ews-managed-api-and-powershell-how-to_23.html
I've put a download of this script here the code itself looks like
- $rptCollection = @()
- ## Load Managed API dll
- Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
- ## Set Exchange Version
- $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
- ## Create Exchange Service Object
- $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
- ## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials
- #Credentials Option 1 using UPN for the windows Account
- $psCred = Get-Credential
- $creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())
- $service.Credentials = $creds
- #Credentials Option 2
- #service.UseDefaultCredentials = $true
- ## Choose to ignore any SSL Warning issues caused by Self Signed Certificates
- ## Code From http://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
- ## end code from http://poshcode.org/624
- ## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
- Get-Mailbox -ResultSize Unlimited | ForEach-Object{
- $MailboxName = $_.PrimarySMTPAddress.ToString()
- "Processing Mailbox : " + $MailboxName
- if($service.url -eq $null){
- ## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
- #CAS URL Option 1 Autodiscover
- $service.AutodiscoverUrl($MailboxName,{$true})
- "Using CAS Server : " + $Service.url
- #CAS URL Option 2 Hardcoded
- #$uri=[system.URI] "https://casservername/ews/exchange.asmx"
- #$service.Url = $uri
- }
- $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
- $PR_MESSAGE_SIZE_EXTENDED = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(3592,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Long);
- $PR_ADDITIONAL_REN_ENTRYIDS = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x36D8, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::BinaryArray);
- $Propset = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
- $Propset.add($PR_ADDITIONAL_REN_ENTRYIDS)
- $Propset.add($PR_MESSAGE_SIZE_EXTENDED)
- #Sync Folders
- $folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)
- $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid,$Propset)
- $objVal = $null
- function ConvertFolderid($hexId){
- $aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId
- $aiItem.Mailbox = $MailboxName
- $aiItem.UniqueId = $hexId
- $aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::HexEntryId;
- return $service.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EWSId)
- }
- if($RootFolder.TryGetProperty($PR_ADDITIONAL_REN_ENTRYIDS,[ref]$objVal)){
- if($objVal[0] -ne $null){
- $rptobj = "" | Select MailboxName,SyncIssuesCount,SyncIssuesSize,ConflictsCount,ConflictsSize,LocalFailuresCount,LocalFailuresSize,ServerFailuresCount,ServerFailuresSize
- $rptobj.MailboxName = $MailboxName
- $cfid = ConvertFolderid([System.BitConverter]::ToString($objVal[0]).Replace("-",""))
- if($cfid.UniqueId -ne $null){
- $ConflictsFolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId($cfid.UniqueId.ToString())
- $ConflictsFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$ConflictsFolderId,$Propset)
- $ConflictsFolder.DisplayName
- $folderSize = $null
- if($ConflictsFolder.TryGetProperty($PR_MESSAGE_SIZE_EXTENDED,[ref]$folderSize)){
- $rptobj.ConflictsCount = $ConflictsFolder.TotalCount
- $rptobj.ConflictsSize = [Math]::Round($folderSize/1MB)
- "ItemCount : " + $ConflictsFolder.TotalCount
- "FolderSize : " + [Math]::Round($folderSize/1MB) + " MB"
- }
- $siId = ConvertFolderid([System.BitConverter]::ToString($objVal[1]).Replace("-",""))
- $SyncIssuesFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId($siId.UniqueId.ToString())
- $SyncIssueFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$SyncIssuesFolderID,$Propset)
- $SyncIssueFolder.DisplayName
- if($SyncIssueFolder.TryGetProperty($PR_MESSAGE_SIZE_EXTENDED,[ref]$folderSize)){
- $rptobj.SyncIssuesCount = $SyncIssueFolder.TotalCount
- $rptobj.SyncIssuesSize = [Math]::Round($folderSize/1MB)
- "ItemCount : " + $SyncIssueFolder.TotalCount
- "FolderSize : " + [Math]::Round($folderSize/1MB) + " MB"
- }
- $lcId = ConvertFolderid([System.BitConverter]::ToString($objVal[2]).Replace("-",""))
- $localFailureId = new-object Microsoft.Exchange.WebServices.Data.FolderId($lcId.UniqueId.ToString())
- $localFailureFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$localFailureId,$Propset)
- $localFailureFolder.DisplayName
- if($localFailureFolder.TryGetProperty($PR_MESSAGE_SIZE_EXTENDED,[ref]$folderSize)){
- $rptobj.LocalFailuresCount = $localFailureFolder.TotalCount
- $rptobj.LocalFailuresSize = [Math]::Round($folderSize/1MB)
- "ItemCount : " + $localFailureFolder.TotalCount
- "FolderSize : " + [Math]::Round($folderSize/1MB) + " MB"
- }
- $sfid = ConvertFolderid([System.BitConverter]::ToString($objVal[3]).Replace("-",""))
- $ServerFailureId = new-object Microsoft.Exchange.WebServices.Data.FolderId($sfid.UniqueId.ToString())
- $ServerFailureFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$ServerFailureId,$Propset)
- $ServerFailureFolder.DisplayName
- if($ServerFailureFolder.TryGetProperty($PR_MESSAGE_SIZE_EXTENDED,[ref]$folderSize)){
- $rptobj.ServerFailuresCount = $ServerFailureFolder.TotalCount
- $rptobj.ServerFailuresSize = [Math]::Round($folderSize/1MB)
- "ItemCount : " + $ServerFailureFolder.TotalCount
- "FolderSize : " + [Math]::Round($folderSize/1MB) + " MB"
- }
- $rptCollection += $rptobj
- }
- }
- }
- }
- $rptCollection
- $rptCollection | Export-Csv -NoTypeInformation -Path c:\temp\SyncFolderReport.csv