none
Powershell EWS Pull Notifications RRS feed

  • Question

  • Hi,

    I am attempting to write a Pull Notification client with the intended purpose of updating an external room resource database.  I found a few C SHarp examples and have gotten pretty far in creating the subscription.  However, after i get back the Subscription Id, I am having a hard time parsing through the resultant notification records.

    I am trying to use the Powershell ISE in order to see the status, I have forund the previous watermark, but cannot seem to get the current watermark ...

    Any help or tips would be MUCH appreciated!

    Thanks,

    Bob

    Code: (not the cleanest, please be gentle!)

    ## Setup the Exchange Service Binding
    $uri = "https://e1/ews/exchange.asmx"
    $esb = new-webserviceproxy -NameSpace "EWS" -URI $uri -UseDefaultCredential
    $esb.RequestServerVersionValue = new-object EWS.RequestServerVersion

    $esb.RequestServerVersionValue.Version = [EWS.ExchangeVersionType]::Exchange2007_SP1
    $esb.Url = $uri

    #Create the Subscription Request, pull
    $subscribeRequest= new-object EWS.SubscribeType
    $pullSubscription= new-object EWS.PullSubscriptionRequestType

    [EWS.DistinguishedFolderIdType]$parentfolderid = new-object EWS.DistinguishedFolderIdType
    $parentfolderid.Id = [EWS.DistinguishedFolderIdNameType]::calendar
    [EWS.BaseFolderIdType[]]$parentfolderids = $parentfolderid

    $pullsubscription.Folderids=$parentfolderids
    $eventtypes=new-object EWS.NotificationEventTypeType
    $eventtypes="CreatedEvent"
    $pullsubscription.eventtypes=$eventtypes
    $pullsubscription.Timeout=10
    $subscriberequest.Item=$pullsubscription

    #Send the Subscribe Request
    $subscriberesponse=$esb.Subscribe($subscriberequest)

    if ($subscriberesponse.ResponseMessages.Items.Length -gt 0 -and $subscriberesponse.ResponseMessages.Items[0].ResponseClass -eq "Success") {
        write-host "Subscription Created ..."
        $subscribeResponseMessage=new-object EWS.SubscriberesponseMessagetype
        $subscriberesponsemessage=$subscriberesponse.ResponseMessages.Items[0]
        $subscribeResponseMessage.SubscriptionId
        $subscribeResponseMessage.Watermark
       
        sleep 5
       
    #Code works to here, manual requests for new events will generate an Invalid watermark error.

        
        #to parse events
        $getEventsRequest=new-object EWS.GetEventsType
        $getEventsRequest.SubscriptionId=$subscriberesponseMessage.Subscriptionid
        $getEventsRequest.watermark=$subscriberesponseMessage.Watermark
        $eventsresponse=$esb.GetEvents($getEventsRequest)
       
        #$eventsresponseMessages=new-object EWS.ArrayofResponseMessagesType
        #$eventsresponseMessages=$eventsresponse
        $eventsresponse.ResponseMessages.Items.Length
       
        #$getEventsRequest.Watermark=$eventsresponse.ResponseMessages.items[0].notification.PreviousWatermark
        #$eventsresponse=$esb.GetEvents($getEventsRequest)
        #$eventsresponse.responsemessages.items[0].notification
       
        $eventsnotification=new-object EWS.Notificationtype
        $eventsresponseMessage= new-object EWS.GetEventsResponseMessageType
        $type=new-object EWS.ItemsChoicetype
       
        foreach ($type in $eventsresponsemessage.Notification.Items) {
            $type
         }  
       
        }

     

     


    robsmith
    Thursday, February 10, 2011 4:24 PM

Answers

  • I'd suggest you look at the EWS Managed API instead to do as this will drop the level of complexity of what your trying to do eg the following works fine in powershell in the Managed API. One restriction with pull subscriptions you should be aware of is they have a maximum duration of 24 hours

    $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)
    $service.Credentials = New-Object System.Net.NetworkCredential("username","password")
    $MailboxName = "mail@domnain.com"
    $service.autodiscoverurl($MailboxName,{$true})
    $InboxId = $folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)
    $fldArray = new-object Microsoft.Exchange.WebServices.Data.FolderId[] 1
    $fldArray[0] = $InboxId
    $pullSubscription = $service.SubscribeToPullNotifications($fldArray,60,$null,[Microsoft.Exchange.WebServices.Data.EventType]::NewMail)
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
      
       	switch ($notificationEvent.EventType)
          {
            EventType.NewMail {"New Mail"}
          }
    }
    read-host "Press key to check next events"
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
       	switch ($notificationEvent.EventType)
          {
            "NewMail" {
    				$item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service,$notificationEvent.ItemId)
    				$item.Subject
    			 }
    						
          }
    }
    
    • Marked as answer by robesmithjr Tuesday, February 15, 2011 2:59 PM
    Monday, February 14, 2011 3:17 AM
  • To Subscribe to multiple events just pass in an array of those events eg

    $evtArray = New-Object Microsoft.Exchange.WebServices.Data.EventType[] 5
    $evtArray[0] = [Microsoft.Exchange.WebServices.Data.EventType]::NewMail
    $evtArray[1] = [Microsoft.Exchange.WebServices.Data.EventType]::Created
    $evtArray[2] = [Microsoft.Exchange.WebServices.Data.EventType]::Modified
    $evtArray[3] = [Microsoft.Exchange.WebServices.Data.EventType]::Deleted
    $evtArray[4] = [Microsoft.Exchange.WebServices.Data.EventType]::Copied
    $pullSubscription = $service.SubscribeToPullNotifications($fldArray,60,$null,$evtArray)
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
      
       	switch ($notificationEvent.EventType)
          {
            EventType.NewMail {"New Mail"}
          }
    }
    read-host "Press key to check next events"
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
       	switch ($notificationEvent.EventType)
          {
            "NewMail" {
    				$item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service,$notificationEvent.ItemId)
    				$item.Subject
    			 }
    			  "Created" {
    				$item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service,$notificationEvent.ItemId)
    				$item.Subject
    			 }
    

    The Watermark gets held in the PullSubscrption object and its available in the Watermark property if you want to export it or save it for later use.

    Cheers
    Glen

    • Marked as answer by robesmithjr Tuesday, February 15, 2011 3:00 PM
    Tuesday, February 15, 2011 2:31 AM

All replies

  • Hello,

    I spent most of today cleaning things up and know I am close to getting this going.  If one of you powerShell / EWS gurus could help me out, I would be eternally grateful::

    Newest Code (transcribed from MSDN samples):

    function ExchangeServiceBinding{
        # Setup the Exchange Service Binding
        $uri = "https://e1/ews/exchange.asmx"
        $esb = new-webserviceproxy -NameSpace "EWS" -URI $uri -UseDefaultCredential
        $esb.RequestServerVersionValue = new-object EWS.RequestServerVersion

        $esb.RequestServerVersionValue.Version = [EWS.ExchangeVersionType]::Exchange2007_SP1
        $esb.Url = $uri
        return $esb
    }

    function Subscribe{
       
        #Create the Subscription Request, pull
        $subscribeRequest= new-object EWS.SubscribeType
        $pullSubscription= new-object EWS.PullSubscriptionRequestType

        [EWS.DistinguishedFolderIdType]$parentfolderid = new-object EWS.DistinguishedFolderIdType
        $parentfolderid.Id = [EWS.DistinguishedFolderIdNameType]::inbox
        [EWS.BaseFolderIdType[]]$parentfolderids = $parentfolderid

        $pullsubscription.Folderids=$parentfolderids
        $eventtypes=new-object EWS.NotificationEventTypeType
        $eventtypes=[EWS.NotificationEventTypeType]::NewMailEvent
        $pullsubscription.eventtypes=$eventtypes
        $pullsubscription.Timeout=10
        $subscriberequest.Item=$pullsubscription

            #Send the Subscribe Request
        $subscriberesponse=$esb.Subscribe($subscriberequest)
       
            if ($subscriberesponse.ResponseMessages.Items.Length -gt 0 -and $subscriberesponse.ResponseMessages.Items[0].ResponseClass -eq "Success") {
                write-host "Subscription Created ..."
                $subscribeResponseMessage=new-object EWS.SubscriberesponseMessagetype
                $subscriberesponsemessage=$subscriberesponse.ResponseMessages.Items[0]
                $subscribeResponseMessage.SubscriptionId #Returned as position [0] in the $Sub array
                $subscribeResponseMessage.Watermark #Returned as position [1] in the $Sub array
                return $subscriberesponse #Returned as an object at position [3] in the $Sub array
        }
    }

     Function UnSubscribe{
        $unsubscribeReq=new-object EWS.UnsubscribeType
        $unsubscribereq.subscriptionid=$args[0]         #$subscriberesponse.ResponseMessages.Items[0].Subscriptionid
        [EWS.UnsubscriberesponseType]$unsubscriberesponse=$esb.Unsubscribe($unsubscribeReq)
        return $unsubscriberesponse.ResponseMessages.Items[0].MessageText

     

    }

    Function GetEvents
    {
        "Getting Events ..."
     
        # Create the GetEvents request.
        $request = new-object EWS.GetEventsType

        # Identify the subscription identifier and watermark for the subscription
        # that will be polled for changes in the Exchange store.
        $request.SubscriptionId = $args[0]      #$subscribeResponseMessage.SubscriptionId
        $request.Watermark = $args[1]           #$subscribeResponseMessage.Watermark

        $request
        # Send the request and get the response.
        $response=new-object EWS.GetEventsResponseType
        $response = $esb.GetEvents($request)
          
        [EWS.ArrayOfResponseMessagesType]$aormt = $response.ResponseMessages
        [EWS.ResponseMessageType[]] $rmta = $aormt.Items
      
        #$aormt.Items.Length + " messages returned ..."
        $rmt=new-object EWS.ResponseMessageType
        foreach ($rmt in $rmta)
        {
            #Code works to here ...
            # Determine whether the request was a success.
            if ($rmt.ResponseClass.ToString() -eq "Success")
            {
                # Cast to appropriate response message type.
                $responseMessage = new-object EWS.GetEventsResponseMessageType

                # Get the notifications.
                [EWS.NotificationType]$notificaton = $responseMessage.Notification
                [EWS.NotificationType]$notificaton =  $aormt.Items[0].Notification
                [EWS.BaseNotificationEventType[]]$bneta = $notificaton.Items
               
                $bnet=new-object EWS.BaseNotificationEventType
                    foreach ($bnet in $bneta)
                        {
                            #$bnet.Item[0]
                            #$bnet|gm
                            #$bnet|fl
                    # TODO: Handle each notification. Refer to the Push Notification
                    #       sample for an example of how to do this.
                        }

                if ($notificaton.MoreEvents)
                {
                       #$notification|gm
                        #$notification|fl
                    # TODO: Call GetEvents again with the watermark to get the
                    #       remaining events.
                }
               
    }
     
    }
    }

    new-variable -name esb -scope "Global"
    new-variable -name Sub -scope "Global"
    new-variable -name UnSub -scope "Global"

    $esb=ExchangeServiceBinding
    "Using " + $esb.Url + "..."
    $Sub=Subscribe
    $sub[2].ResponseMessages.items[0]


    #while ($TRUE)
    #{

      # sleep 10
       GetEvents $sub[0] $sub[1]
       
    #}

     

     

     


    robsmith
    Friday, February 11, 2011 8:28 PM
  • I'd suggest you look at the EWS Managed API instead to do as this will drop the level of complexity of what your trying to do eg the following works fine in powershell in the Managed API. One restriction with pull subscriptions you should be aware of is they have a maximum duration of 24 hours

    $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)
    $service.Credentials = New-Object System.Net.NetworkCredential("username","password")
    $MailboxName = "mail@domnain.com"
    $service.autodiscoverurl($MailboxName,{$true})
    $InboxId = $folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName)
    $fldArray = new-object Microsoft.Exchange.WebServices.Data.FolderId[] 1
    $fldArray[0] = $InboxId
    $pullSubscription = $service.SubscribeToPullNotifications($fldArray,60,$null,[Microsoft.Exchange.WebServices.Data.EventType]::NewMail)
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
      
       	switch ($notificationEvent.EventType)
          {
            EventType.NewMail {"New Mail"}
          }
    }
    read-host "Press key to check next events"
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
       	switch ($notificationEvent.EventType)
          {
            "NewMail" {
    				$item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service,$notificationEvent.ItemId)
    				$item.Subject
    			 }
    						
          }
    }
    
    • Marked as answer by robesmithjr Tuesday, February 15, 2011 2:59 PM
    Monday, February 14, 2011 3:17 AM
  • Glen,

    Thanks for the reply.  I thought that I was going about this the right way, as other examples showed using the web-service proxy instead of calling the API directly. 

    The example you sent works, thank you.  How does it derive the Watermark for the next call to getevents?

    Thanks again for all of your help!

    Rob


    robsmith
    Monday, February 14, 2011 4:16 PM
  • Glenn,

    My intent is to use this for syncing Calendar items to a Linux based calendar app.  Thanks for the info that the subscription is only valid for 24 hours.

    I seem to be running into more trouble.  I have changed things around so that I can subscribe to "Created" events, but can't seem to subscribe to multiple events.  In other words, "Created", "Modified" and "Deleted" events.  

    Thanks again for your help!

    Rob

     


    robsmith
    Monday, February 14, 2011 8:17 PM
  • To Subscribe to multiple events just pass in an array of those events eg

    $evtArray = New-Object Microsoft.Exchange.WebServices.Data.EventType[] 5
    $evtArray[0] = [Microsoft.Exchange.WebServices.Data.EventType]::NewMail
    $evtArray[1] = [Microsoft.Exchange.WebServices.Data.EventType]::Created
    $evtArray[2] = [Microsoft.Exchange.WebServices.Data.EventType]::Modified
    $evtArray[3] = [Microsoft.Exchange.WebServices.Data.EventType]::Deleted
    $evtArray[4] = [Microsoft.Exchange.WebServices.Data.EventType]::Copied
    $pullSubscription = $service.SubscribeToPullNotifications($fldArray,60,$null,$evtArray)
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
      
       	switch ($notificationEvent.EventType)
          {
            EventType.NewMail {"New Mail"}
          }
    }
    read-host "Press key to check next events"
    $events = $pullSubscription.GetEvents();
    foreach ($notificationEvent in $events.AllEvents)
    {
       	switch ($notificationEvent.EventType)
          {
            "NewMail" {
    				$item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service,$notificationEvent.ItemId)
    				$item.Subject
    			 }
    			  "Created" {
    				$item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($service,$notificationEvent.ItemId)
    				$item.Subject
    			 }
    

    The Watermark gets held in the PullSubscrption object and its available in the Watermark property if you want to export it or save it for later use.

    Cheers
    Glen

    • Marked as answer by robesmithjr Tuesday, February 15, 2011 3:00 PM
    Tuesday, February 15, 2011 2:31 AM
  • Glen,

    Thank you so much for your help on this!  I just received my book on EWS today and will be reading more about the capabilities of the API.

    I spent many days trying to work through this, your assistance is much appreciated ...

    Rob


    robsmith
    Tuesday, February 15, 2011 3:02 PM