Friday, August 05, 2011

Using the AllItems Search folder from Outlook 2010 on Exchange 2010 with Powershell and the EWS Managed API

Search folders in Exchange make searching for items in multiple folders a little more easier and/or allows you to group and find email with certain properties easier eg things like Unread email, Flagged for followup etc. Outlook 2010 makes use of these features for To-Do list etc. One useful search folder that gets created by Outlook 2010 when its used against a Exchange 2010 server is the AllItems search folder. eg this one




This is a search folder that gets created in the NON_IPM_Subtree folder and essentially allows you to do a generic search of all the folders within a Mailbox. This can be useful in a powershell script if you do need to enumerate every item within a mailbox to use the Allitems search folder you first need to do a search for this search folder in the Mailbox Root and then you can use some normal findItems enumeration code.

To filter a findfolders operation to only return search folders you can use the PR_Folder_Type extended property if this property is set to 2 then you know the folder is a search folder

$PR_FOLDER_TYPE = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(13825,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer);


The following sample script shows how to return items that where received in January 2011 in all folders within a mailbox using the AllItems search folder with an AQS query. I've put a download of the code here the script itself looks like

$AqsString = "System.Message.DateReceived:01/01/2011..01/31/2011"
$MailboxName = "domain.com"

$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.Credentials = New-Object System.Net.NetworkCredential("user@domain.com","passwod")

$service.AutodiscoverUrl($MailboxName,{$true})
$PR_FOLDER_TYPE = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(13825,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer);

"Checking : " + $MailboxName
$folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)
$fvFolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$fvFolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow;
$sf1 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo($PR_FOLDER_TYPE,"2")
$sf2 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,"allitems")
$sfSearchFilterCol = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$sfSearchFilterCol.Add($sf1)
$sfSearchFilterCol.Add($sf2)
$fiResult = $Service.FindFolders($folderidcnt,$sfSearchFilterCol,$fvFolderView)
$fiItems = $nulll
$ItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000)
if($fiResult.Folders.Count -gt 0){
$fiResult.Folders[0].DisplayName
do{
$fiItems = $fiResult.Folders[0].findItems($AqsString,$ItemView)
$ItemView.offset += $fiItems .Items.Count
foreach($Item in $fiItems.Items){
$Item.Subject
}
}while($fiItems .MoreAvailable -eq $true)
}

12 comments:

Luke said...

Do you have any sample code on how I can use the EWS Managed API with the All Folders? I don't quite follow you when you say I need to search for the folder first. Is there not a well known folder name such as WellKnownFolderName.Inbox?

Luke said...

Sorry for the double comments. I have ported this PowerShell script over to c# however it is not quite working yet. Any ideas ? - http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/8c71ace4-43d2-4ba2-88f2-16376dad828f

Joachim said...

I combined this script with $AQSString = "System.Size:10mb..9999mb"

It finds some items but not nearly all that are over 10MB. I tried it too with PDFs just to be sure and the same result: it founds some, but not all. So these "all item" are not all items but an obscure subset of items.

What did I get wrong? How can I search every mail folder for items over 10MB?

Joachim said...
This comment has been removed by the author.
Joachim said...

The "obscure subset" is the inbox again, so only the inbox is search, not "allitems".

If you are interested in the details I have added it there: http://social.technet.microsoft.com/Forums/en-US/exchange2010/thread/9f38b4c4-add1-4f12-b832-c2417ec5a58d

I have mentioned your fine blog as source of my scripts :)

Glen said...

AFAIK mixing AQS with Search folder won't work correctly I've had this argument with someone before I'm sorry to say you will need to query ever folder individually or create your own searchfolder and wait for that to be populated.

Cheers
Glen

Joachim said...
This comment has been removed by the author.
Joachim said...

I can query all folders with "$folders = get-mailbox -identity $MailboxName -resultsize unlimited | get-mailboxfolderstatistics -folderscope all | %{$_.Name }" but then I do not know how to search in them. Can you give me antoher hint here?
Any way to set $folderid to the folders I find this way?

Glen said...

You would be better just putting a FindItems query within the FindFolders Query this will be quicker then needing to convert the Id from using EMS.

Cheers
Glen

Sonorous Synthesis said...

Hi, I'm trying to get your script to do something but I can't quite get there.

We have hundreds of public folders, and they have a tonne of sub folders.

There are about 5 or 6 "top level" folders we are interested in and we want to get the contents of pretty much every sub folder unless the sub folder is in the format monthyear* eg Mar2015-1 - we also only want to bring in processed (those with a folder that contains processed) items if they have been put there today.

The information we want to return from each item is

RECEIVED DATE
,MODIFIED DATE
,SENDER NAME
,SENDER EMAIL ADDRESS
,SUBJECT
,FOLDER
,FOLDER PATH
,CATEGORY(s)

Is this possible with this script or am I barking up the wrong tree?

Glen Scales said...

Not with this script maybe try http://gsexdev.blogspot.com.au/2016/02/mining-clientinfo-property-in-messages.html

Cheers
Glen

Sonorous Synthesis said...

Will do, cheers Glen!