One of the new features that has been added in Exchange 2016 and Office365 in OWA is a birthday calendar which is a dedicated calendar for the Birthday appointments that are associated with contacts. eg
So in EWS you can do something like the following to access the HexEntryId value from this extended property which you can then convert to a EWSId using the ConvertId operation and then you will be able to bind to the folder using that ID. eg
Enumerating through birthdays and working out a persons age :
Birthdays are stored as recurring appointments (as they do occur every year) so if you want to display all the birthdays in a calendar its better to use a CalendarView to expand any recurring appointments. To determine the Age of the person associated with the calendar appointment you can use the Birthdaylocal property which holds the actual date of birth (if it was entered). eg
If you then do a Time difference between that and the Start time of the appointment that will give you the Age of the person in days which you can then convert to years using some simple math. In code this looks like
I've put a copy of this script up on github at https://github.com/gscales/Powershell-Scripts/blob/master/BirthDayCalendar.ps1
Like many of the special folders in a Mailbox the folder name for this is localized so if your mailbox is set to use a different language this folder name should appear in your localized language. Unlike most of the special folders in Exchange there is no WellKnownFolder enumeration for the birthday calendar so if you want to open this folder you either need to search for it by name (as long as you know the localization of the Mailbox) or you can use the following extended property that should exist on the root mailbox folder.
function Get-BirthDayCalendar{ param ( [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName, [Parameter(Position=1, Mandatory=$true)] [System.Management.Automation.PSCredential]$Credentials, [Parameter(Position=2, Mandatory=$false)] [switch]$useImpersonation )
process{ $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials if($useImpersonation.IsPresent){ $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) } $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName) $BirthdayCalendarFolderEntryId = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::Common,"BirthdayCalendarFolderEntryId",[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary); $psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $psPropset.Add($BirthdayCalendarFolderEntryId) $EWSRootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid,$psPropset) $BirthdayCalendarFolderEntryIdValue = $null $BirthdayCalendarFolderHexValue = $null if($EWSRootFolder.TryGetProperty($BirthdayCalendarFolderEntryId,[ref]$BirthdayCalendarFolderEntryIdValue)){ $BirthdayFolderEWSId = new-object Microsoft.Exchange.WebServices.Data.FolderId((ConvertId -HexId ([System.BitConverter]::ToString($BirthdayCalendarFolderEntryIdValue).Replace("-","")))) $BirthdayFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$BirthdayFolderEWSId); return $BirthdayFolder }
else { throw [System.IO.FileNotFoundException] "folder not found." } } }
Enumerating through birthdays and working out a persons age :
Birthdays are stored as recurring appointments (as they do occur every year) so if you want to display all the birthdays in a calendar its better to use a CalendarView to expand any recurring appointments. To determine the Age of the person associated with the calendar appointment you can use the Birthdaylocal property which holds the actual date of birth (if it was entered). eg
If you then do a Time difference between that and the Start time of the appointment that will give you the Age of the person in days which you can then convert to years using some simple math. In code this looks like
function Get-Birthdays{ param ( [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName, [Parameter(Position=1, Mandatory=$true)] [System.Management.Automation.PSCredential]$Credentials, [Parameter(Position=2, Mandatory=$false)] [switch]$useImpersonation ) process{ $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials if($useImpersonation.IsPresent){ $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) } $strtime = (Get-date).Year.ToString() + "0101" $endtime = (Get-date).AddYears(1).Year.ToString() + "0101" $StartDate = [datetime]::ParseExact($strtime,"yyyyMMdd",$null) $EndDate = [datetime]::ParseExact($endtime,"yyyyMMdd",$null) $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName) $BirthdayCalendarFolderEntryId = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::Common,"BirthdayCalendarFolderEntryId",[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary); $psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $psPropset.Add($BirthdayCalendarFolderEntryId) $EWSRootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid,$psPropset) $BirthdayCalendarFolderEntryIdValue = $null $BirthdayCalendarFolderHexValue = $null if($EWSRootFolder.TryGetProperty($BirthdayCalendarFolderEntryId,[ref]$BirthdayCalendarFolderEntryIdValue)){ $BirthdayFolderEWSId = new-object Microsoft.Exchange.WebServices.Data.FolderId((ConvertId -HexId ([System.BitConverter]::ToString($BirthdayCalendarFolderEntryIdValue).Replace("-","")))) $BirthdayFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$BirthdayFolderEWSId); $CalendarView = New-Object Microsoft.Exchange.WebServices.Data.CalendarView($StartDate,$EndDate,1000) $psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $BirthDayLocal = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([Microsoft.Exchange.WebServices.Data.DefaultExtendedPropertySet]::Address,0x80DE, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::SystemTime) $psPropset.Add($BirthDayLocal) $CalendarView.PropertySet = $psPropset $fiItems = $service.FindAppointments($BirthdayFolder.Id,$CalendarView) foreach($Item in $fiItems.Items){ $exportObj = "" | Select subject,StartTime,EndTime,DateOfBirth,Age $exportObj.StartTime = $Item.Start $exportObj.EndTime = $Item.End $exportObj.Subject = $Item.Subject $BirthDavLocalValue = $null if($Item.TryGetProperty($BirthDayLocal,[ref]$BirthDavLocalValue)){ $exportObj.DateOfBirth = $BirthDavLocalValue $exportObj.Age = [Math]::Truncate(($Item.Start – $BirthDavLocalValue).TotalDays / 365); } Write-Output $exportObj } } else { throw [System.IO.FileNotFoundException] "folder not found." } } }
I've put a copy of this script up on github at https://github.com/gscales/Powershell-Scripts/blob/master/BirthDayCalendar.ps1