Bol*_*ick 79 outlook exchange-server webdav outlook-object-model
我们正在编写一个MS Outlook插件.为了满足我们的业务逻辑,它应检查某些日期之间的所有约会.从日历中检索所有项目时遇到了一些问题.我们尝试了两种选择:
Outlook API.我们使用MSDN中描述的标准逻辑 - 按[开始]对项目进行排序,设置IncludeRecurrences为True日历项目并在此处运行Find\Restrict查询.它在我们的测试环境中工作正常.但是,在我们客户的环境中:对于定期约会,开始和结束日期设置为"主约会"的相应日期.例如,在某个房间的日历中,我们有一个在1月创建的每周约会,如果我们试图在8月找到所有项目,我们会获得此定期约会的四个项目,但其开始和结束日期设置为1月.但Outlook在同一日历中显示正确的日期...
很糟糕,但我们还有WebDAV!我们编写一个简单的测试应用程序,并尝试使用WebDAV查询日历中的所有项目.当然,我们没有重新发明轮子,只是粘贴了文档中的代码.之前的问题已经解决,但下一个问题出现了:它不会返回大约六个月前创建的重复项目.我没有线索 - 没有限制'旧'项目的参数!
怎么了?我们缺少重要的东西吗?
技术细节:Exchange 2003,Outlook 2003-2010.坦率地说,如果我们打开缓存Exchange模式,第一个错误就会消失,但我们不能这样做.
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();
}
Run Code Online (Sandbox Code Playgroud)
使用OutlookSpy的其他研究表明问题不在我们的代码中 - 当缓存Exchange模式关闭时,API内的Start\End日期不正确.但Outlook开发人员已经意识到这一点,并且他们以某种方式在日历中显示正确的日期!有谁知道怎么样?
来自Outlook支持升级工程师的回答:
基于此,我可以确认这是我们产品中的一个问题.
可能的原因:
\n\n以下是我的 PowerShell 模块代码,用于检索两个日期之间的 Outlook 项目。
\n\n还有一个小小程序,用于检查更改并发送包括议程更新的电子邮件,当您无法通过移动设备访问 Exchange 时,这会很方便。
\n\n路径:Documents\\WindowsPowerShell\\Modules\\Outlook\\expcal.ps1
\n\nFunction Get-OutlookCalendar\n{\n <#\n .Synopsis\n This function returns appointment items from default Outlook profile\n .Description\n This function returns appointment items from the default Outlook profile. It uses the Outlook interop assembly to use the olFolderCalendar enumeration.\n It creates a custom object consisting of Subject, Start, Duration, Location\n for each appointment item.\n .Example\n Get-OutlookCalendar |\n where-object { $_.start -gt [datetime]"5/10/2011" -AND $_.start -lt `\n [datetime]"5/17/2011" } | sort-object Duration\n Displays subject, start, duration and location for all appointments that\n occur between 5/10/11 and 5/17/11 and sorts by duration of the appointment.\n The sort is the shortest appointment on top.\n .Notes\n NAME: Get-OutlookCalendar\n AUTHOR: ed wilson, msft\n LASTEDIT: 05/10/2011 08:36:42\n KEYWORDS: Microsoft Outlook, Office\n HSG: HSG-05-24-2011\n .Link\n Http://www.ScriptingGuys.com/blog\n #Requires -Version 2.0\n #>\n\n echo Starting... Initialize variables\n\n Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null\n $olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type]\n $olCalendarDetail = "Microsoft.Office.Interop.Outlook.OlCalendarDetail" -as [type]\n\n echo ... Getting ref to Outlook and Calendar ...\n\n $outlook = new-object -comobject outlook.application\n $namespace = $outlook.GetNameSpace("MAPI")\n $folder = $namespace.getDefaultFolder($olFolders::olFolderCalendar)\n\n echo ... Calculating dates ...\n\n $now = Get-Date -Hour 0 -Minute 00 -Second 00\n\n echo From $a To $b\n\n echo ... Getting appointments ...\n\n $Appointments = $folder.Items\n $Appointments.IncludeRecurrences = $true\n $Appointments.Sort("[Start]")\n\n echo ... Setting file names ...\n\n $oldfile = "$env:USERPROFILE\\outlook-calendar.bak"\n echo oldfile: $oldfile\n $newfile = "$env:USERPROFILE\\outlook-calendar.txt"\n echo newfile: $newfile\n $calfile = "$env:USERPROFILE\\outlook-calendar.ics"\n echo calfile: $calfile\n\n echo ... Exporting calendar to $calfile ...\n\n $calendarSharing = $folder.GetCalendarExporter()\n $calendarSharing.CalendarDetail = $olCalendarDetail::olFullDetails\n $calendarSharing.IncludeWholeCalendar = $false\n $calendarSharing.IncludeAttachments = $false\n $calendarSharing.IncludePrivateDetails = $true\n $calendarSharing.RestrictToWorkingHours = $false\n $calendarSharing.StartDate = $now.AddDays(-30)\n $calendarSharing.EndDate = $now.AddDays(30)\n echo $calendarSharing\n $calendarSharing.SaveAsICal($calfile)\n\n echo ... Backing up $newfile into $oldfile ...\n\n if (!(Test-Path $newfile)) {\n echo "" |Out-File $newfile\n }\n\n # Backup old export into $oldfile\n if (Test-Path $oldfile) {\n echo "Deleting old backup file $oldfile"\n del $oldfile \n }\n echo " ... moving $newfile into $oldfile ... "\n move $newfile $oldfile\n\n echo "... Generating text report to file $newfile ..."\n\n $Appointments | Where-object { $_.start -gt $now -AND $_.start -lt $now.AddDays(+7) } | \n Select-Object -Property Subject, Start, Duration, Location, IsRecurring, RecurrenceState |\n Sort-object Start |\n Out-File $newfile -Width 100\n\n echo "... Comparing with previous export for changes ..."\n\n $oldsize = (Get-Item $oldfile).length\n $newsize = (Get-Item $newfile).length\n\n if ($oldsize -ne $newsize ) {\n echo "!!! Detected calendar change. Sending email..."\n $mail = $outlook.CreateItem(0)\n\n #2 = high importance email header\n $mail.importance = 2\n\n $mail.subject = $env:computername + \xe2\x80\x9c Outlook Calendar\xe2\x80\x9c\n\n $mail.Attachments.Add($newfile)\n $mail.Attachments.Add($calfile)\n $text = Get-Content $newfile | Out-String\n $mail.body = \xe2\x80\x9cSee attached file...\xe2\x80\x9c + $text\n\n #for multiple email, use semi-colon ; to separate\n $mail.To = \xe2\x80\x9cyour-email@your-mail-domain.com\xe2\x80\x9c\n\n $mail.Send()\n\n }\n else {\n echo "No changes detected in Calendar!"\n }\n\n\n} #end function Get-OutlookCalendar\n\nFunction Get-OutlookCalendarTest\n{\n echo starting...\n Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null\n $olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type]\n $outlook = new-object -comobject outlook.application\n $namespace = $outlook.GetNameSpace("MAPI")\n $folder = $namespace.getDefaultFolder($olFolders::olFolderCalendar)\n\n $a = Get-Date -Hour 0 -Minute 00 -Second 00\n $b = (Get-Date -Hour 0 -Minute 00 -Second 00).AddDays(7)\n echo From $a To $b\n\n $Appointments = $folder.Items\n $Appointments.IncludeRecurrences = $true\n $Appointments.Sort("[Start]")\n\n $Appointments | Where-object { $_.start -gt $a -AND $_.start -lt $b } | Select-Object -Property IsRecurring, RecurrenceState, Subject, Start, Location\n\n} #end function Get-OutlookCalendarTest\nRun Code Online (Sandbox Code Playgroud)\n\n这是调用模块中 PowerShell 函数的代码:
\n\n路径:Documents\\WindowsPowerShell\\mono.ps1
\n\nImport-Module -Name Outlook\\expcal.psm1 -Force\n\n$i=0\n\n#infinite loop for calling connect function \nwhile(1)\n{\n $i = $i +1\n Write-Output "Running task Get-OutlookCalendar ($i)"\n Get-OutlookCalendar\n\n start-sleep -seconds 300\n\n}\nRun Code Online (Sandbox Code Playgroud)\n\n要运行 PowerShell 脚本,请使用 powershell.exe。要在启动时运行此程序,请使用“%APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\”上的快捷方式:
\n\nC:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy Bypass "C:\\Users\\%USERNAME%\\Documents\\WindowsPowerShell\\mono.ps1"\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
5858 次 |
| 最近记录: |