≡ Menu

How To Add a Custom Holiday to an Exchange Calendar with PowerShell and the EWS Managed API

I’ve been asked several times how to modify my previous function to add custom holidays to a calendar. I figured I would create a new function geared specifically for this task. If you take a look at a typical holiday event on a calendar, like the one below (yes, Golfer’s Day really is a holiday, at least for some), you’ll notice that its basically just an all day appointment, where the free/busy status is set to free, and the category is set to Holiday. I’ve added the required changes to the previous function and added the ability to accept pipeline input.

If you’re looking for more background on exactly what is going on with a the majority of this code, like getting connected to the end-point on your CAS, specifying credentials, etc., check out my older posts on EWS. Also, Glenn has a great “How-To” series over at his blog. What you need to do is add the following function to your PowerShell session:

function New-Holiday {
    [CmdletBinding(DefaultParametersetName='Identity')]
    param(
        [Parameter(Position=0, ParameterSetName='Identity')]
        $Identity,

        [Parameter(Position=1, Mandatory=$true)]
        $Subject,

        [Parameter(Position=2, Mandatory=$true)]
        $Date,

        [Parameter(Position=3)]
        [Switch]$Impersonate,

        [Parameter(Position=4)]
        $ExchangeVersion = 'Exchange2010_SP2',

        [Parameter(Position=5, ParameterSetName='Pipeline', ValueFromPipelineByPropertyName=$true)]
        $PrimarySmtpAddress,

        [Parameter(Position=6)]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter(Position=7)]
        $EWSUrl
    )

    begin {
        #Load the EWS Assembly
        Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
    }

    process {
        #Is the identity coming from the pipeline?
        if($PsCmdlet.ParameterSetName -eq 'Pipeline') {
            $Identity = $PrimarySmtpAddress.ToString()
        }

        #Create the ExchangeService object
        $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::$ExchangeVersion)

        #If Credential parameter used, set the credentials on the $service object
        if($Credential) {
            $service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password
        }

        #If EWSUrl parameter not used, locate the end-point using autoD
        if(!$EWSUrl) {
            $service.AutodiscoverUrl($Identity, {$true})
        }
        else {
            $service.Url = New-Object System.Uri -ArgumentList $EWSUrl
        }        

        #If Impersonation parameter used, impersonate the user
        if($Impersonate) {
            $ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress),$Identity
            $service.ImpersonatedUserId = $ImpersonatedUserId
        }

        #Configure the start and end time for this all day event
        $start = (get-date $date)
        $end = $start.addhours(24)

        #Create and save the appointment
        $appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
        $appointment.Subject = $Subject
        $appointment.Start = $Start
        $appointment.End = $End
        $appointment.IsAllDayEvent = $true
        $appointment.IsReminderSet = $false
        $appointment.Categories.Add('Holiday')
        $appointment.Location = 'United States'
        $appointment.LegacyFreeBusyStatus = [Microsoft.Exchange.WebServices.Data.LegacyFreeBusyStatus]::Free
        $appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone)
    }
}

Here are a few examples of how to run this code. Keep in mind that to add entries to another persons calendar you’ll need to be assigned the Application Impersonaiton RBAC role or have rights to their mailbox.

Here’s an example of adding a holiday to my own calendar. I’m already signed into Windows with my own mailbox-enabled Active Directory account, and this could be done in the standard “blue” shell or EMS:

New-Holiday -Identity mike@domain.com -Subject "Golfer's Day" -Date 4/10/13

This function also has an additional parameter set, and it can accept the identity of the mailbox from the pipeline in EMS. This means its easy to create these custom holidays on behalf of other users, in bulk, as long as you have impersonation rights:

Get-Mailbox -OrganizationalUnit Sales | New-Holiday -Subject "Golfer's Day" -Date 4/10/13 -Impersonate

Finally, you can use this function to add custom holidays to the calendars for Office 365 mailboxes. For example, here’s how I would add a holiday to my cloud mailbox, using the -Credential parameter to authenticate:

$cred = Get-Credential
New-Holiday -Identity mike@domain.onmicrosoft.com -Subject "Golfer's Day" -Date 4/10/13 -Credential $cred

I’ve added lots of comments in the code for each phase of the function. Hopefully it will be fairly straight forward if you need to extend it further to meet your specific requirements. One more FYI – prior to posting this, I tested the code on PowerShell v3 with both on prem Exchange 2010 SP2, and Exchange Online (Wave 15) mailboxes with the 1.2 version of the EWS Managed Api and everything worked great.

0 comments… add one

Leave a Comment