≡ Menu

Implementing Custom Validation in the Exchange 2010 Management Tools

Let’s say that you are in charge of a large Exchange organization that is distributed across multiple locations. You have administrators on your messaging team that are located in multiple cities, and they will be delegated tasks like managing recipients and creating mailbox databases. You need to implement a naming convention for mailbox databases, and you want to ensure that databases are only created using a predefined naming scheme, such as SEA-DB-01, or PHX-DB-01. This is a great use case for the scripting agent validation API.

The scripting agent is a cmdlet extension agent that allows you to hook into the execution of the cmdlets being run within your organization. This works both for cmdlets that are being run directly from the management shell, or in the background as changes are being made in EMC. The scripting agent has several APIs, like ProvisionDefaultProperties and OnComplete (good examples of these can be found here, here, and here), which can be used to trigger one or more commands before or after a cmdlet is executed. It also provides the Validate API which can be used to make sure that administrators are using acceptable values for input when using the management tools.

Let’s take a look at how to use this to validate input and enforce a standard naming convention for mailbox databases. First, create an XML file called ScriptingAgentConfig.xml with the following code. Save the file on each Exchange 2010 server in the <Install Path>\V14\bin\CmdletExtensionAgents directory.

<?xml version="1.0" encoding="utf-8" ?>
<Configuration version="1.0">
  <Feature Name="Custom Validation" Cmdlets="New-MailboxDatabase,Set-MailboxDatabase">
    <ApiCall Name="Validate">
      if($provisioningHandler.UserSpecifiedParameters["Name"] -cnotmatch '^[A-Z]{3}-DB-\d{2}$') {
        New-Object -type Microsoft.Exchange.Data.ProvisioningValidationError -argumentlist (
        "Please use proper naming convention for databases (e.g., PHX-DB-01)",
        [Microsoft.Exchange.Data.ExchangeErrorCategory]::Client
        )
      }
    </ApiCall>
  </Feature>
</Configuration>

This code might look a little strange with all of these XML tags, especially if you are not a developer, but we just need to focus on a few key points. Notice that within the Feature tag we’ve defined two cmdlets; New-MailboxDatabase and Set-MailboxDatabase. We’re basically telling the scripting agent that we want to run a script when either of these cmdlets are executed. We’ve specified that we want to use the Validate API in the APICall tag, and as you can see inside this tag we’ve got some PowerShell code. When either of these cmdlets are executed, we can check the value assigned to the Name parameter by accessing the corresponding key name in $provisioningHandler.UserSpecifiedParameters to make sure it complies with our standard naming convention.

This validation code checks the value assigned to the Name parameter to see if it matches a regular expression, which in this case is ^[A-Z]{3}-DB-\d{2}$. Notice that I’ve used the -cnotmatch operator here, so that pattern is case sensitive. The ^ is the start of line anchor, which is followed by [A-Z]{3} which means that the value provided for the database name should start with three letters, such as a city code like PHX or NYC. Next we have the -DB- characters that represent a literal value. Finally, the \d{2}, which is followed by the $ end of line anchor, means that the database name should end with a two digit code, like 01 or 02. If the database name does not match the pattern when attempting to create a database with New-MailboxDatabase, or when trying to rename one using Set-MailboxDatabase, a validation error is thrown and the command fails. Based on all of this, valid database names would be something like PHX-DB-12, SEA-DB-04, or NYC-DB-71.

Once your XML file has been created and deployed to the servers, you just need to enable the scripting agent from the Exchange Management Shell:

Enable-CmdletExtensionAgent 'Scripting Agent'

This is an organization wide setting, so again, the XML file needs to reside on each Exchange server. This is because administrators could potentially be running commands against any server in the organization. When testing this in your lab, you’ll probably need to restart the Exchange tools to make sure it picks up the changes.

Once all of this is in place, you’re ready to test it out. Below you can see I am trying to run the New-MailboxDatabase cmdlet to create a mailbox database that does not conform to my database naming convention, and I receive an error explaining what the problem is:

And of course, since the graphical tools are built on Exchange cmdlets, you’ll see the same error in EMC when trying to use a non-compliant database name:

Keep in mind that you can change the regular expression used in the code to meet your requirements, or you can replace it completely with any other validation logic. Also, you can perform validation on any of the Exchange cmdlets, this is just one scenario. For more code samples, check out the ScriptingAgentConfig.xml.sample file in the CmdletExtensionAgents directory on an Exchange server. You might also want to take a look at Understanding the Scripting Agent on TechNet.

8 comments… add one

  • Turbomcp July 4, 2011, 1:38 pm

    Great stuff
    as always
    highly appreciated

  • Mike Pfeiffer July 5, 2011, 7:01 am

    Thanks Turbo.

  • Turbomcp August 8, 2011, 8:14 am

    Hi Mike
    i have a quick question around scripting agent
    i am trying to do a very simple thing and it doesnt seem to work:)
    i want to make sure everytime a mailbox is moved(lets say from 2007 to 2010 or from 2010 to 2010)
    or every time a mailbox is enabled(when people provision users)
    single item recovery is enabled
    so i created this:

    if($succeeded)
    {

    $mailbox = $provisioningHandler.UserSpecifiedParameters["Alias"]

    Set-Mailbox $mailbox -SingleItemRecoveryEnabled $true
    }

    copied the file to the right place on all my cas servers(multirole)
    and ran this
    Enable-CmdletExtensionAgent “Scripting Agent”

    and im getting this:
    http://www.postfiles.net/images/93309527048740437467.png
    http://www.postfiles.net/images/74602109667087380777.png

    if you have any idea on what am i doing wrong i would appreciate it
    Thanks

  • Turbomcp August 8, 2011, 9:33 am

    oops the code didnt pass completly

    if($succeeded)
    {

    $mailbox = $provisioningHandler.UserSpecifiedParameters["Alias"]

    Set-Mailbox $mailbox -SingleItemRecoveryEnabled $true
    }

  • Turbomcp August 8, 2011, 9:34 am
  • Turbomcp August 8, 2011, 9:35 am

    i am after these three commands:

  • Mike Pfeiffer August 13, 2011, 6:37 pm

    Hey Turbo,

    Apologies for the late reply, I’ve been on vacation…

    So the issue with your code is that the New-MoveRequest cmdlet does not have an alias parameter. Give this a shot:

    [powershell]
    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration version="1.0">
    <Feature Name="SIR" Cmdlets="new-mailbox,enable-mailbox">

    <ApiCall Name="OnComplete">
    if($succeeded) {
    $mailbox = $provisioningHandler.UserSpecifiedParameters["Alias"]
    Set-Mailbox $mailbox -SingleItemRecoveryEnabled $true
    }
    </ApiCall>
    </Feature>

    <Feature Name="SIR" Cmdlets="new-moverequest">
    <ApiCall Name="OnComplete">
    if($succeeded) {
    [string]$id = $provisioningHandler.UserSpecifiedParameters["Identity"]
    Set-Mailbox $id -SingleItemRecoveryEnabled $true
    }
    </ApiCall>
    </Feature>
    </Configuration>
    [/powershell]

    As you can see here, setting it up this way allows you to have separate configurations depending on which cmdlets are being called. For New-Mailbox and Enable-Mailbox, you’ll still capture the alias. When New-MoveRequest is called, you can capture the value used to provide the identity of the mailbox.

  • shishir May 23, 2014, 6:56 am

    Hi Mike,

    I am trying to allow large items in all mailbox moves from one db to other within a same domain. However, after using the API as Oncomplete, move request is not including the -allowlargeitems.
    Below is the script I am using. Kindly suggest where I am missing and what API i should be using.

    Thank you very much.

    If($succeeded) {
    [string]$id = $provisioningHandler.UserSpecifiedParameters["Identity"]
    New-MoveRequest $id -AllowLargeItems $True
    }

Leave a Comment