Accessing Appointment Body via EWS Managed API

Hey All,

First-time poster, long-time fan and lurker. I turn to you for your sage advice and guidance.

I’m attempting to use EWS Manged API via PowerShell to programmatically schedule server downtime and ticket generation.

I am successfully able to output basic Appointment information (Subject, Start, End, Location). However, when trying to capture the text in the actual “Body” of the appointment, I keep getting blank output. I know that the appointment Body is not blank, and that my permissions are correct. I’m sure it’s just me attempting to access that property incorrectly, as my experience with EWS is very limited.

I’ve sanitized my code, and posted my Gist here:
https://gist.github.com/4dilio/cace5e1669d10ddcbd36c5eb858fc138

Hoping someone here can help, or point me in the right direction. Always happy to learn :slight_smile:

Thanks in advance for your time.

I’ve never used that API (but have connected to many others), but you should be able to what is available using basic Powershell commands. My next steps would be something like:

$appt = $Folder.FindAppointments($View2)
$appt.GetType() #see what data type the API is returning. API typically going to return XML\JSON
$appt | Get-Member -Force #see the available properties of that object
$appt. #Let Intellisense tell you what properties are available with dot notation.

I did see this code out there that searches appointments and returns data, which I didn’t see a call to .FindAppointments, so you may want to review this code to see if you are parsing the correct data:

https://code.msdn.microsoft.com/office/PowerShellEWS-Search-e0f9c169

Thanks much for the tips, Rob! Definitely good breadcrumbs to follow.

I had a look at the link you attached, and the script does not seem to be accessing the appointment body at all.

I agree with you that I may not be parsing the correct data. Perhaps the Body of the appointment is actually contained in another Item or Schema. I’ve done some exploration using the Get-Member -Force and Dot-Notation IntelliSense, but I’m still not seeing any Body field with content. I’ve looked at the members of Microsoft.Exchange.WebServices.Data.Appointment and Microsoft.Exchange.WebServices.Data.AppointmentSchema. I see reference to the properties TextBody, UniqueBody, and NormalizedBody as well. However, when attempting to select for these, they also come up blank.

As you said, it’s likely that FindAppointments method is not going to work for this. I did come across the following articles that allude to this, specifically referring to a “LoadPropertiesForItems” method. However, this doesn’t look like PowerShell, and the articles are frankly way above my level of understanding, hehe :
https://blogs.msdn.microsoft.com/exchangedev/2010/03/16/loading-properties-for-multiple-items-with-one-call-to-exchange-web-services/
https://social.msdn.microsoft.com/Forums/exchange/en-US/ce1e0527-e2db-490d-817e-83f586fb1b44/ews-managed-api-findappointments-loadpropertiesforitems?forum=exchangesvrdevelopment

I’ll keep hunting. I’m still learning, and sorry if some of this is obvious to someone that’s not a novice. Please let me know if anyone can help shed some light, or has experience with EWS API and PowerShell. I am always in awe of the PoSh Community and great input!

Hey All,

Just wanted to update this post with my solution, in case it helps someone in future. Much thanks to Rob above, as well as Glen Sales for his wonderful Exchange Blog (http://gsexdev.blogspot.ca/).

The solution was provided via Glen’s blog, where he details the LoadItemsFromProperties method for accessing appointment details such as Recipients and Body. These are not accessible via the FindAppointments method, as I used earlier. I thus created a new view with an additional PropertySet.

Code included below. Happy Scripting :slight_smile: !

# Import the EWS Managed API
Import-Module 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'

# Set Exchange version, credentials, and other variables
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$Service = [Microsoft.Exchange.WebServices.Data.ExchangeService]::new($ExchangeVersion)
$User = "MY-SERVICE-ACCOUNT"
$Password = Get-Content MySuperSecureStringPassword.txt | ConvertTo-SecureString
$Service.Credentials = [System.Net.NetworkCredential]::new($User, $Password)
$Service.Url = "https://autodiscover.MYDOMAIN.ca/EWS/Exchange.asmx"
$DaysAhead = 1

# Specify Calendar folder to access
$FolderID = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar, "MY.MAILBOX@MYDOMAIN.CA")
$Folder = [Microsoft.Exchange.WebServices.Data.calendarFolder]::Bind($Service, $FolderID)

# Create View for Appointment Details
$View = [Microsoft.Exchange.WebServices.Data.CalendarView]::new([datetime]::Now, [datetime]::Now.AddDays($DaysAhead))
$View.PropertySet = [Microsoft.Exchange.WebServices.Data.PropertySet]::new([Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Subject,
    [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Start,
    [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::End,
    [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Location)

$Folder.FindAppointments($View) | Select-Object Start , End , Subject , Location

# Create View2 for Appointment Body
$BodyPropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$View2 = [Microsoft.Exchange.WebServices.Data.CalendarView]::new([datetime]::Now, [datetime]::Now.AddDays($DaysAhead))
$FolderItems = $Service.FindItems($Folder.Id, $View2)
[Void]$Service.LoadPropertiesForItems($FolderItems, $BodyPropertySet)
# For each Maintenance Window, generate e-mail for ticket
foreach ($Item in $FolderItems.Items) {
    $Subject = $Item.Subject
    $Body = $Item.Body.Text
    $SmtpServer = "MY.SMTPSERVER.ca"
    $From = "no-reply@MYDOMAIN.ca"
    $To = "MY.EMAIL@MYDOMAIN.ca"
    $BodyFooter =
    Send-MailMessage -SmtpServer $SmtpServer -From $From -To $To -Subject $Subject -Body $Body -BodyAsHtml 
}