For troubleshooting, we sometime need to dive into MAPI properties.
To do this, we usually use Outlook Spy or MFCMAPI.
They both work great and let you debug the MAPI properties in GUI.
The third approach is use EWS(Exchange WebServices) through PowerShell.
The benefit of using PowerShell to see the MAPI properties is that we can work with the data easily.
These are the use cases from my mailbox.
- Disk space saved by replacing the email with ShortCut.
PS>$return_object | %{if($_.OriginalSize -gt $_.Size){$_.OriginalSize - $_.Size}} | Measure-Object -Sum -Maximum|ft Count,Sum,Maximum -AutoSize Count Sum Maximum ----- --- ------- 122 5324215 551692
Total of 5324215 bytes were saved and the maximum was 551692 bytes.
- Average days Enterprise Vault archived the emails.
PS> $return_object | %{($_.ArchivedDate - $_.DateTimeReceived).Days} | Measure-Object -Average|format-table Count,Average -autosize Count Average ----- ------- 122 25.5081967213115
- When did the archive run ?
PS > $return_object|Group-Object {($_.ArchivedDate).toShortDateString()}|Sort-Object name -Descending|ft Name,Count -AutoSize Name Count ---- ----- 2014/05/08 17 2014/05/07 70 2014/05/06 23 2014/05/05 11 2014/05/02 1 2014/05/01 7 2014/04/30 12
- Which emails were archived on 2014-05-07?
PS > $return_object | where-object {(($_.ArchivedDate -gt (get-date 2014-05-07)) -and ($_.ArchivedDate -lt (get-date 2014-05-08)))} | format-table DateTimeReceived,ArchivedDate,Sender,Subject -autosize DateTimeReceived ArchivedDate Sender Subject ---------------- ------------ ------ ------- 2014/04/09 21:55:25 2014/05/07 9:43:01 Christopher Loak New Lab budget 2014/04/09 22:00:59 2014/05/07 9:43:01 Scott Mathews Feature News 2014/04/09 22:12:18 2014/05/07 9:43:02 Ted Johnson Re:New Lab budget ..
Once you have the data from EWS, you can sort or filter with any property you like.
Other possible use case are
- Search for emals with specifig MAPI property with specif value.
- Loop through the Folder and watch if any property changed
Let's go through how this is done.
First you need to install "Microsoft Exchange Web Services Managed API".
http://www.microsoft.com/en-us/download/confirmation.aspx?id=35371
Import the Microsoft.Exchange.WebServices.dll to your PowerShell session.
PS>Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
Then we connect to the Exchange Service.
We have to specify the version of Exchange Version you are connecting.
If you do not know which version, see this article or you can try your luck (There are only 5 versions that support EWS).
http://office.microsoft.com/en-001/outlook-help/determine-the-version-of...
Exchange2007_SP1
Exchange2010
Exchange2010_SP1
Exchange2010_SP2
Exchange2013
PS>$exchService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2, [System.TimeZoneInfo]::Local)
Use the default credential to connect to Exchange Server and use your email address to auto discover the EWS access point.
PS > $exchService.UseDefaultCredentials = $true PS > $exchService.AutodiscoverUrl("YOUR@EMAIL_ADDRESS")
This part is creating the Filter criteria.
The example is specifying any items with "IPM.Note.EnterpriseVault.Shortcut" ItemClass.
PS > $searchFilterCollection = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::Or) PS > $searchFilter1 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.ContactSchema]::ItemClass,"IPM.Note.EnterpriseVault.Shortcut") PS > $searchFilterCollection.add($searchFilter1)
This part is creating a MAPI Protery Set that you are interested in.
Archive Date is a custom MAPI Property created by the Enterprise Vault so need to specify the GUID, name and the Type.
PS > $prArchiveDate = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([GUID]"D0F41A15-9E91-D111-84E6-0000F877D428","Archived Date",[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::SystemTime) PS > $prArchiveDatePropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet($prArchiveDate ) PS > $customPropSet = new-object Microsoft.Exchange.WebServices.Data.PropertySet($prArchiveDatePropertySet)
Add any other properties in interest.
PS > $customPropSet.add([Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject) PS > $customPropSet.add([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived) PS > $customPropSet.add([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Sender)
This part creates a view of the query result from the EWS.
This is specifying that only 50 items are returned from Exchange so that unexpected large amount of items are not returned.
Also it is setting the custom PropSet created earlier and sorting with DateTimeReceived.
PS > $itemView = new-object Microsoft.Exchange.WebServices.Data.ItemView(50,0,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning) PS > $itemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow PS > $itemView.PropertySet=$customPropSet PS > $itemView.OrderBy.add([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived,[Microsoft.Exchange.WebServices.Data.SortDirection]::Ascending)
The last part is doing the actual search.
We get the results from the EWS only 50 items per query so loop though the result untill we get all the result.
The result is put into a custom object which makes the sorting and filtering in PowerShell easier.
PS > $return_object =@() PS > do { $FindItems = $exchService.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$searchFilterCollection,$itemView) foreach ($eItems in $FindItems.Items){ $props = @{ DateTimeReceived = $eItems.DateTimeReceived ArchivedDate = $eItems.ExtendedProperties[0].Value; Sender = $eItems.Sender.Name; Subject = $eItems.Subject } $return_object += New-Object -TypeName PSCustomObject -Property $props } $itemView.Offset= $itemView.Offset + $itemView.PageSize }while ($FindItems.MoreAvailable)
At last, we have result in $return_object.
With this result, we can filter , count as you like.
PS > $return_object | where-object {(($_.ArchivedDate -gt (get-date 2014-05-07)) -and ($_.ArchivedDate -lt (get-date 2014-05-08)))} | format-table DateTimeReceived,ArchivedDate,DiffData,Sender,Subject -autosize
This is the script all in one.
Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll" $exchService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::YOUR_EXCHANGE_VERSION, [System.TimeZoneInfo]::Local) $exchService.UseDefaultCredentials = $true $exchService.AutodiscoverUrl("YOUR@EMAIL_ADDRESS") $searchFilterCollection = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::Or) $searchFilter1 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.ContactSchema]::ItemClass,"IPM.Note.EnterpriseVault.Shortcut") $searchFilterCollection.add($searchFilter1) $prArchiveDate = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([GUID]"D0F41A15-9E91-D111-84E6-0000F877D428","Archived Date",[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::SystemTime) $prArchiveDatePropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet($prArchiveDate ) $prOriginalSize = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([GUID]"D0F41A15-9E91-D111-84E6-0000F877D428","Original Size",[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer) $prArchiveDatePropertySet.add($prOriginalSize) $customPropSet = new-object Microsoft.Exchange.WebServices.Data.PropertySet($prArchiveDatePropertySet) $customPropSet.add([Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject) $customPropSet.add([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived) $customPropSet.add([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Sender) $itemView = new-object Microsoft.Exchange.WebServices.Data.ItemView(50,0,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning) $itemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow $itemView.PropertySet=$customPropSet $itemView.OrderBy.add([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived,[Microsoft.Exchange.WebServices.Data.SortDirection]::Ascending) $return_object =@() do { $FindItems = $exchService.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$searchFilterCollection,$itemView) foreach ($eItems in $FindItems.Items){ $props = @{ DateTimeReceived = $eItems.DateTimeReceived ArchivedDate = $eItems.ExtendedProperties[0].Value; Sender = $eItems.Sender.Name; Subject = $eItems.Subject; Size = $eItems.Size; OriginalSize = $eItems.ExtendedProperties[1].Value; } $return_object += New-Object -TypeName PSCustomObject -Property $props } $itemView.Offset= $itemView.Offset + $itemView.PageSize }while ($FindItems.MoreAvailable) $return_object | where-object {(($_.ArchivedDate -gt (get-date 2014-05-07)) -and ($_.ArchivedDate -lt (get-date 2014-05-08)))} | format-table DateTimeReceived,ArchivedDate,DiffData,Sender,Subject -autosize