Cmdlet Extension Agents (Part 2)

by [Published on 16 July 2013 / Last Updated on 16 July 2013]

In the first part of this three-part article, we had a look at what Cmdlet Extensions Agents are and how they work. The second and third parts will be full hands-on as we will see how to use the Scripting agent to extend any Exchange cmdlet and go through a few examples about improving the mailbox provisioning process.

If you would like to read the other parts in this article series please go to:

Scripting Agent Configuration File

The Scripting agent configuration file is an XML file named ScriptingAgentConfiglocated in the <installation path>\V15\Bin\CmdletExtensionAgents folder:

Image
Figure 2.1: Scripting Agent Configuration File Location

This file contains all the scripts that you want the Scripting agent to run. As this is an XML file, scripts in this file are contained within XML tags that define the beginning and end of the script and various input parameters required to pass data to the script. Although this is an XML file and scripts are contained within XML tags, scripts are written using PowerShell syntax.

As you can see in Figure 2.1, initially this file is named ScriptingAgentConfig.xml.sample. This is a sample configuration file that contains sample scripts that you can use to help you understand how to add scripts to the configuration file. The following picture shows part of the content of this file where you can see most of the elements that are part of the configuration file:

Image
Figure 2.2: Scripting Agent Sample Configuration File

As it is explained at the start of the sample file, some characters typically used in scripts have a special meaning in XML. As such, to use these characters we must use escape sequences:

  • Instead of a greater than sign ( > ), use &gt;
  • Instead of a less than sign ( < ), use &lt;
  • Instead of an ampersand ( & ), use &amp.

The configuration file uses the following elements or attributes:

Element

Attribute

Description

Configuration

 

This element contains all the scripts that the Scripting agent cmdlet extension agent can run. The Feature tag is a child of this tag.

There is only one Configuration tag in the configuration file.

Feature

 

This element contains a set of scripts that relate to a feature. Each script, defined in the ApiCall child tag, extends a specific part of the cmdlet execution pipeline. This tag contains the Name and Cmdlets attributes.

There can be multiple Feature tags under the Configuration tag.

 

Name

This attribute contains the name of the feature. Use this attribute to help identify which feature is extended by the scripts contained within the tag.

 

Cmdlets

This attribute contains a list of the Exchange cmdlets used by the set of scripts in this feature extension. You can specify multiple cmdlets by separating each cmdlet with a comma.

ApiCall

 

This element contains scripts that can extend a part of the cmdlet execution pipeline. Each script is defined by the API call name in the cmdlet execution pipeline it is extending. The following are the API names that can be extended:

  • ProvisionDefaultProperties
  • UpdateAffectedIConfigurable
  • Validate
  • OnComplete
 

Name

This attribute includes the name of the API call that is extending the cmdlet execution pipeline.

Common

 

This element contains functions that can be used by any script in the configuration file.

Table 1 

Important:
Every Exchange 2013 server includes the file ScriptingAgentConfig.xml.sample in the <installation path>\V15\Bin\CmdletExtensionAgents folder. This file must be renamed to ScriptingAgentConfig.xml on every Exchange 2013 server in the organization if you enable the Scripting Agent cmdlet extension agent. This is because you do not know which Exchange server an administrator will connect to or which server will execute the cmdlet.

The same applies when you add code to the configuration file, or when you make a change to the configuration file - you must update the file on every Exchange server to ensure that each server contains an up-to-date version of the scripts that the Scripting Agent runs. If different servers contain different configuration files, the results for the cmdlets they extend will not be the same across the organization depending on which server executed the cmdlet.

Enabling the Scripting Agent

As we saw previously, the Scripting agent cmdlet extension agent is the only one disabled by default. When you enable it, the agent is enabled for the entire Exchange 2013 organization.

Before you enable the Scripting agent, it is important to verify that the ScriptingAgentConfig.xml.sample configuration file has been correctly renamed and updated with your scripts on every Exchange 2013 server. You will receive the following error message each time a non-Get* cmdlet is run if you enable the Scripting agent without renaming the configuration file correctly or copying a configuration file to this computer from another Exchange 2013 server:

Image
Figure 2.3:
Scripting Agent Error

To enable the Scripting agent, you must do the following:

  1. Rename the ScriptingAgentConfig.xml.sample file in <installation path>\V15\Bin\CmdletExtensionAgents to ScriptingAgentConfig.xml on every Exchange 2013 server in your organization. Alternatively, you can copy the configuration file from one Exchange 2013 server to all other Exchange 2013 servers;
  2. Enable the Scripting agent cmdlet extension agent by running the Enable-CmdletExtensionAgent "Scripting Agent" cmdlet.

Now that the Scripting agent is enabled, we can start adding scripts to the configuration file to extend the capability of any cmdlets we want.

Remember that you must add the same code to every single configuration file in all your Exchange servers because you do not know which Exchange server an administrator will connect to or which server will execute the cmdlet.

Automatically Create Archive Mailbox

Let us say that whenever a new mailbox is created you want to automatically enable it for archiving and create the archive mailbox on a particular database. When possible, one of the things I like to do is create normal mailboxes in databases named MDB01, MDB02, etc., and the respective archive mailbox on a separate database with the same “number”: ADB01, ADB02, etc. This assuming everyone in the organization will be enabled for archiving, otherwise this approach is clearly not the best.

So let us consider this scenario and see how we could use the Scripting agent to achieve this.

To do this, we need to add a script to the ScriptingAgentConfig.xml configuration file on all Exchange servers. For this scenario we will use the OnComplete API and check the $succeeded parameter so that our code only runs when a mailbox is created successfully.

<?xml version="1.0" encoding="utf-8" ?>

<Configuration version="1.0">

   <Feature Name="MailboxProvisioning" Cmdlets="New-Mailbox">

     <ApiCall Name="OnComplete">

       If($succeeded) {

         $mbx = $provisioningHandler.UserSpecifiedParameters["Name"]

 

         If ((Get-Mailbox $mbx).ArchiveDatabase -eq $null) {

           $mbxDatabase= (Get-Mailbox $mbx).Database

           $arcDatabase= $mbxDatabase -ireplace "M", "A"

           Enable-Mailbox $mbx -Archive -ArchiveDatabase $arcDatabase

         }

       }

     </ApiCall>

   </Feature>

</Configuration>

Here is how this code works:

  • The Configuration tag contains all the scripts that the Scripting agent cmdlet extension agent can run, so we place our code inside this tag (remember that there is only one Configuration tag in the configuration file);
  • Next we create a new Feature, which will contain a set of scripts related to a feature and defined in the ApiCall child tag (remember that there can be multiple Feature tags under the Configuration tag). We use the Name attribute to name this Feature something meaningful like MailboxProvisioning since our code is related the provisioning of mailboxes. We also use the Cmdlets attribute to specify to which cmdlets our code applies to. In this case, we only want the code to run when a new mailbox is created, so we only specify the New-Mailbox cmdlet;
  • For the ApiCall tag, we use the Name property to specify we will be using the OnComplete API so that the code runs after the New-Mailbox cmdlet is complete;
  • Then starts the code itself:
    • $provisioningHandler.UserSpecifiedParameters contains user provided parameters passed to the cmdlet. As such, $provisioningHandler.UserSpecifiedParameters["Name"] returns the value of the Name parameter in the New-Mailbox cmdlet. We could use Alias instead for example;
    • We then check if the mailbox was created with a personal archive. If it was not, then we proceed. If we really wanted, we could extend this code to check if the archive mailbox was created in the right database and move it if it was not;
    • Next, we check in which database the mailbox was created by reading the MailboxDatabase property of the mailbox;
    • We then map the mailbox database name to the personal archive naming convention by replacing the first character of the database name (“M”) with an “A”;
    • Finally, we enable the mailbox for archiving by executing the Enable-Mailbox cmdlet.

And here is how the configuration file looks like (note that I have removed all the code that was present in the sample file as I am not interested in it):

Image
Figure 2.4:
Configuration File to Create Archive Mailbox

Now it is time to test it! To do so, let us simply create a normal mailbox without specifying in which database to create it so that the Mailbox Resources Management agent (responsible for the automatic mailbox distribution) selects a random database and we can see if our code in the Scripting agent does the job right:

Image
Figure 2.5:
Configuration File to Create Archive Mailbox - Test 

As you can see from the screenshot above, I created a mailbox called Test1 and only specified its UserPrincipalName and Password. The Mailbox Resources Management agent returned MDB05 as the database where to create the mailbox and our code automatically created an archive for it in the ADB05 database. All working exactly as we wanted!

An alternative to use the OnComplete API would be to use the ProvisionDefaultProperties to define the personal archive parameters. However, this might conflict with the Mailbox Resources Management agent. As we saw in section Agent Priority in the first part of this article series, by default the Mailbox Resources Management agent has a higher priority (2) than the Scripting Agent (6), meaning it will override any settings made by the Scripting agent.

We could assign the Scripting agent a higher priority than the Mailbox Resources Management agent. The problem with this approach is that we would not have a database value so we would not be able to determine the right archive database. This unless we make our script do all the work from start to finish.

Conclusion

In this second part of this article series, we had a look at how the Scripting agent works and how we can use it to automatically create an archive when a new mailbox is created. In the third and final part, we will see how to further extend this agent to configure certain mailbox properties such as ActiveSync, IMAP, Single Item Recovery, etc. We will also see how to automatically send a welcome e-mail and a couple of examples of uses for the Validate API.

If you would like to read the other parts in this article series please go to:

Advertisement

Featured Links