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:

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:

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:




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

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:

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






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):

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:

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.


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:

Nuno Mota

Nuno Mota is an Exchange MVP working as a Microsoft Messaging Specialist for a financial institution. He is passionate about Exchange, Lync, Active Directory, PowerShell, and Security. Besides writing his personal Exchange blog, LetsExchange.blogspot.com, he regularly participates in the Exchange TechNet forums and is the author of the book “Microsoft Exchange Server 2013 High Availability.”

Published by
Nuno Mota

Recent Posts

Hardware RAID vs. software RAID: Pros and cons for each

RAID is a technique to virtualize independent disks into arrays for improved performance. Should you…

4 days ago

After the plague: What IT will look like in a post-COVID-19 world

COVID-19 has changed everything, but once it disappears, we will not go back to how…

4 days ago

Solved: Outlook defaults to Microsoft 365 version with Exchange server

An Exchange server with a hybrid connection to Microsoft 365 is usually pretty seamless —…

4 days ago

How chatbots are changing the way teams communicate internally

Chatots are primarily thought of as consumer-facing solutions. They bring life to customer interactions by…

5 days ago

Hakbit ransomware campaign targeting specific European countries

The newly uncovered Hakbit ransomware campaign spread via spear-phishing emails may indicate a shift in…

5 days ago

Credential stuffing: Everything you need to know to avoid being a victim

Credential stuffing is yet another weapon being used by cybercriminals. Here’s what credential stuffing is…

5 days ago