I’m sure this has also happened already several times to you. You finish up your work to start into your well deserved holidays and only after you arrive at home do you realize that you forgot about to set your “Out of Office” status (considering that you actually do that). Usually, this would mean that you need to use your company device in order to connect back to work and set it up. If your company is running Exchange mail servers there is actually another option available which enables you to do the same from any PC that is connected to the Internet. The EWS Managed API is the technology that enables this.
I’ve written a module that uses the API in order to set an Out of Office message. The function has the following features:
- Check whether the EWS Managed API is installed and offer an option to download and install in case it is not
- Option to provide credentials (-ProvideCredentials switch) or use the current
- A pop-up calendar to select the duration of the absence.
- Automatic calculation of the return date based on the next business day after the duration end date
- A custom OOTO message including start and return date (based on next business day after duration end date) and your Outlook signature (the signature is copied from your work PC ($env:APPDATE\Microsoft\Outlook\Signatures\) if available or should be within the same location as the module)
- The function also creates an appointment in your Outlook based on the provided start and end date
Usage:
Import-Module Set-OOTO Set-OOTO 'email@domain.com' -ExchangeVersion Exchange2007_SP1 -ProvideCredential
I’ve added my email and Exchange server version as default parameters to the function (if you are using Exchange 2007SP3 you can also need to use Exchange2007_SP1 as the value for the ExchangeVersion parameter (this took me quite a while to figure out)). Other than that you can of course modify the function with your own custom message and additional features (please share).
I’m posting the code below including helper functions to set the appointment and the calendar window. The code can also be downloaded from my GitHub repo:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-DateRange { | |
Add-Type –AssemblyName System.Windows.Forms | |
$form = new-object Windows.Forms.Form | |
$form.text = "Calendar" | |
$form.Size = new-object Drawing.Size @(656,639) | |
# Make "Hidden" SelectButton to handle Enter Key | |
$btnSelect = new-object System.Windows.Forms.Button | |
$btnSelect.Size = "1,1" | |
$btnSelect.add_Click({ | |
$form.close() | |
}) | |
$form.Controls.Add($btnSelect ) | |
$form.AcceptButton = $btnSelect | |
$cal = new-object System.Windows.Forms.MonthCalendar | |
$cal.ShowWeekNumbers = $true | |
$cal.MaxSelectionCount = 356 | |
$cal.Dock = 'Fill' | |
$form.Controls.Add($cal) | |
$Form.Add_Shown({$form.Activate()}) | |
[void]$form.showdialog() | |
return $cal.SelectionRange | |
} | |
function Set-CalendarAppointment($startDate,$endDate,$subject,$location){ | |
$appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment($service) | |
$appointment.Subject = $subject | |
$appointment.Start = $startDate | |
$appointment.End = $endDate | |
$appointment.Location = $location | |
$appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone) | |
} | |
function Set-OOTO($Email='email@domain.com', [Microsoft.Exchange.WebServices.Data.ExchangeVersion]$ExchangeVersion=[Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1, [switch]$ProvideCredentials,[switch]$Off){ | |
#EWS managed API 2.1 | |
#reference: https://msdn.microsoft.com/en-us/library/jj220535%28v=exchg.80%29.aspx | |
#https://www.microsoft.com/en-us/download/details.aspx?id=42022 | |
$apiPath = 'C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll' | |
if (-not (Test-Path $apiPath)){ | |
$a = new-object –comobject wscript.shell | |
$answer = $a.popup("The function requires the EWS Mangaged API to be installed on your machine do you want to do download and install it now?", ` | |
0,"Download",4) | |
If ($answer -eq 6) { | |
$webclient = New-Object Net.WebClient | |
$url = 'https://download.microsoft.com/download/3/E/4/3E4AF215-E418-47B8-BB89-D5555E858728/EwsManagedApi.MSI' | |
$path = "$env:TEMP\EwsManagedApi.MSI" | |
$webclient.DownloadFile($url, $path) | |
$argument = '/quiet' | |
Start-Process $path $argument –Wait | |
} else { | |
Write-Warning "Please visit https://www.microsoft.com/en-us/download/details.aspx?id=44011 to download the EWS managed API manually" | |
exit | |
} | |
} | |
Add-Type –Path $apiPath | |
$script:service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion) | |
if ($provideCredentials){ | |
$credentials = Get-Credential | |
$service.Credentials = $credentials.GetNetworkCredential() | |
} | |
$service.AutodiscoverUrl($email) | |
$oofSetting = $service.GetUserOofSettings($email) | |
if (!$off){ | |
$dateRange = Get-DateRange | |
$startDt = [DateTime]::Parse(($dateRange.Start.ToLongDateString() + " 12:00 AM")) | |
#get next business day | |
$returnDt = $dateRange.End.AddDays(1) | |
while ($returnDt.DayOfWeek -eq "Saturday" -or $returnDt.DayOfWeek -eq "Sunday") { $returnDt = $returnDt.AddDays(1) } | |
$endDt = [DateTime]::Parse(($dateRange.End.AddDays(1).ToLongDateString() + " 12:00 AM")) | |
$msg="<span style='font-size:10.0pt;font-family:" + '"Arial","sans-serif"' + "'>" | |
$text=@" | |
Hello, | |
<br><br>Thank you for your email. | |
<br> | |
<br>Please note I will be out of the office from $($startDt.ToLongDateString()), returning $($returnDt.ToLongDateString()). During this time I will have no access to emails. | |
<br><br><br><br> | |
"@ | |
$msg += $text + "</span>" | |
#if on company pc get the signature otherwise go with the local copy | |
$remoteSigPath ="$env:APPDATA\Microsoft\Signatures\PLTeam.htm" | |
$localSigPath = ".\Signature.htm" | |
if (Test-Path $remoteSigPath){ | |
copy $remoteSigPath $localSigPath | |
} | |
$msg += Get-Content $localSigPath | Out-String | |
$msg = $msg.ToString() | |
$msg = New-Object Microsoft.Exchange.WebServices.Data.OofReply($msg) | |
$oofSetting.InternalReply = $msg | |
$oofSetting.ExternalReply = $msg | |
$duration = New-Object Microsoft.Exchange.WebServices.Data.TimeWindow($startDt,$endDt) | |
$oofSetting.Duration = $duration | |
$oofSetting.State = [Microsoft.Exchange.WebServices.Data.OofState]::Enabled | |
$service.SetUserOofSettings($email, $oofSetting) | |
Set-CalendarAppointment $startDt $endDt "Out of Office" "Away" | |
Write-Host "Set OOTO from $($startDt.ToShortDateString()) to $($endDt.AddDays(-1).ToShortDateString())" | |
} | |
else{ | |
$oofSetting.State = [Microsoft.Exchange.WebServices.Data.OofState]::Disabled | |
$service.SetUserOofSettings($email, $oofSetting) | |
} | |
} | |
Export-ModuleMember –Function @('Set-OOTO') | |