in , , , , ,

Pull Subscription Mailbox Merchandise transfer monitoring script MEC pattern 2

Pull Subscription Mailbox Item move tracking script MEC sample 2

Pull Subscription Mailbox Merchandise transfer monitoring script MEC pattern 2 That is the second of the Powershell script samples from my MEC speak final week. The thought behind this script is to trace the motion of Objects in a Mailbox between folders utilizing Pull Notifications in EWS, you possibly can learn extra about how Pull notifications work right here .  This script takes benefit of the truth that whenever you allow Single Merchandise Restoration any deletes you make in a Mailbox (exhausting or mushy) the Objects aren’t deleted fairly moved to the Dumpster v2 RecoverableItems folders. So if you happen to observe all of the transfer notification occasions you possibly can observe each the motion of Messages by guidelines, customers or deletes. eg the outcomes seem like

I’ve created two totally different variations of this script, the primary model subscribes to all folders in a Mailbox and runs constantly in opposition to the Mailbox and does a GetEvents request each minute to retrieve the most recent occasions from all folders in a Mailbox after which logs that to file.

The second model simply subscribes to the Inbox folder and saves the subscription data out to file whenever you run it the primary time. Then the subsequent time you run the script it should use the saved SubscriptionId and Watermark worth to get all of the occasions because the script was final run. Pull Subscriptions have a timeout of 1440 minutes (which is 1 day) so if you’ll run this model it is advisable to run it with a most hole of 1 day. The thought of this second model was simply to trace inbox fan-out of messages fairly then subscribing to all folders like the primary model.

Each of those scripts use EWS Impersonation which have to be configured for the account your going to run the script as. While you run the script it is advisable to move within the Mailbox to run in opposition to and the timeout worth in minutes for subscription which must between 1 and 1440 eg

./pullSubTrackWm.ps1 [email protected] 1440

I’ve put a download of each scripts right here the code itself seems to be like

  1. ## Get the Mailbox to Entry from the 1st commandline argument  
  2. $MailboxName = $args[0]  
  3. $period = $args[1]  
  4. $sw = [system.diagnostics.stopwatch]::startNew()  
  5. $Error.Clear()  
  6. $Script:changeLog = “c:tempChangeLog-$(get-date -f yyyy-MM-dd).csv”;   
  7. if(-Not(Take a look at-Path -Path $Script:changeLog)){  
  8.     Add-Content material -Path $Script:changeLog (“EventTime,MessageDateTimeReceived,Subject,MovedFrom,MovedTo,LastModifiedName”)  
  9. }  
  10. #Add-Content material -Path $Script:changeLog (“Start Log” + (Get-Date).ToString())   
  11.   
  12. ## Load Managed API dll    
  13. Add-Kind -Path “C:Program FilesMicrosoftExchangeWeb Services2.0Microsoft.Exchange.WebServices.dll”    
  14. Add-Kind -AssemblyName System.Runtime.Serialization  
  15. ## Set Change Model    
  16. $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Change2010_SP2    
  17.     
  18. ## Create Change Service Object    
  19. $service = New-Object Microsoft.Change.WebServices.Information.ExchangeService($ExchangeVersion)    
  20.     
  21. ## Set Credentials to use two choices are availible Option1 to use explict credentials or Choice 2 use the Default (logged On) credentials    
  22.     
  23. #Credentials Choice 1 utilizing UPN for the home windows Account    
  24. $psCred = Get-Credential    
  25. $creds = New-Object System.Web.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())    
  26. $service.Credentials = $creds        
  27.     
  28. #Credentials Choice 2    
  29. #service.UseDefaultCredentials = $true    
  30.     
  31. ## Select to ignore any SSL Warning points precipitated by Self Signed Certificates    
  32.     
  33. ## Code From http://poshcode.org/624  
  34. ## Create a compilation atmosphere  
  35. $Supplier=New-Object Microsoft.CSharp.CSharpCodeProvider  
  36. $Compiler=$Supplier.CreateCompiler()  
  37. $Params=New-Object System.CodeDom.Compiler.CompilerParameters  
  38. $Params.GenerateExecutable=$False  
  39. $Params.GenerateInMemory=$True  
  40. $Params.IncludeDebugInformation=$False  
  41. $Params.ReferencedAssemblies.Add(“System.DLL”) | Out-Null  
  42.   
  43. $TASource[email protected] 
  44.   namespace Native.ToolkitExtensions.Web.CertificatePolicy{ 
  45.     public class TrustAll : System.Web.ICertificatePolicy { 
  46.       public TrustAll() {  
  47.       } 
  48.       public bool CheckValidationResult(System.Web.ServicePoint sp, 
  49.         System.Safety.Cryptography.X509Certificates.X509Certificates cert,  
  50.         System.Web.WebRequest req, int downside) { 
  51.         return true; 
  52.       } 
  53.     } 
  54.   } 
  55. @   
  56. $TAResults=$Supplier.CompileAssemblyFromSource($Params,$TASource)  
  57. $TAAssembly=$TAResults.CompiledAssembly  
  58.   
  59. ## We now create an occasion of the TrustAll and connect it to the ServicePointManager  
  60. $TrustAll=$TAAssembly.CreateInstance(“Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll”)  
  61. [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll  
  62.   
  63. ## finish code from http://poshcode.org/624  
  64.     
  65. ## Set the URL of the CAS (Shopper Entry Server) to use two choices are availbe to use Autodiscover to discover the CAS URL or Hardcode the CAS to use    
  66.     
  67. #CAS URL Choice 1 Autodiscover    
  68. $service.AutodiscoverUrl($MailboxName,{$true})    
  69. “Using CAS Server : “ + $Service.url     
  70.   
  71.   
  72. #CAS URL Choice 2 Hardcoded    
  73.     
  74. #$uri=[system.URI] “https://casservername/ews/exchange.asmx”    
  75. #$service.Url = $uri      
  76.     
  77. ## Non-compulsory part for Change Impersonation    
  78.     
  79. $service.ImpersonatedUserId = new-object Microsoft.Change.WebServices.Information.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)   
  80. #test Anchor header for Change 2013/Workplace365    
  81. if($service.HttpHeaders.ContainsKey(“X-AnchorMailbox”)){    
  82.     $service.HttpHeaders[“X-AnchorMailbox”] = $MailboxName    
  83. }else{    
  84.     $service.HttpHeaders.Add(“X-AnchorMailbox”$MailboxName);    
  85.     $service.HttpHeaders.Add(“X-PreferServerAffinity”,“true”);  
  86. }    
  87. “AnchorMailbox : “ + $service.HttpHeaders[“X-AnchorMailbox”]    
  88.   
  89.   
  90.   
  91. $FolderCollection = New-Object System.Collections.Hashtable  
  92. #Outline Operate to convert String to FolderPath    
  93. perform ConvertToString($ipInputString){    
  94.     $Val1Text = “”    
  95.     for ($clInt=0;$clInt -lt $ipInputString.size;$clInt++){    
  96.             $Val1Text = $Val1Text + [Convert]::ToString([Convert]::ToChar([Convert]::ToInt32($ipInputString.Substring($clInt,2),16)))    
  97.             $clInt++    
  98.     }    
  99.     return $Val1Text    
  100. }   
  101.   
  102. #Outline Prolonged properties    
  103. $PR_FOLDER_TYPE = new-object Microsoft.Change.WebServices.Information.ExtendedPropertyDefinition(13825,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer);    
  104. $folderidcnt = new-object Microsoft.Change.WebServices.Information.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)    
  105. #Outline the FolderView used for Export ought to not be any bigger then 1000 folders due to throttling    
  106. $fvFolderView =  New-Object Microsoft.Change.WebServices.Information.FolderView(1000)    
  107. #Deep Transval will guarantee all folders in the search path are returned    
  108. $fvFolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep;    
  109. $psPropertySet = new-object Microsoft.Change.WebServices.Information.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)    
  110. $PR_Folder_Path = new-object Microsoft.Change.WebServices.Information.ExtendedPropertyDefinition(26293, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String);    
  111. #Add Properties to the  Property Set    
  112. $psPropertySet.Add($PR_Folder_Path);    
  113. $fvFolderView.PropertySet = $psPropertySet;    
  114. #The Search filter will exclude any Search Folders    
  115. $sfSearchFilter = new-object Microsoft.Change.WebServices.Information.SearchFilter+IsEqualTo($PR_FOLDER_TYPE,“1”)    
  116. $fiResult = $null    
  117. #The Do loop will deal with any paging that is required if there are extra the 1000 folders in a mailbox    
  118. do {    
  119.     $fiResult = $Service.FindFolders($folderidcnt,$sfSearchFilter,$fvFolderView)    
  120.     foreach($ffFolder in $fiResult.Folders){    
  121.         $foldpathval = $null    
  122.         #Attempt to get the FolderPath Worth and then covert it to a usable String     
  123.         if ($ffFolder.TryGetProperty($PR_Folder_Path,[ref] $foldpathval))    
  124.         {    
  125.             $binarry = [Text.Encoding]::UTF8.GetBytes($foldpathval)    
  126.             $hexArr = $binarry | ForEach-Object { $_.ToString(“X2”) }    
  127.             $hexString = $hexArr -join     
  128.             $hexString = $hexString.Change(“FEFF”“5C00”)    
  129.             $fpath = ConvertToString($hexString)    
  130.         }    
  131.         “FolderPath : “ + $fpath    
  132.         $FolderCollection.Add($ffFolder.Id.UniqueId,$fpath)  
  133.     }   
  134.     $fvFolderView.Offset += $fiResult.Folders.Rely  
  135. }whereas($fiResult.MoreAvailable -eq $true)    
  136.   
  137. perform GetEventsRequest{    
  138. param (  
  139.   $SubscriptionId=“$( throw ‘SubscriptionId is a mandatory Parameter’ )”,  
  140.   $Watermark=“$( throw ‘Credentials is a mandatory Parameter’ )”,  
  141.   $ImpersonationHeader=“$( throw ‘ImpersonationHeader is a mandatory Parameter’ )”  
  142. )  
  143. course of{  
  144. Write-Host($SubscriptionId)  
  145. $request = @ 
  146. <?xml model=”1.0” encoding=”utf-8“?> 
  147. <cleaning soap:Envelope xmlns:cleaning soap=”http://schemas.xmlsoap.org/cleaning soap/envelope/ 
  148.   xmlns:t=”http://schemas.microsoft.com/trade/companies/2006/varieties“> 
  149.    <cleaning soap:Header> 
  150.     <t:RequestServerVersion Model=”Change2010_SP2“/> 
  151.     <t:ExchangeImpersonation> 
  152.       <t:ConnectingSID> 
  153.         <t:SmtpAddress>$ImpersonationHeader</t:SmtpAddress> 
  154.       </t:ConnectingSID> 
  155.     </t:ExchangeImpersonation> 
  156.   </cleaning soap:Header> 
  157.   <cleaning soap:Physique> 
  158.     <GetEvents xmlns=”http://schemas.microsoft.com/trade/companies/2006/messages“> 
  159.       <SubscriptionId>$SubscriptionId</SubscriptionId> 
  160.       <Watermark>$Watermark</Watermark> 
  161.     </GetEvents> 
  162.   </cleaning soap:Physique> 
  163. </cleaning soap:Envelope> 
  164. @  
  165. return $request  
  166. }  
  167. }  
  168. $DeletionsID = new-object Microsoft.Change.WebServices.Information.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::RecoverableItemsDeletions,$MailboxName);  
  169. $Deletions = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$DeletionsID)  
  170. $evEvents = new-object Microsoft.Change.WebServices.Information.EventType[] 6  
  171. $evEvents[0] = [Microsoft.Exchange.WebServices.Data.EventType]::Copied  
  172. $evEvents[1] = [Microsoft.Exchange.WebServices.Data.EventType]::Created  
  173. $evEvents[2] = [Microsoft.Exchange.WebServices.Data.EventType]::Deleted  
  174. $evEvents[3] = [Microsoft.Exchange.WebServices.Data.EventType]::Modified  
  175. $evEvents[4] = [Microsoft.Exchange.WebServices.Data.EventType]::Moved  
  176. $evEvents[5] = [Microsoft.Exchange.WebServices.Data.EventType]::NewMail  
  177. $psSub = “”  
  178. if(Take a look at-Path -Path (“c:temp” + $MailboxName + “PullSubWM.wm“)){ 
  179.     $psSub = Import-Csv -Path (“c:temp” + $MailboxName + “PullSubWM.wm“) 
  180.     $request = GetEventsRequest -SubscriptionId $psSub.SubscriptionID -Watermark $psSub.Watermark -ImpersonationHeader $MailboxName 
  181.     $mbMailboxFolderURI = New-Object System.Uri($service.url)   
  182.     $wrWebRequest = [System.Net.WebRequest]::Create($mbMailboxFolderURI)   
  183.     $wrWebRequest.CookieContainer =  New-Object System.Web.CookieContainer    
  184.     $wrWebRequest.KeepAlive = $false;   
  185.     $wrWebRequest.Useragent = “EWS Script 
  186.     $wrWebRequest.Headers.Set(“Pragma“, “no-cache“);   
  187.     $wrWebRequest.Headers.Set(“Translate“, “f“);   
  188.     $wrWebRequest.Headers.Set(“Depth“, “0“);   
  189.     $wrWebRequest.ContentType = “textual content/xml“;   
  190.     $wrWebRequest.ContentLength = $expRequest.Size;   
  191.     $wrWebRequest.Timeout = 60000;   
  192.     $wrWebRequest.Technique = “POST“;   
  193.     $wrWebRequest.Credentials = $creds   
  194.     $bqByteQuery = [System.Text.Encoding]::ASCII.GetBytes($request);   
  195.     $wrWebRequest.ContentLength = $bqByteQuery.Size;   
  196.     $rsRequestStream = $wrWebRequest.GetRequestStream();   
  197.     $rsRequestStream.Write($bqByteQuery, 0, $bqByteQuery.Size);   
  198.     $rsRequestStream.Shut();   
  199.     $wrWebResponse = $wrWebRequest.GetResponse();   
  200.     $rsResponseStream = $wrWebResponse.GetResponseStream()   
  201.     $sr = new-object System.IO.StreamReader($rsResponseStream);   
  202.     $rdResponseDocument = New-Object System.Xml.XmlDocument   
  203.     $rdResponseDocument.LoadXml($sr.ReadToEnd()); 
  204.     $rdResponseDocument.Envelope.Physique.GetEventsResponse.ResponseMessages.GetEventsResponseMessage.ResponseClass 
  205.     if($rdResponseDocument.Envelope.Physique.GetEventsResponse.ResponseMessages.GetEventsResponseMessage.ResponseClass -eq “Error“) fl 
  206.         Take away-Merchandise (“c:temp” + $MailboxName + “PullSubWM.wm“) 
  207.         Write-Host (“Eliminated outdated watermarkFile“) 
  208.      
  209.     else{ 
  210.         if($rdResponseDocument.Envelope.Physique.GetEventsResponse.ResponseMessages.GetEventsResponseMessage.ResponseClass -eq “Success“){ 
  211.             $pullSubSav = “” | Choose Watermark,SubscriptionID 
  212.             $wmark2 = $rdResponseDocument.getElementsByTagName(“t:Watermark“)            
  213.             $pullSubSav.Watermark = $wmark2.Merchandise(($wmark2.Rely-1)).”#textual content”  
  214.             $pullSubSav.SubscriptionID = $rdResponseDocument.Envelope.Physique.GetEventsResponse.ResponseMessages.GetEventsResponseMessage.Notification.SubscriptionId  
  215.             $pullSubSav | Export-Csv -Path (“c:temp” + $MailboxName + “PullSubWM.wm“) -NoTypeInformation 
  216.             Write-Host “Subscription saved 
  217.             $movedEvents = $rdResponseDocument.getElementsByTagName(“t:MovedEvent“)  
  218.             if($movedEvents.Rely -gt 0){ 
  219.                 attempt{ 
  220.                     for($intmc=0;$intmc -lt $movedEvents.Rely;$intmc++){ 
  221.                         $merchandise = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service, $movedEvents.Merchandise($intmc).ItemId.Id); 
  222.                         $ItemEvt = “” | Choose EventTime,MessageDateTimeReceived,Topic,MovedFrom,MovedTo,LastModifiedName 
  223.                         $ItemEvt.EventTime = $movedEvents.Merchandise($intmc).TimeStamp 
  224.                         Write-Host (“Processing : ” + $merchandise.Topic) 
  225.                         write-host (“Final Modified by :” + $merchandise.LastModifiedName) 
  226.                         $ItemEvt.Topic = $merchandise.Topic  
  227.                         $ItemEvt.LastModifiedName = $merchandise.LastModifiedName 
  228.                         $ItemEvt.MessageDateTimeReceived = $merchandise.DateTimeReceived        
  229.                                  
  230.                         #$movedEvents.Merchandise($intmc).OldItemId.Id 
  231.                      
  232.                         if($FolderCollection.containsKey($movedEvents.Merchandise($intmc).OldParentFolderId.Id)){ 
  233.                             Write-Host (“Moved From Folder ” + $FolderCollection[$movedEvents.Item($intmc).OldParentFolderId.Id]) 
  234.                             $ItemEvt.MovedFrom = $FolderCollection[$movedEvents.Item($intmc).OldParentFolderId.Id] 
  235.                         }                    
  236.                         if($FolderCollection.containsKey($movedEvents.Merchandise($intmc).ParentFolderId.Id)){ 
  237.                             Write-Host (“Moved To Folder ” + $FolderCollection[$movedEvents.Item($intmc).ParentFolderId.Id]) 
  238.                             $ItemEvt.MovedTo = $FolderCollection[$movedEvents.Item($intmc).ParentFolderId.Id] 
  239.                         } 
  240.                         else{ 
  241.                              if ($movedEvents.Merchandise($intmc).ParentFolderId.Id -eq $Deletions.Id.UniqueId) 
  242.                              { 
  243.                                 Write-Host (“Moved to Recoverable Objects – Deleted Objects“);                           
  244.                              } 
  245.                              $ItemEvt.MovedTo = “Moved to Recoverable Objects – Deleted Objects 
  246.                         } 
  247.                         Add-Content material -Path $Script:changeLog ($ItemEvt.EventTime + “,`“” + $ItemEvt.MessageDateTimeReceived + “`”,`“” + $ItemEvt.Topic + “`”,” + $ItemEvt.MovedFrom + “,” + $ItemEvt.MovedTo + “,” + $ItemEvt.LastModifiedName) 
  248.                     } 
  249.                 } 
  250.                 catch fl) 
  251.                     $Error.Clear() 
  252.                  
  253.             } 
  254.  
  255.         } 
  256.     }    
  257. } 
  258. else Export-Csv -Path (“c:temp” + $MailboxName + “PullSubWM.wm“) -NoTypeInformation 
  259.     Write-Host “Subscription saved”  
  260.