Truy xuất các mục lịch (API Outlook, WebDAV) hiển thị hành vi lạ


79

Chúng tôi đang viết một plugin MS Outlook. Để đáp ứng logic kinh doanh của chúng tôi, nó nên kiểm tra tất cả các cuộc hẹn giữa một số ngày. Chúng tôi đang gặp một số sự cố khi truy xuất tất cả các mục từ lịch. Chúng tôi đã thử hai tùy chọn:

  1. API Outlook. Chúng tôi sử dụng logic tiêu chuẩn được mô tả trong MSDN - sắp xếp các mục theo [Bắt đầu], đặt IncludeRecurrencesthành Truevà chạy truy vấn Tìm \ Hạn chế trên các mục lịch như ở đây . Nó hoạt động tốt trong môi trường thử nghiệm của chúng tôi. Tuy nhiên, trong môi trường khách hàng của chúng tôi: Đối với các cuộc hẹn định kỳ, ngày bắt đầu và ngày kết thúc được đặt thành ngày tương ứng của 'cuộc hẹn chính'. Ví dụ: trong lịch của một số phòng, chúng tôi có một cuộc hẹn hàng tuần được tạo vào tháng 1 và nếu chúng tôi cố gắng tìm tất cả các mục trong tháng 8, chúng tôi nhận được trong số những mục khác của cuộc hẹn định kỳ này, nhưng ngày bắt đầu và kết thúc của chúng được đặt thành tháng 1 . Nhưng Outlook hiển thị các ngày chính xác trong cùng một lịch ...

  2. Rất tệ, nhưng chúng ta vẫn có WebDAV! Chúng tôi viết một ứng dụng thử nghiệm đơn giản và cố gắng truy vấn tất cả các mục từ lịch bằng cách sử dụng WebDAV. Tất nhiên, chúng tôi không phát minh lại bánh xe và chỉ dán mã từ tài liệu . Vấn đề trước đó đã được giải quyết, nhưng vấn đề tiếp theo lại phát sinh: Nó không trả lại các mục lặp lại đã được tạo hơn khoảng sáu tháng trước. Tôi không phải là một manh mối - không có tham số nào hạn chế các mặt hàng 'cũ'!

Chuyện gì thế? Chúng ta đang thiếu một cái gì đó quan trọng?

Chi tiết kỹ thuật: Exchange 2003, Outlook 2003-2010. Thành thật mà nói, lỗi đầu tiên sẽ biến mất nếu chúng tôi bật Chế độ đệm ẩn Exchange, nhưng chúng tôi không thể làm điều đó.

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();
}

CẬP NHẬT 1:

Nghiên cứu bổ sung bằng cách sử dụng OutlookSpy cho thấy rằng vấn đề không nằm trong mã của chúng tôi - ngày Bắt đầu \ Kết thúc không chính xác bên trong API khi Chế độ đệm ẩn Exchange tắt. Nhưng các nhà phát triển Outlook đã biết về điều đó và bằng cách nào đó họ hiển thị ngày chính xác trong lịch! Có ai biết làm thế nào không?

CẬP NHẬT 2:

Câu trả lời từ Kỹ sư nâng cấp hỗ trợ Outlook:

Dựa trên điều này, tôi có thể xác nhận rằng đây là một vấn đề trong sản phẩm của chúng tôi.


3
1. Mã của bạn là gì? 2. Không sử dụng WebDAV; nó không được dùng nữa.
Dmitry Streblechenko

Trông hoàn toàn ổn ... Mã truy cập cuộc hẹn của bạn là gì? Bạn đã bao giờ truy cập AppointmentItem.Parent (sẽ cung cấp cho bạn cuộc hẹn chính cho một trường hợp hoạt động định kỳ)?
Dmitry Streblechenko

Tôi đã cập nhật mã ở trên. Không, chúng tôi không sử dụng AppointmentItem.Parent. Dù sao, trước khi chúng tôi truy cập Ngày bắt đầu và Ngày kết thúc, chúng tôi chỉ truy cập các thuộc tính Chủ đề, Trạng thái đáp ứng và Trạng thái họp của AppointmentItem.
Bolick

Thứ nhất, Outlook không sử dụng OOM để hiển thị nội dung thư mục Lịch, thứ hai, tại sao bạn cho rằng ngày Bắt đầu / Kết thúc không chính xác? Chính xác thì điều gì là sai?
Dmitry Streblechenko

Chính xác: OutlookSpy hiển thị cho chúng ta một số cuộc hẹn với cùng một StartTime, trong trường hợp của chúng ta là = 11/01/2012 và đây chắc chắn là cuộc hẹn chính của hoạt động định kỳ hàng tuần (cùng một người tổ chức, cùng một chủ đề, v.v.). Nhưng trong lịch, chúng ta có thể thấy hình ảnh chính xác - một mục trong mỗi tuần. Tôi rất đánh giá cao nếu Bạn có thể giải thích cách hoạt động của Outlook, công nghệ nó sử dụng để hiển thị lịch, bất kỳ ý tưởng nào khiến chúng tôi nhận được kết quả sai trong OOM và cách khắc phục những lỗi này?
Bolick

Câu trả lời:


1

Nguyên nhân có thể:

  • Sắp xếp sau khi thiết lập includeRecurrences.

Đây là mã của tôi về mô-đun PowerShell truy xuất các mục Outlook giữa hai ngày.

Và một applet nhỏ để kiểm tra các thay đổi và gửi email bao gồm các bản cập nhật chương trình làm việc, rất hữu ích khi bạn không có quyền truy cập trên thiết bị di động vào Exchange.

Đường dẫn: 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

Đây là mã để gọi hàm PowerShell trong mô-đun:

Đường dẫn: 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

}

Để chạy tập lệnh PowerShell, hãy sử dụng powershell.exe. Để chạy tính năng này khi khởi động, hãy sử dụng phím tắt trên "% APPDATA% \ Microsoft \ Windows \ Start Menu \ Programs \ Startup \":

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "C:\Users\%USERNAME%\Documents\WindowsPowerShell\mono.ps1"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.