Get calendar items (Outlook API, WebDAV) displaying strange behavior

We are writing a plugin for MS Outlook. To satisfy our business logic, he must check all appointments between dates. We are having some problems retrieving all items from calendars. We tried two options:

  1. Outlook API We use the standard logic described in MSDN - we sort the elements by [Start], set IncludeRecurrences to True and run the Find \ Restrict query on the calendar elements , as here . It works great in our test environment. However, among our clients: for recurring meetings, the start and end dates are set to the corresponding dates of the β€œmain meeting”. For example, in some premises calendar we have a weekly meeting that was created in January, and if we try to find all the elements in August, we will get, among others, four elements of this recurring meeting, but their start and end dates are set for January, But Outlook displays the correct dates on the same calendar ...

  2. Very bad, but we still have WebDAV! We are writing a simple test application and trying to request all the items from the calendar using WebDAV. Of course, we did not invent the bicycle and simply inserted the code from the documentation . The previous problem is solved, but the following arises: it does not return duplicate elements created more than six months ago. I have no idea - there are no parameters restricting the "old" objects!

What happened? Are we missing something?

Technical Details: Exchange 2003, Outlook 2003-2010. Honestly, the first error disappears if we enable the Exchange caching mode, but we cannot do this.

 var nameSpace = application.GetNamespace("MAPI"); var recepient = nameSpace.CreateRecipient(roomEMail); recepient.Resolve(); var calendar = nameSpace.GetSharedDefaultFolder(recepient, OlDefaultFolders.olFolderCalendar); var filter = string.Format("[Start]<'{1}' AND [End]>'{0}'", dateFrom.ToString("dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture), dateTo.ToString("dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture) ); var allItems = calendar.Items; allItems.Sort("[Start]"); allItems.IncludeRecurrences = true; var _item = allItems.Find(filter); while (_item != null) { AppointmentItem item = _item as AppointmentItem; if (item != null) { if (item.Subject != "some const") && (item.ResponseStatus != OlResponseStatus.olResponseDeclined) && (item.MeetingStatus != OlMeetingStatus.olMeetingReceivedAndCanceled && item.MeetingStatus != OlMeetingStatus.olMeetingCanceled)) { /* Here we copy item to our internal class. * We need: Subject, Start, End, Organizer, Recipients, MeetingStatus, * AllDayEvent, IsRecurring, RecurrentState, ResponseStatus, * GlobalAppointmentID */ } } _item = allItems.FindNext(); } 

UPDATE 1:

Additional research using OutlookSpy shows that the problem is not in our code - the start / end dates are incorrect inside the API when the Exchange caching mode is disabled. But the Outlook developers knew about it, and somehow they displayed the correct dates on the calendars! Does anyone know how?

UPDATE 2:

Outlook support support engineer answer:

Based on this, I can confirm that this is a problem in our product.

+79
outlook webdav exchange-server outlook-object-model
Aug 28 2018-12-12T00:
source share
1 answer

Possible reason:

  • Sort after setting IncludeRecurrence.

Here is my PowerShell module code that retrieves Outlook items between two dates.

And a small applet for checking changes and sending emails, including updating the agenda, which is very convenient when you do not have mobile access to Exchange.

Path: Documents \ WindowsPowerShell \ Modules \ Outlook \ expcal.ps1

 Function Get-OutlookCalendar { <# .Synopsis This function returns appointment items from default Outlook profile .Description This function returns appointment items from the default Outlook profile. It uses the Outlook interop assembly to use the olFolderCalendar enumeration. It creates a custom object consisting of Subject, Start, Duration, Location for each appointment item. .Example Get-OutlookCalendar | where-object { $_.start -gt [datetime]"5/10/2011" -AND $_.start -lt ' [datetime]"5/17/2011" } | sort-object Duration Displays subject, start, duration and location for all appointments that occur between 5/10/11 and 5/17/11 and sorts by duration of the appointment. The sort is the shortest appointment on top. .Notes NAME: Get-OutlookCalendar AUTHOR: ed wilson, msft LASTEDIT: 05/10/2011 08:36:42 KEYWORDS: Microsoft Outlook, Office HSG: HSG-05-24-2011 .Link Http://www.ScriptingGuys.com/blog #Requires -Version 2.0 #> echo Starting... Initialize variables Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null $olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type] $olCalendarDetail = "Microsoft.Office.Interop.Outlook.OlCalendarDetail" -as [type] echo ... Getting ref to Outlook and Calendar ... $outlook = new-object -comobject outlook.application $namespace = $outlook.GetNameSpace("MAPI") $folder = $namespace.getDefaultFolder($olFolders::olFolderCalendar) echo ... Calculating dates ... $now = Get-Date -Hour 0 -Minute 00 -Second 00 echo From $a To $b echo ... Getting appointments ... $Appointments = $folder.Items $Appointments.IncludeRecurrences = $true $Appointments.Sort("[Start]") echo ... Setting file names ... $oldfile = "$env:USERPROFILE\outlook-calendar.bak" echo oldfile: $oldfile $newfile = "$env:USERPROFILE\outlook-calendar.txt" echo newfile: $newfile $calfile = "$env:USERPROFILE\outlook-calendar.ics" echo calfile: $calfile echo ... Exporting calendar to $calfile ... $calendarSharing = $folder.GetCalendarExporter() $calendarSharing.CalendarDetail = $olCalendarDetail::olFullDetails $calendarSharing.IncludeWholeCalendar = $false $calendarSharing.IncludeAttachments = $false $calendarSharing.IncludePrivateDetails = $true $calendarSharing.RestrictToWorkingHours = $false $calendarSharing.StartDate = $now.AddDays(-30) $calendarSharing.EndDate = $now.AddDays(30) echo $calendarSharing $calendarSharing.SaveAsICal($calfile) echo ... Backing up $newfile into $oldfile ... if (!(Test-Path $newfile)) { echo "" |Out-File $newfile } # Backup old export into $oldfile if (Test-Path $oldfile) { echo "Deleting old backup file $oldfile" del $oldfile } echo " ... moving $newfile into $oldfile ... " move $newfile $oldfile echo "... Generating text report to file $newfile ..." $Appointments | Where-object { $_.start -gt $now -AND $_.start -lt $now.AddDays(+7) } | Select-Object -Property Subject, Start, Duration, Location, IsRecurring, RecurrenceState | Sort-object Start | Out-File $newfile -Width 100 echo "... Comparing with previous export for changes ..." $oldsize = (Get-Item $oldfile).length $newsize = (Get-Item $newfile).length if ($oldsize -ne $newsize ) { echo "!!! Detected calendar change. Sending email..." $mail = $outlook.CreateItem(0) #2 = high importance email header $mail.importance = 2 $mail.subject = $env:computername + ' Outlook Calendar' $mail.Attachments.Add($newfile) $mail.Attachments.Add($calfile) $text = Get-Content $newfile | Out-String $mail.body = 'See attached file...' + $text #for multiple email, use semi-colon ; to separate $mail.To = 'your-email@your-mail-domain.com' $mail.Send() } else { echo "No changes detected in Calendar!" } } #end function Get-OutlookCalendar Function Get-OutlookCalendarTest { echo starting... Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null $olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type] $outlook = new-object -comobject outlook.application $namespace = $outlook.GetNameSpace("MAPI") $folder = $namespace.getDefaultFolder($olFolders::olFolderCalendar) $a = Get-Date -Hour 0 -Minute 00 -Second 00 $b = (Get-Date -Hour 0 -Minute 00 -Second 00).AddDays(7) echo From $a To $b $Appointments = $folder.Items $Appointments.IncludeRecurrences = $true $Appointments.Sort("[Start]") $Appointments | Where-object { $_.start -gt $a -AND $_.start -lt $b } | Select-Object -Property IsRecurring, RecurrenceState, Subject, Start, Location } #end function Get-OutlookCalendarTest 

This is the code to call the PowerShell function in the module:

Path: Documents \ WindowsPowerShell \ mono.ps1

 Import-Module -Name Outlook\expcal.psm1 -Force $i=0 #infinite loop for calling connect function while(1) { $i = $i +1 Write-Output "Running task Get-OutlookCalendar ($i)" Get-OutlookCalendar start-sleep -seconds 300 } 

To run a PowerShell script, use powershell.exe. To start this at startup, use the shortcut "% APPDATA% \ Microsoft \ Windows \ Start Menu \ Programs \ Startup \":

 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "C:\Users\%USERNAME%\Documents\WindowsPowerShell\mono.ps1" 
+1
May 28 '18 at 8:28
source share



All Articles