Retrieving your Outlook appointments for a given date range

Before we dive into the code sample lets take a quick look at what it means for an appointment to fall into a given date range.

When you compare an appointment with a given date range (or any two time intervals) there are the 6 possible outcomes displayed in the diagram above. Usually as a first attempt people write a comparison that looks like:

[Start] >= RangeStart AND [End] <= RangeEnd

If you examine that comparison closely you will notice that it will only retrieve appointments of type 1. This maybe fine for most applications, like getting all appointments for a given week because there usually aren't any appointments spanning over the range edges. However, if you want to be more precise and include any appointments that overlap with a given date range (i.e. type 1, 2, 3, 4) you can use the following comparison:

[End] >= RangeStart AND [Start] <= RangeEnd

This type of restriction will help when you have smaller date/time ranges such as a few hours or a day. In general, unless you specifically only want type 1 appointments, I would recommend using this restriction which finds any appointments that overlap with the given date/time range.

Since Walter has already provided a VBA, WebDAV, and CDO code sample on how to find appointments within a specific time frame, I figured I would provide some Powershell code samples.

Powershell script to retrieve appointments using the Outlook Object Model for a given date range.

Keep in mind in order to get all the appointments, including any instances of recurring appointments, you need to get the items collection on the calendar folder and then Sort by the "[Start]" property and set IncludeRecurrences to true. Once you have done this the Count property on the items collection is bogus because there could potentially be an infinite number of recurring appointments. So to traverse this collection you need to use the enumerator (i.e. foreach) or use the Find/FindNext methods on the collection.

# Get-ApptsUsingOOM.ps1
#    Powershell script to retrieve all appointments for a given date range using the Outlook Object Model
param ( [DateTime] $rangeStart = [DateTime]::Now
      , [DateTime] $rangeEnd   = [DateTime]::Now.AddDays(7))

$outlook = New-Object -ComObject Outlook.Application

# Ensure we are logged into a session
$session = $outlook.Session
$session.Logon()

$olFolderCalendar = 9
$apptItems = $session.GetDefaultFolder($olFolderCalendar).Items
$apptItems.Sort("[Start]")
$apptItems.IncludeRecurrences = $true $restriction = "[End] >= '{0}' AND [Start] <= '{1}'" -f $rangeStart.ToString("g"), $rangeEnd.ToString("g") foreach($appt in $apptItems.Restrict($restriction)) { "{0:MM/dd hh:mm tt} - {1:MM/dd hh:mm tt} : {2}" -f [DateTime]$appt.Start, [DateTime]$appt.End, $appt.Subject } $outlook = $session = $null;

Powershell script to retrieve appointments using Exchange Web Services for a given date range

For simplicity I built the soap message manually and submitted the request, but you could easily generate the web service proxy classes using wsdl.exe like I did in another example if you don't wish to build the soap message yourself.

# GetApptsUsingEWS.ps1
#    Powershell script to retrieve all appointments for a given date range using Exchange Web Services
param ( [DateTime] $rangeStart = [DateTime]::Now
      , [DateTime] $rangeEnd   = [DateTime]::Now.AddDays(7)
      , [System.Net.NetworkCredential] $credentials = (Get-Credential).GetNetworkCredential())

# Remember to set your exchange server address
$exchangeServerAddress = "http<s>://<ExchangeServer>/EWS/Exchange.asmx"

# Soap request derived from http://msdn2.microsoft.com/en-us/library/aa564515.aspx
$soapRequest = @'
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
  <soap:Body>
    <FindItem Traversal="Shallow" xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
      <ItemShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:FieldURI FieldURI="calendar:Start"/>
          <t:FieldURI FieldURI="calendar:End"/>
          <t:FieldURI FieldURI="item:Subject"/>
        </t:AdditionalProperties>
      </ItemShape>
      <CalendarView MaxEntriesReturned="100" StartDate="{0}" EndDate="{1}"/>
      <ParentFolderIds>
        <t:DistinguishedFolderId Id="calendar"/>
      </ParentFolderIds>
    </FindItem>
  </soap:Body>
</soap:Envelope>
'@

# Put the range start and end date in the correct format
$soapRequest = $soapRequest -f $rangeStart.ToString("yyyy-MM-ddTHH:mm:sszzz"), $rangeEnd.ToString("yyyy-MM-ddTHH:mm:sszzz")

# Create the request 
$webRequest = [System.Net.WebRequest]::Create($exchangeServerAddress)
$webRequest.ContentType = "text/xml"
$webRequest.Headers.Add("Translate", "F")
$webRequest.Method = "Post"
$webRequest.Credentials = $credentials

# Setup the soap request to send to the server
$content = [System.Text.Encoding]::UTF8.GetBytes($soapRequest)
$webRequest.ContentLength = $content.Length
$requestStream = $webRequest.GetRequestStream()
$requestStream.Write($content, 0, $content.Length)
$requestStream.Close()

# Get the xml response from the server
$webResponse = $webRequest.GetResponse()
$responseStream = $webResponse.GetResponseStream()
$responseXml = [xml](new-object System.IO.StreamReader $responseStream).ReadToEnd()
$responseStream.Close()
$webResponse.Close()

foreach ($appt in $responseXml.GetElementsByTagName("t:CalendarItem"))
{
    "{0:MM/dd hh:mm tt} - {1:MM/dd hh:mm tt} : {2}" -f [DateTime]$appt.Start, [DateTime]$appt.End, $appt.Subject
}

8 Comments

  • Wes,

    Thanks for the very informative article.

    Good insight into PowerShell and Exchange.

  • I think you have a typo in your second (better) comparison example. You have:

    [End] >= RangeStart AND [End] = RangeStart AND [Start] <= RangeEnd

    Yours would only catch Type 1 & 2

  • Thanks Logan - I've updated the post (dumb copy and paste errors :)).

  • Can we obtain appointments for all users on exchange?

    or we can only get the appointments for which we have rights

  • Clare - The only way you I know of to get another users appointments using EWS is to provide their credentials. But I'm by no means an expert on EWS so there maybe a way to do it.

  • I've created a web service for SharePoint, and it works if I load the DLL, and execute a function on the instance of the service. But I need to customize the XML that is sent back to the server. If I send just enough parameters that the method will run (but not actually modify anything), it works. If I provide the parameters necessary for the procedure to do some work, I invariably get "500 Internal Server Error" messages. How can I debug this? The client and service are both at the URL provided.

  • Sir, actually i need to find the item in the notes by the creation Date time. so i wrote the query like :

    items.Find([creationTime] = '2009-02-13 12:45:03');

    but i am getting null values its not able to find the item by exact date time which i need.

    please if u have any idea about how to find the time by matching the exact date time than please let me know.

    i will be very thankfull to you.

  • I tried out this but i'm not getting all the occurrence of a recurring appointment. I'm getting only the first one.
    I tried with IncludeRecurring = true for the Items.

    Could you please help

Comments have been disabled for this content.