Contents

Using cmdlet extensions to automate Exchange

There are some days I actualy feel sorry for my colleagues. Not because we hate our jobs (far from!) or because we have to drink bad coffee while in the office, but because my standard resposne to every request for help seems to be:

Have you tried using Powershell? ūüėČ

Ever since Windows Server 2012 and Exchange 2013 it’s obvious that Powershell is the way to go: it’s here to stay! The GUI’s for management are stripped down more and more, especialy in Exchange where the GUI has been nothing more than a graphical shell around Powershell for a while now.

However, there still are things that don’t come naturally in Powershell or the EMC. One of those things I ran into a few weeks ago, while setting up Exchange retention policies on an on-prem Exchange server.

Introduction

The particular costumer was using Exchange 2010 SP3, in combination with a software based anti-spam solution. Ever since they’ve been using this software, all users have gotten used to the ‘spam’ or ‘junk’ folder in Outlook, where the anti-spam software would place suspicious emails. The user then can scan this folder manualy, checking if the mail is indeed a spam message or that a legitimate mail has been marked as spam: a so-called false positive. There is one downside to this way of working: users check the folder, read or move the mail they need and just ignore the rest. The junk folder quickly fills up with bad emails using up storage and backup resources, while they ofcourse just should be deleted.

The solution is relatively simple: retention policies. Just create a retention tag for the junk folder, set it to ‘delete after 30 days’ and create a retention poicy you can apply to all mailboxes.

Apply the policy

Applying the policy to all mailboxes is done in a blink, when using PoSH

1
get-mailbox -resultsize unlimited | foreach {set-mailbox $_.identity -retentionpolicy policy}

Easy as that‚Ķ But the policy now only applies to existing mailboxes. Newly created mailboxes won’t get this policy applied automaticly. It’s not possible to set a default policy for all mailboxes in you environment or in a particular database.

No matter if your using EMC or EMS, when creating a mailbox you will have to specify explicitly that you want to apply this policy.

So that’s where the Exchange cmdlet extension agents come in! In this case, the scripting agent.

Exchange comes with several ‘extension agents’, for example to mange the Offline Address Book. The scriptig agent is one of those seven agents and is the only one that is disabled by default.

The agent’s work is fairly simply, but it’s an unknown (or better: relatively unmentioned) part of Exchange. After activating the scripting agent, it will be called every time a cmdlet is run on the server. That goes for cmdlets run directly from the Powershell interface, but for cmdlets run from EMC, Exchange services or Exchange Control Panel too.

When the agent is called, it checks if there are scripts defined for that particular cmdlet. So that’s what we are going to do to make sure our retention policy is applied on all new mailboxes!

First of all, we have to activate the scripting agent. This is simple: in the <installation path>\V14\bin\cmdletextensionagents folder there’s a ScriptingAgentConfig.xml sample. By renaming this to ScriptingAgentConfig.xml we create the config file for the scripting agent. The agent itself, we active through, you guessed it, Powershell.

1
Enable-CmdletExtensionAgent "Scripting Agent"

Now we have to make the script do what we want.

Configure the script

First we’ll have a look at the entire script, after that we’ll break it in pieces to see what it does.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<xml version="1.0" encoding="utf-8">
<Configuration version="1.0">
<Feature Name="Mailboxes" Cmdlets="New-Mailbox,Enable-Mailbox">
<ApiCall Name="OnComplete">
if($succeeded) { 
$Name= $provisioningHandler.UserSpecifiedParameters["Alias"] 
Set-Mailbox $Name -RetentionPolicy "Retention Policy" 
} 
</ApiCall>
</Feature>
</Configuration>

The first thing to notice, is that it isn’t an actual script, but it’s XML. The XML-file specifies what script to run in what situation. Because of this setup, it’s easy to have multiple actions in one config file.

The first real lines after opening the XML-file call the action on creating new mailboxes or mail-enabling existing users.

1
2
<Feature Name="Mailboxes" Cmdlets="New-Mailbox,Enable-Mailbox">
<ApiCall Name="OnComplete">

In other words: when using the new-mailbox or enable-mailbox cmdlet an action should be started, when the cmdlet has been run completely. The feature name tag is something we can specify freely and is purely meant to clearify the XML-file. For example, you can separate scripts meant for provisioning from scripts that should be started when removing a mailbox.

The next few lines specify when the action should be run and ofcourse what the action is.

1
2
3
4
if($succeeded) { 
$Name= $provisioningHandler.UserSpecifiedParameters["Alias"] 
Set-Mailbox $Name -RetentionPolicy "Retention Policy" 
}

First, the $name variable is set, by the called API, with the name of recently created mailbox. Next, set-mailbox is called to the $name mailbox for setting the retention policy.

In the script block, specified by the { and } symbols, we can run any regular PoSH-code. However, we can choose to call an external .ps1-file as well. When you are going the use the scripting agent a lot and for more complex code, that will surely improve the readability of the config file.

User experience

The actions that are run by the scripting agent aren’t visible in the Powershell code the EMC displays when creating a mailbox. You do get feedback however, when the API-call running the scripting agent can’t be run correctly and returns an error. In that case, the mailbox will be created succesfully but the extra actions from the scripting agent won’t be run on the mailbox.

When the scripting agent does it job without any problems, directly after creating the mailbox you can check the properties of the newly created mailbox to see the retention policy has been applied.

As you see, using the scripting agent enables you to automate a lot in your Exchange-environment. The best way to check it out, is to fire up your testing environment to see what you can do.

Example usage

Just to get you started, another cool example of using this technique:

1
2
3
4
5
6
7
8
<Feature Name="MailboxProvisioning" Cmdlets="remove-mailbox">
<ApiCall Name="validate">
if($succeeded)    { 
$removedmailbox = $provisioningHandler.UserSpecifiedParameters["Name"] 
New-MailboxExportRequest -Mailbox $removedmailbox -FilePath \\filserver\PSTFiles 
} 
</ApiCall>
</Feature>

In this case, the validate API-call is used. When running a cmdlet, Exchange will always check if the cmdlet is valid and if there is enough information to start the cmdlet. If this is the case, the scripting agent Is triggered. So, this happens before the cmdlet is actualy run. Whit this information, can you guess what above code does? ūüėČ

Last tip before you start using the scripting agent: in a multiserver environment, the scripting agent must be activated on each server and the XML-file must be available on each server. The easiest way ofcourse, is to just copy the XML-file between servers.

If you want to know more about the scripting agent, you can ofcourse check Technet.