web-dev-qa-db-ja.com

奇妙な動作を表示する予定表アイテム(Outlook API、WebDAV)を取得する

MS Outlookプラグインを作成しています。私たちのビジネスロジックを満たすためには、いくつかの日付の間のすべての予定をチェックする必要があります。カレンダーからすべてのアイテムを取得する際にいくつかの問題が発生しています。 2つのオプションを試しました。

  1. Outlook API。 MSDNで説明されている標準ロジックを使用します-[開始]でアイテムを並べ替え、IncludeRecurrencesTrueに設定し、カレンダーアイテムに対してFind\Restrictクエリを実行します こちらのように =。テスト環境では問題なく動作します。ただし、お客様の環境では、定期的な予定の場合、開始日と終了日は、「マスター予定」の対応する日付に設定されます。たとえば、一部の会議室のカレンダーでは、1月に作成された毎週の予定があり、8月にすべてのアイテムを検索しようとすると、この定期的な予定の4つのアイテムが表示されますが、開始日と終了日は1月に設定されています。しかし、Outlookは同じカレンダーに正しい日付を表示します...

  2. 非常に悪いですが、まだWebDAVがあります。簡単なテストアプリケーションを作成し、WebDAVを使用してカレンダーからすべてのアイテムをクエリしようとします。もちろん、ホイールを再発明することはせず、コードを documentation から貼り付けました。前の問題は解決されましたが、次の問題が発生します。約6か月以上前に作成された定期的なアイテムは返されません。手がかりはありません-「古い」アイテムを制限するパラメーターはありません!

なにが問題ですか?重要なものが欠けていますか?

技術詳細: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();
}

更新1:

OutlookSpyを使用した追加の調査では、問題がコードにないことが示されています。Exchangeキャッシュモードがオフの場合、API内でStart\Endの日付が正しくありません。しかし、Outlook開発者はそれを知っていて、どういうわけかカレンダーに正しい日付を表示します!誰か知っていますか?

更新2:

Outlookサポートエスカレーションエンジニアからの回答:

これにより、弊社製品に問題があることが確認できました。

79
Bolick

考えられる原因:

  • IncludeRecurrencesを設定してから並べ替えます。

これは、2つの日付の間で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 = “[email protected]“

  $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"