The Categories or Keywords properties on a Mailbox Item is one of the more commonly used Item properties in Exchange. When you want to search for Items with a particular Category set it does present some challenges in EWS.
With EWS you have 3 different search methods, the first being Restrictions (or SearchFilter's if your using the Managed API) that work like MAPI restrictions although you can't build restriction that are 100% equivalent to what you can in MAPI. One particular case is with the Categories property, because this is a Multi-Valued property (or String Array) the IsEqual and Contains Restrictions wont work like the Sproperty restriction in MAPI http://msdn.microsoft.com/en-us/library/office/cc815385(v=office.15).aspx
So the next type of Search you can do is a Search of a Mailbox folder using an AQS querystring which essentially does an Index search. Because the Categories property is an Indexed property this will work fine for Categories. The thrid type of Search you can do is eDiscovery in Exchange 2013 which I'll cover in another post
The following script does a search of the the Inbox folder for a particular Keyword using the AQS query
"System.Category:Categorytolookfor"
It also does a client side validation to ensure no false positives are included. To run the script just pass in the name of the mailbox you want to search and the Category to search for (enclosed in '' if there is a space) eg .\SearchCategory.ps1 glen@domain.com 'green category' . The script will output a CSV report of all the messages founds with that particular Category set.
I've put a download of this script here the code itself looks like
With EWS you have 3 different search methods, the first being Restrictions (or SearchFilter's if your using the Managed API) that work like MAPI restrictions although you can't build restriction that are 100% equivalent to what you can in MAPI. One particular case is with the Categories property, because this is a Multi-Valued property (or String Array) the IsEqual and Contains Restrictions wont work like the Sproperty restriction in MAPI http://msdn.microsoft.com/en-us/library/office/cc815385(v=office.15).aspx
So the next type of Search you can do is a Search of a Mailbox folder using an AQS querystring which essentially does an Index search. Because the Categories property is an Indexed property this will work fine for Categories. The thrid type of Search you can do is eDiscovery in Exchange 2013 which I'll cover in another post
The following script does a search of the the Inbox folder for a particular Keyword using the AQS query
"System.Category:Categorytolookfor"
It also does a client side validation to ensure no false positives are included. To run the script just pass in the name of the mailbox you want to search and the Category to search for (enclosed in '' if there is a space) eg .\SearchCategory.ps1 glen@domain.com 'green category' . The script will output a CSV report of all the messages founds with that particular Category set.
I've put a download of this script here the code itself looks like
- ## Get the Mailbox to Access from the 1st commandline argument
- $MailboxName = $args[0]
- $CategoryToFind = $args[1]
- ## Load Managed API dll
- ###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
- $EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
- if (Test-Path $EWSDLL)
- {
- Import-Module $EWSDLL
- }
- else
- {
- "$(get-date -format yyyyMMddHHmmss):"
- "This script requires the EWS Managed API 1.2 or later."
- "Please download and install the current version of the EWS Managed API from"
- "http://go.microsoft.com/fwlink/?LinkId=255472"
- ""
- "Exiting Script."
- exit
- }
- ## 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
- #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
- ## Optional section for Exchange Impersonation
- #$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
- $AQSString = "System.Category:`"" + $CategoryToFind + "`""
- # Bind to the Inbox Folder
- $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)
- $Inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
- $rptCollection = @()
- #Define ItemView to retrive just 1000 Items
- $ivItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000)
- $fiItems = $null
- do{
- $fiItems = $service.FindItems($Inbox.Id,$AQSString,$ivItemView)
- #[Void]$service.LoadPropertiesForItems($fiItems,$psPropset)
- foreach($Item in $fiItems.Items){
- #Validate exact Category Match
- $match = $false
- foreach($cat in $Item.Categories){
- if($cat.ToLower() -eq $CategoryToFind.ToLower()){
- $match = $true;
- }
- }
- if($match){
- $rptObj = "" | Select DateTimeReceived,From,Subject,Size,Categories
- $rptObj.DateTimeReceived = $Item.DateTimeReceived
- $rptObj.From = $Item.From.Name
- $rptObj.Subject = $Item.Subject
- $rptObj.Size = $Item.Size
- $rptObj.Categories = [system.String]::Join(",",$Item.Categories)
- $rptCollection += $rptObj
- }
- }
- $ivItemView.Offset += $fiItems.Items.Count
- }while($fiItems.MoreAvailable -eq $true)
- $rptCollection | Export-Csv -NoTypeInformation -Path c:\temp\$MailboxName-CategoryReport.csv
- Write-Host "Report Saved to c:\temp\$MailboxName-CategoryReport.csv"