检索显示奇怪行为的日历项目(Outlook API、WebDAV)
Posted
技术标签:
【中文标题】检索显示奇怪行为的日历项目(Outlook API、WebDAV)【英文标题】:Retrieve calendar items (Outlook API, WebDAV) displaying strange behaviour 【发布时间】:2012-08-23 05:41:01 【问题描述】:我们正在编写一个 MS Outlook 插件。为了满足我们的业务逻辑,它应该检查某些日期之间的所有约会。我们在从日历中检索所有项目时遇到了几个问题。我们尝试了两种选择:
Outlook API。我们使用 MSDN 中描述的标准逻辑 - 按 [开始] 对项目进行排序,将 IncludeRecurrences
设置为 True
并对日历项目 like here 运行 Find\Restrict 查询。它在我们的测试环境中运行良好。但是,在我们客户的环境中: 对于定期约会,开始和结束日期设置为“主约会”的相应日期。例如,在某个房间的日历中,我们有一个在 1 月份创建的每周约会,如果我们尝试查找 8 月份的所有项目,我们会得到这个定期约会的四个项目,但它们的开始和结束日期设置为 1 月.但 Outlook 在同一日历中显示正确的日期...
非常糟糕,但我们仍然有 WebDAV!我们编写了一个简单的测试应用程序并尝试使用 WebDAV 从日历中查询所有项目。当然,我们没有重新发明***,只是粘贴了documentation 的代码。上一个问题解决了,但出现了下一个问题:它不会返回大约六个月前创建的经常性项目。我不知道 - 没有限制“旧”项目的参数!
怎么了?我们错过了什么重要的东西吗?
技术细节:Exchange 2003、Outlook 2003-2010。坦率地说,如果我们打开缓存交换模式,第一个错误就会消失,但我们不能这样做。
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();
更新 1:
使用 OutlookSpy 进行的其他研究表明问题不在我们的代码中 - 当缓存 Exchange 模式关闭时,API 中的开始\结束日期不正确。但是 Outlook 开发人员意识到了这一点,并且他们以某种方式在日历中显示了正确的日期!有人知道怎么做吗?
更新 2:
来自 Outlook 支持升级工程师的回答:
基于此,我可以确认这是我们产品的问题。
【问题讨论】:
1.你的代码是什么? 2、不要使用WebDAV;它已被弃用。 看起来非常好...您访问约会的代码是什么?您是否访问过 AppointmentItem.Parent(它将为您提供重复活动实例的主约会)? 我已经更新了上面的代码。不,我们不使用 AppointmentItem.Parent。无论如何,在我们访问开始和结束日期之前,我们只访问 AppointmentItem 的 Subject、ResponseStatus 和 MeetingStatus 属性。 一来,Outlook 不使用 OOM 来显示日历文件夹内容,二来,为什么您认为开始/结束日期不正确?究竟出了什么问题? 完全正确:OutlookSpy 向我们展示了几个具有相同 StartTime 的约会,在我们的例子中 = 11/01/2012,这绝对是每周重复活动的主约会(相同的组织者,相同的主题,等等)。但在日历中,我们可以看到正确的图片 - 每周一项。如果您能解释一下 Outlook 的工作原理、它使用什么技术来显示日历、我们在 OOM 中得到错误结果的任何想法以及如何修复这些错误,我将不胜感激? 【参考方案1】:可能的原因:
设置 IncludeRecurrences 后排序。这是我在两个日期之间检索 Outlook 项目的 PowerShell 模块代码。
还有一个小小程序,用于检查更改并发送包含议程更新的电子邮件,当您无法通过移动设备访问 Exchange 时,它会派上用场。
路径: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
这是在模块中调用 PowerShell 函数的代码:
路径: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
要运行 PowerShell 脚本,请使用 powershell.exe。要在启动时运行它,请使用“%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\”上的快捷方式:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "C:\Users\%USERNAME%\Documents\WindowsPowerShell\mono.ps1"
【讨论】:
以上是关于检索显示奇怪行为的日历项目(Outlook API、WebDAV)的主要内容,如果未能解决你的问题,请参考以下文章
在JavaScript / JQuery中检索Outlook日历信息
对于 Outlook 日历 API 中的任何用户,两个或多个事件的事件 ID 是不是相同?