Thursday, 30 January 2014

SCSM: Changing the Message Class of Emails for Ingestion

Scenario

We have deployed SCSM (System Centre Service Manager), and setup a mailbox for receiving and processing service requests. We also have a custom Outlook com-addin installed on all workstations. The addin ensures email is filed to our DMS (Document Management System). When the addin processes email, it changes the message class of the email from IPM.Note to a one of four custom message classes. For example, email that is filed to the DMS, gets the new message class IPM.Note.Imc.Dms.Filed.

This causes a problem with the SCSM ingestion process. When someone emails a service request to the SCSM mailbox, if they file the message, the message class will be changed. The SCSM ingestion process only processes emails that have a message class of IPM.Note. This results in emails that don't get processed by SCSM, and service requests that "are lost".

Solution

Have something runs on a schedule and updates the message class of all emails in the SCSM mailbox that have a custom message class. Sounds simple right? Well, using PowerShell and EWS (Exchange Web Services), it actually is!

The script below demonstrates using EWS to search the inbox of a mailbox, looking for emails that contain a specific value in the message class. Once the search has finished, the script iterates through the collection of items, changing the message class back to IPM.Note.

To work with EWS and PowerShell, you'll need to meet the following requirements
And here's the PowerShell... to the rescue again!

#Get the SCSM Mailbox            
$Identity = Get-Mailbox SCSM             
#Load the Exchange Web Services DLL            
$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll";                        
[void][Reflection.Assembly]::LoadFile($dllpath);                        
#Create a service reference            
$Service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1);                        
$mailAddress = $Identity.PrimarySmtpAddress.ToString();                        
$Service.AutodiscoverUrl($mailAddress);                        
$enumSmtpAddress = [Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress                        
#Set Impersonation            
$Service.ImpersonatedUserId =  New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId($enumSmtpAddress,$mailAddress);             
#Limit the page size. If there are more than 100 results returned from the search, we'll page through them            
$pageSize=100;                        
$pageLimitOffset=0;                        
$getMoreItems=$true;                        
$itemCount=0;                        
#These are the properties that we want returned with our search results            
$propItemSubject = [Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject;            
$propItemClass = [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass;                     
$itemsProcessed = 0;            
                        
while ($getMoreItems)                        
{                           
 #Create a view that includes the page size and page offset            
 $view = new-object Microsoft.Exchange.WebServices.Data.ItemView($pageSize,$pageLimitOffset,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning);                        
 $view.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow;                         
 #Add the two properties to the view            
 $view.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet($propItemClass,$propItemSubject);                         
 #Define the first filter. This filter is used to look for any email with a message class that contains "IMC" and is used to find emails containing our custom message class            
 $searchFilterItemClass1 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring($propItemClass,"IMC",[Microsoft.Exchange.WebServices.Data.ContainmentMode]::Substring,[Microsoft.Exchange.WebServices.Data.ComparisonMode]::IgnoreCase);            
 #Define the first filter. This filter is used to look for any email with a message class that contains "OofTemplate", and is used to find Out Of Office emails            
 $searchFilterItemClass2 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring($propItemClass,"OofTemplate",[Microsoft.Exchange.WebServices.Data.ContainmentMode]::Substring,[Microsoft.Exchange.WebServices.Data.ComparisonMode]::IgnoreCase);            
 #Create a search filter collection            
 $searchFilters = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::Or);                        
 #Add the two search filters to the collection            
 $searchFilters.add($searchFilterItemClass1);                        
 $searchFilters.add($searchFilterItemClass2);             
 #Perform the search            
 $mailItems = $Service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$searchFilters,$view);                         
 #Iterate through the emails, updating the message class            
 foreach ($item in $mailItems.Items)                        
 {                        
  if ($item.GetType().FullName -eq "Microsoft.Exchange.WebServices.Data.EmailMessage")                        
  {                            
   Write-Host ([String]::Format("************** {0} ******************",$item.Subject));                        
   Write-Host "Message Class:"$item.ItemClass;            
   $item.ItemClass = "IPM.Note";            
   $item.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite);            
   Write-Host ([String]::Format("Item updated.",$item.Subject));             
   $itemsProcessed++;            
  }                        
 }            
 #Check if there are more emails available in the mailbox that match our search criteria            
 if ($mailItems.MoreAvailable -eq $false){$getMoreItems = $false}            
 #If there are more items to get, update the page offset            
 if ($getMoreItems){$pageLimitOffset += $pageSize}                         
}            
Write-Host ([String]::Format("Updated the message class on {0} mail items.",$itemsProcessed));             

References