Manage Exchange 2007 Out-Of-Office (OOF) Settings with PowerShell and the EWS Managed API

by Mike Pfeiffer on July 12, 2010

One of the new features in Exchange 2010 is the ability to manage Out-Of-Office settings for mailboxes from EMS. This is made possible by the Get-MailboxAutoReplyConfiguration and Set-MailboxAutoReplyConfiguration cmdlets. Unfortunately, these cmdlets are only available in Exchange 2010. With Exchange 2007 SP2 or higher, using the Exchange EWS Managed API and PowerShell v2, you can write your own advanced functions that emulate the functionality of the auto reply cmdlets included with 2010. In this post, I'll share a couple of functions that you can use from within EMS that will allow you to do that.

Mailbox Permissions

Before we look at the code, a quick note about permissions. Ideally, we'd like to use Exchange impersonation to access and modify the OOF settings for a user. Unfortunately, EWS impersonation doesn't work with the GetUserOofSettings and SetUserOofSetting methods (see this post for details). So, you'll need to use the Add-MailboxPermission cmdlet to assign your account full access to the mailboxes you want to manage. For more details on Exchange Impersonation vs. Delegate Access, also check out this post.

The Get Function

This code assumes the EWS Managed API assembly is located in c:\bin; update the path as needed for your machine. If you have not yet downloaded the EWS Managed API, you can grab it here. This function is designed to return information similar to the Get-MailboxAutoReplyConfiguration cmdlet in Exchange 2010, here is the code:

function Get-EWSOofSettings {
    [CmdletBinding()]
    param(
        [Parameter(Position=0, ValueFromPipelineByPropertyName=$true, Mandatory=$true)]
        [System.String]
        [Alias("Identity")]
        $PrimarySmtpAddress,
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $ver = "Exchange2007_SP1"
        )

    begin {
        Add-Type -Path "C:\bin\Microsoft.Exchange.WebServices.dll"
        $sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
        $user = [ADSI]"LDAP://<SID=$sid>"
    }

    process {
        $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -Arg $ver
        $service.AutodiscoverUrl($user.Properties.mail)    

        if($PrimarySmtpAddress -notmatch "@") {
          $PrimarySmtpAddress = (Get-Recipient $PrimarySmtpAddress).PrimarySMTPAddress.ToString()
        }

        $oof = $service.GetUserOofSettings($PrimarySmtpAddress)
        New-Object PSObject -Property @{
            State = $oof.State
            ExternalAudience = $oof.ExternalAudience
            StartTime = $oof.Duration.StartTime
            EndTime = $oof.Duration.EndTime
            InternalReply = $oof.InternalReply
            ExternalReply = $oof.ExternalReply
            AllowExternalOof = $oof.AllowExternalOof
            Identity = (Get-Recipient $PrimarySmtpAddress).Identity
        }
    }
}

Once you have the mailbox permissions worked out and have added the function to your PowerShell session, you can test out the code. The following example shows how you would run the function:

Get-EWSOofSettings -Identity abarlow

The above information is returned for a user with the alias of abarlow. If you've worked with the Get-MailboxAutoReplyConfiguration cmdlet in Exchange 2010, you'll notice that all of the same information is returned.

Finding Users in the Organization with Out-Of-Office Enabled

The Get-EWSOofSettings function is designed to accept pipeline input from the Get-Mailbox cmdet. This means that you could find the settings for multiple users in a single command. For instance, it may be useful to find all users who currently have OOF enabled:

Get-Mailbox | Get-EWSOofSettings | ?{$_.state -eq "Enabled"} | select identity, state

It's worth mentioning here that if a user has a duration set (start and end time) the state will show as "Scheduled". In that case, you would simply modify your where clause to ?{($_.state -eq "Enabled") -or ($_.state -eq "Scheduled")}

The Set Function

Again, this code assumes the EWS Managed API assembly is located in c:\bin, you'll need to update the path accordingly. This function is similar to the Set-MailboxAutoReplyConfiguration cmdlet in Exchange 2010.

function Set-EWSOofSettings {
    [CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$true)]
        [System.String]
        $Identity,
        [Parameter(Position=1, Mandatory=$false)]
        [System.String]
        $State,
        [Parameter(Position=2, Mandatory=$false)]
        [System.String]
        $ExternalAudience,
        [Parameter(Position=3, Mandatory=$false)]
        [System.DateTime]
        $StartTime,
        [Parameter(Position=4, Mandatory=$false)]
        [System.DateTime]
        $EndTime,
        [Parameter(Position=5, Mandatory=$false)]
        [System.String]
        $InternalReply,
        [Parameter(Position=6, Mandatory=$false)]
        [System.String]
        $ExternalReply,
        [Parameter(Position=7, Mandatory=$false)]
        [System.String]
        $ver = "Exchange2007_SP1"
        )

    begin {
        Add-Type -Path "C:\bin\Microsoft.Exchange.WebServices.dll"
        $sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
        $user = [ADSI]"LDAP://<SID=$sid>"
    }

    process {
        $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -arg $ver
        $service.AutodiscoverUrl($user.Properties.mail)    

        if($Identity -notmatch "@") {
            $Identity = (Get-Recipient $Identity).PrimarySMTPAddress.ToString()
        }        

        $oof = $service.GetUserOofSettings($Identity)

        if($StartTime -and $EndTime) {
            $Duration = New-Object Microsoft.Exchange.WebServices.Data.TimeWindow `
            -arg $StartTime,$EndTime
            $PSBoundParameters.Duration = $Duration
            $PSBoundParameters.State = "Scheduled"
            [Void]$PSBoundParameters.remove("StartTime")
            [Void]$PSBoundParameters.remove("EndTime")
        }

        foreach($p in $PSBoundParameters.GetEnumerator()) {
            if($p.key -ne "Identity") {
                $oof."$($p.key)" = $p.value
            }
        }
        $service.SetUserOofSettings($Identity,$oof)
    }
}

Here is an example using the above function to enable out-of-office for a user:

Set-EWSOofSettings -Identity bharris -State Enabled -InternalReply "I am out of the office"

Looking at the function parameters, you can see that several properties can be set including start and end time, internal and external reply, and also external audience.

Here is another example. This will schedule out of office using a start and end time, set the internal and external reply, and configure the external audience to "Known" so that external replies are only sent to recipients in the users contact list:

$start = Get-Date "7/12/2010"
$end = Get-Date "7/15/2010"
Set-EWSOofSettings -Identity jknapp -StartTime $start -EndTime $end -InternalReply "I am out of the office" -ExternalReply "I am out of the office" -ExternalAudience Known

Note that when setting a start and end time, you do not need to provide a value for the state parameter, it will automatically be set to "Scheduled". And finally, to turn off OOF for a user, set the value for the state parameter to "disabled".

Related Posts

{ 4 trackbacks }

links for 2010-07-12 « Steve Goodman's Tech Blog – The weblog of an IT pro specialising in Exchange, Exchange, VMware, Servers and Storage
July 12, 2010 at 3:05 pm
links for 2010-07-15 « Steve Goodman's Tech Blog – The weblog of an IT pro specialising in Exchange, Exchange, VMware, Servers and Storage
July 26, 2010 at 2:28 pm
Set Out-Of-Office for a user without using his credentials « Sadissa B.'s Blog
November 1, 2010 at 6:47 am
Changing another user’s Out of Office reply | Baerst Blog
November 16, 2011 at 2:30 pm

{ 35 comments… read them below or add one }

PSLover October 6, 2010 at 3:02 pm

Very usefull tips for those running exchange 2007, thank you for sharing

Reply

Mike Pfeiffer October 6, 2010 at 9:27 pm

Thanks for the feedback :)

Reply

Marcos Posh December 1, 2010 at 8:45 am

This tip saved my day.
Greatly appreciated your sharing.

Reply

Mike Pfeiffer December 1, 2010 at 8:46 am

Awesome, thanks Marcos!

Reply

Josh Bright December 1, 2010 at 9:42 am

Thanks for the post… I’m trying to implement this but I get this error in PowerShell console when I try to run the first code …
Missing closing ‘)’ in expression.
At C:\Documents and Settings\besadmin\Desktop\Step1.ps1:5 char:9
+ [ <<<< System.String]

Any suggestions on what I'm doing incorrect?

Josh

Reply

Mike Pfeiffer December 1, 2010 at 9:46 am

Josh, are you running PowerShell v2? Also, have a look at this post

Reply

Josh Bright December 1, 2010 at 9:51 am

I’m using 1.0

Reply

Mike Pfeiffer December 1, 2010 at 9:56 am

Ok, that is the problem. As stated at the beginning of the post, these are advanced functions written for PowerShell v2. If you are running Exchange 2007 SP2 or higher, you can upgrade to PowerShell v2 and then you’ll be all set.

Reply

Josh Bright December 1, 2010 at 9:56 am

Great! Thanks I must have missed that line.

Josh Bright December 1, 2010 at 10:28 am

One more thing… I updated to 2.0 and ran the two listed above, but when I try to use EMS to get the in I get this [PS] C:\Documents and Settings\besadmin>Get-EWSOofSettings -Identity jbright
The term ‘Get-EWSOofSettings’ is not recognized as the name of a cmdlet, functi
on, script file, or operable program. Check the spelling of the name, or if a p
ath was included, verify that the path is correct and try again.
At line:1 char:19
+ Get-EWSOofSettings <<<< -Identity jbright
+ CategoryInfo : ObjectNotFound: (Get-EWSOofSettings:String) [],
CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Josh Bright December 3, 2010 at 7:44 am

Last Post I promise… If I can’t figure this out I go on Merry Way!

[PS] C:\Documents and Settings\frodo1>Get-Mailbox -ResultSize Unlimited -Identit
y jbright | ForEach-Object { Get-EWSOofSettings -Identity $_.alias }
Exception calling “AutodiscoverUrl” with “1″ argument(s): “A valid SMTP address
must be specified.”
At C:\Get-OOF.psm1:21 char:33
+ $service.AutodiscoverUrl <<<< ($user.Properties.mail)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Exception calling "GetUserOofSettings" with "1" argument(s): "The Url property
on the ExchangeService object must be set."
At C:\Get-OOF.psm1:27 char:43
+ $oof = $service.GetUserOofSettings <<<< ($PrimarySmtpAddress)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Reply

Mike Pfeiffer December 3, 2010 at 9:14 am

The function uses autodiscover to determine the EWS url based on the identity of the person running the code. Does the user account you are running the function with have an Exchange mailbox, and is the mail attribute set on their AD account to a valid smtp address?

Reply

Andrew Vogel December 10, 2010 at 9:18 am

Wow. All I have to say is, “Thank you!”

Reply

Mike Pfeiffer December 10, 2010 at 11:47 am

Your very welcome Andrew!

Reply

Bruno Domingues December 12, 2010 at 7:35 pm

Hi Mike,

I’m having the similar problem Josh had:

“[PS] C:\>Get-EWSOofSettings -identity UXX
Exception calling “AutodiscoverUrl” with “1″ argument(s): “The Autodiscover ser
vice couldn’t be located.”
At C:\Program Files\Microsoft\Exchange Server\bin\Get-EWSOofSettings.ps1:21 cha
r:33
+ $service.AutodiscoverUrl <<<< ($user.Properties.mail)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Exception calling "GetUserOofSettings" with "1" argument(s): "The Url property
on the ExchangeService object must be set."
At C:\Program Files\Microsoft\Exchange Server\bin\Get-EWSOofSettings.ps1:27 cha
r:43
+ $oof = $service.GetUserOofSettings <<<< ($PrimarySmtpAddress)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

StartTime :
State :
InternalReply :
ExternalReply :
Identity : XX-ad/XXX/XXX/Users/XX, User
ExternalAudience :
EndTime :
AllowExternalOof :"

I had a look on your other posts but can't get it to work. I'm running PowerShell 2 under Windows XP SP3 and the Exchange is 2007 SP3.

Really appreciate if you could help me since this Oof is a day-to-day process and we need to find a better way to do it!!

Rgrds,
Bruno

Reply

ExchangeGuy June 23, 2011 at 2:52 pm

I have Windows 7 , 32 bit operating system with service pack 1.
I have installed exchange 2007 SP3 management tools on it with powershell version 2.0
I also installed the Exchange and Active Directory powerpacks from PowerGui.
I have created my profile with the get-ewsoofsettings function and my profile loads without any error.

When I run get-ewsoofsettings -identity user@domain.com I get the following error
———-
Exception calling “AutodiscoverUrl” with “1″ argument(s): “A valid SMTP address
must be specified.”
At C:\Users\xxx\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.p
s1:21 char:33
+ $service.AutodiscoverUrl <<<< ($user.Properties.mail)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Exception calling "GetUserOofSettings" with "1" argument(s): "The Url property
on the ExchangeService object must be set."
At C:\Users\xxx\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.p
s1:27 char:43
+ $oof = $service.GetUserOofSettings <<<< ($PrimarySmtpAddress)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Reply

Mike Pfeiffer June 26, 2011 at 4:25 pm

The function attempts to use the callers email address to determine the EWS endpoint using AutoDiscover. Are you running this with an account that has an Exchange mailbox? If not, that could be the cause of the error.

Reply

smooter July 13, 2011 at 6:49 am

Is it possible to do this without the Autodiscover section in the code?

The first command complains about the Autodiscover not being able to be located, but it does return the OoO settings.

However, when I run the second, it pukes all over the place and will not make any adjustments.

Exception calling “AutodiscoverUrl” with “1″ argument(s): “The Autodiscover ser
vice couldn’t be located.”
At C:\utilities\Set-EwsOofSettings.psm1:38 char:33
+ $service.AutodiscoverUrl <<<< ($user.Properties.mail)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Exception calling "GetUserOofSettings" with "1" argument(s): "The Url property
on the ExchangeService object must be set."
At C:\utilities\Set-EwsOofSettings.psm1:44 char:43
+ $oof = $service.GetUserOofSettings <<<< ($Identity)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Property 'InternalReply' cannot be found on this object; make sure it exists an
d is settable.
At C:\utilities\Set-EwsOofSettings.psm1:57 char:22
+ $oof. <<<< "$($p.key)" = $p.value
+ CategoryInfo : InvalidOperation: (InternalReply:String) [], Run
timeException
+ FullyQualifiedErrorId : PropertyNotFound

Property 'ExternalReply' cannot be found on this object; make sure it exists an
d is settable.
At C:\utilities\Set-EwsOofSettings.psm1:57 char:22
+ $oof. <<<< "$($p.key)" = $p.value
+ CategoryInfo : InvalidOperation: (ExternalReply:String) [], Run
timeException
+ FullyQualifiedErrorId : PropertyNotFound

Property 'Duration' cannot be found on this object; make sure it exists and is
settable.
At C:\utilities\Set-EwsOofSettings.psm1:57 char:22
+ $oof. <<<< "$($p.key)" = $p.value
+ CategoryInfo : InvalidOperation: (Duration:String) [], RuntimeE
xception
+ FullyQualifiedErrorId : PropertyNotFound

Property 'State' cannot be found on this object; make sure it exists and is set
table.
At C:\utilities\Set-EwsOofSettings.psm1:57 char:22
+ $oof. <<<< "$($p.key)" = $p.value
+ CategoryInfo : InvalidOperation: (State:String) [], RuntimeExce
ption
+ FullyQualifiedErrorId : PropertyNotFound

Exception calling "SetUserOofSettings" with "2" argument(s): "Value cannot be n
ull.
Parameter name: oofSettings"
At C:\utilities\Set-EwsOofSettings.psm1:60 char:36
+ $service.SetUserOofSettings <<<< ($Identity,$oof)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Thanks for your help!

smooter

Reply

Mike Pfeiffer July 14, 2011 at 6:27 am

Yeah, you can set the URL manually. For example, replace $service.AutodiscoverUrl($user.Properties.mail) with:

$url = “https://ex1.contoso.com/EWS/Exchange.asmx”
$service.Url = New-Object System.Uri -ArgumentList $url

Another thing to check is that the machine you are running the code from trusts the certificates on your CAS server.

Reply

Gui September 7, 2011 at 2:19 am

!!! VERY SIMPLE SOLUTION:

1. Give yourself full access permissions to the user’s mailbox

2. Goto your control panel, then Mail (32-bit)

3. Under Profiles, add a profile (no OST / Non-Cached Mode) with the user’s mail address (do not give credentials)

4. When asked for credentials just use your own ]

5. Open Outlook with newly created profile, and go to the OOO Assistant.

6. Voila!

Reply

Mike Pfeiffer September 7, 2011 at 11:46 am

That’s great…use whatever method works best for you. I am not saying my solution here is the best way to do anything. I’m just sharing some code I used to solve a problem.

Reply

Tom September 15, 2011 at 9:21 am

Can this be used against an exchange 2007 sp1 environment but running it on my win7 desktop with PS v2?

thanks!

Reply

Mike Pfeiffer September 15, 2011 at 10:03 am

Yes, you can run it remotley from Win7…just make sure the EWS Managed API assembly is local so it can be imported.

Reply

Sheetal Jain September 17, 2011 at 5:02 pm

Mike,

We are running into an issue while using GetUserOofSettings method of EWS. Every time we try using the current users’ credential it throws “The smtp address has no mailbox associated with” error. Though other api works… Do you have any suggestions ? I would greatly appreciate it

thanks
Sheetal

Reply

Maxy December 1, 2011 at 4:29 pm

Hello,

Is there any way to do the same for Exchange 2007 SP1?
Any ideas?

Thanks!

Reply

Mike Pfeiffer December 2, 2011 at 6:27 pm

Yes, you should be able to run it remotely from a machine with PowerShell v2…just make sure the EWS Managed API assembly is local so it can be imported.

Of course, 2007 SP1 is pretty old, so I’d consider upgrading to SP3 anyways. It’s been available since June of 2010. I know that’s not always an easy thing to do though :)

Reply

Ernesto December 15, 2011 at 9:44 am

Hello Mike,

I’m running this function on a server Exchange 2007 SP3, PS 2.0 and receive this message error

Exception calling “GetUserOofSettings” with “1″ argument(s): “The request faile
d. The remote server returned an error: (403) Forbidden.”
At C:\function.ps1:29 char:43
+ $oof = $service.GetUserOofSettings <<< User is not mailbox owner. User = S-1-5-21-292766723
8-228183578-1654702620-7801, MailboxGuid = S-1-5-21-2605977091-1024320090-31298
82909-1281″
At C:\function.ps1:29 char:43
+ $oof = $service.GetUserOofSettings <<<< ($PrimarySmtpAddress)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Any ideas?

Regards

Ernesto.

Reply

Mike Pfeiffer December 15, 2011 at 10:26 am

Do you have full access rights to the mailbox?

Reply

Ernesto December 16, 2011 at 2:27 am

Yes i have full access to the mailbox, also with the user i’m trying to run this function has a mailbox.

Sometimes i receive this error

[PS] C:\Documents and Settings\user1>Get-EWSOofSettings -Identity user2
Exception calling “GetUserOofSettings” with “1″ argument(s): “The request faile
d. The remote server returned an error: (403) Forbidden.”
At C:\function.ps1:29 char:43
+ $oof = $service.GetUserOofSettings <<< User is not mailbox owner. User = S-1-5-21-292766723
8-228183578-1654702620-7801, MailboxGuid = S-1-5-21-2605977091-1024320090-31298
82909-1281″
At C:\function.ps1:29 char:43
+ $oof = $service.GetUserOofSettings <<<< ($PrimarySmtpAddress)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException

Thanks in advance

Ernesto

Reply

Ernesto December 19, 2011 at 7:36 am

Thanks a lot for this post, is working now, seem to be we had a replication problems.

Ernesto.

Reply

Thiago Cardoso December 28, 2011 at 6:49 am

Mike Hi,

Can you post your script at Script Center?

http://technet.microsoft.com/en-US/scriptcenter/

Ty,

Reply

Mike Pfeiffer December 1, 2010 at 10:40 am

Sure, you’ll need to add the function to your PowerShell session, check out this post for details:

http://www.mikepfeiffer.net/2010/06/how-to-add-functions-to-your-powershell-session/

Reply

Josh Bright December 1, 2010 at 12:08 pm

I got it working! What about if you have three different Mailbox servers? Example EX1 EX2 EX3 if the code is ran on EX1 it can Set OOF on all mailboxes within EX1 but not EX2 and EX3? Thanks again! I know I’m filling up your comments section…

Reply

Mike Pfeiffer December 1, 2010 at 12:26 pm

Here’s an example. Let’s say that you want to disable OOF for every mailbox in the org:

Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox | ForEach-Object { Set-EWSOofSettings -Identity $_.alias -State Disabled }

So, you use Get-Mailbox to retrieve every mailbox in the organization, regardless of which database they are in and which server that database is mounted on. You then pipe the results to ForEach-Object, loop through each item in the collection and disable the setting for the mailbox.

Reply

Shohn January 25, 2011 at 9:25 am

Josh or Bruno,

How did you get it working? Experiencing the same problem – logged on as Enterprise Admin…

Reply

Leave a Comment

Previous post:

Next post: