If your organization uses mailbox audit logging you will probably find it useful to automatically enable it when new mailboxes are created. This avoids the potential problem of mailboxes not being enabled manually when they are created by your help desk, and avoids you having to run regular scheduled scripts to enable auditing for new mailboxes.

This is achieved using the Scripting Agent, one of the cmdlet extension agents in Exchange Server 2013 and 2010.

If you have not already enabled the Scripting Agent you can find steps here. Don’t forget to distribute a ScriptingAgentConfig.xml file to all Exchange servers first.

To enable audit logging for new mailboxes create and distribute a ScriptingAgentConfig.xml file containing the following:

scriptingagentconfig

The important part is these lines, that will fire if the New-Mailbox or Enable-Mailbox cmdlet completes successfully. You can see that all it is really doing is running Set-Mailbox to enable auditing, just as you would manually in the Exchange management shell.

  If ($succeeded)
  {
  	$Alias= $provisioningHandler.UserSpecifiedParameters["Alias"]
	$mailbox = Get-Mailbox $Alias
	Set-Mailbox $mailbox -AuditEnabled:$true
  }

This config uses the Alias attribute of the mailbox, which is populated when a new mailbox is created.

exchange-2013-mailbox-audit-logging-01

When the mailbox creation process has completed you can verify that auditing has been enabled.

[PS] C:\>Get-Mailbox Alannah.Shaw | fl auditenabled

AuditEnabled : True

And that is basically it. As you can see using the Scripting Agent to automate this task is quite simple, yet powerful, and saves you a lot of administrative burden.

About the Author

Paul Cunningham

Paul is a former Microsoft MVP for Office Apps and Services. He works as a consultant, writer, and trainer specializing in Office 365 and Exchange Server. Paul no longer writes for Practical365.com.

Comments

  1. Ziya Piriyev

    The cmdlet extension agent with the index 5 has thrown an exception in OnComplete(). The exception is: Microsoft.Exchange.Provisioning.ProvisioningException: ScriptingAgent: Exception thrown while invoking scriptlet for OnComplete API: Exception calling “Send” with “1” argument(s): “Transaction failed. The server response was: 5.6.0 Invalid message content”. —> System.Management.Automation.MethodInvocationException: Exception calling “Send” with “1” argument(s): “Transaction failed. The server response was: 5.6.0 Invalid message content” —> System.Net.Mail.SmtpException: Transaction failed. The server response was: 5.6.0 Invalid message content at System.Net.Mail.DataStopCommand.CheckResponse(SmtpStatusCode statusCode, String serverResponse) at System.Net.Mail.DataStopCommand.Send(SmtpConnection conn) at System.Net.ClosableStream.Close() at System.Net.Mail.SmtpClient.Send(MailMessage message) at CallSite.Target(Closure , CallSite , Object , Object ) — End of inner exception stack trace — at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo) at CallSite.Target(Closure , CallSite , Object , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at

  2. Yuriy Samorodov

    Please note that this method requires engineer specify Alias when creating a mailbox. Otherwise scriptlet execution is going to fail.
    To overcome this we have to implement user parameter check before running get-mailbox:

    if ($provisioningHandler.UserSpecifiedParameters[“Identity”] -ne $null) {
    $userParameter = $provisioningHandler.UserSpecifiedParameters[“Identity”]
    }
    elseif ($provisioningHandler.UserSpecifiedParameters[“Name”] -ne $null) {
    $userParameter = $provisioningHandler.UserSpecifiedParameters[“Name”]
    }
    else {
    $userParameter = $provisioningHandler.UserSpecifiedParameters[“Alias”]
    }
    $userParameter = $userParameter.ToString()

  3. Raj

    Is this available for Office 365, otherwise which way this automation can be achieved ?

    1. Paul Cunningham

      The scripting agent is not, but you can add the steps into your normal PowerShell script/process that you use for provisioning accounts. If you don’t have a PowerShell script driving that task, then I recommend you create one.

  4. Dotan

    Is there a way to do this with an api? or is powershell the only way?
    Or even just enabling auditing on a mailbox. I don’t mind running it whenever a new mailbox is created.

  5. kjstech

    Getting this message after creating a new user with this scripting agent file in place and set to true.

    The cmdlet extension agent with the index 5 has thrown an exception in OnComplete(). The exception is: Microsoft.Exchange.Provisioning.ProvisioningException: ScriptingAgent: Exception thrown while invoking scriptlet for OnComplete API: Cannot bind argument to parameter ‘Identity’ because it is null.. —> System.Management.Automation.ParameterBindingValidationException: Cannot bind argument to parameter ‘Identity’ because it is null. at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input, Hashtable errorResults, Boolean enumerate) at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput, CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][] commandRedirections, FunctionContext funcContext) at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame) at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame) — End of inner exception stack trace — at Microsoft.Exchange.ProvisioningAgent.ScriptingAgentHandler.OnComplete(Boolean succeeded, Exception e) at Microsoft.Exchange.Provisioning.ProvisioningLayer.OnCompleteImpl(Task task, Boolean succeeded, Exception exception)

    1. Klaus

      Hello,

      I had the same problem and that’s why a opened a call at Microsoft.

      The following solution works for me.

      $alias = [string]$provisioningHandler.UserSpecifiedParameters[“Identity”]

      1. Matt D

        Thanks for the information Klaus. We’ve begun having this exact issue here recently. So, is it just as simple as putting this line in the ScriptingAgentConfig.xml file?

        $alias = [string]$provisioningHandler.UserSpecifiedParameters[“Identity”]

        1. Klaus

          Hello,

          Yes it works for me with some Start-Sleep.
          See the complete script:

          (the last set-mailbox is to switch off of the external out of Office message tabs in Outlook and OWA.)

          if($succeeded) {
          Start-sleep 30
          Set-ADServerSettings -ViewEntireForest $true
          $Alias = [string]$provisioningHandler.UserSpecifiedParameters[“Identity”]

          $AccessRights = “LimitedDetails”
          $Mailbox = Get-Mailbox -Identity $Alias -DomainController:$ReadOnlyIConfigurable.OriginatingServer
          $calendar = (($mailbox.SamAccountName)+ “:” + (Get-MailboxFolderStatistics -Identity $Mailbox.SamAccountName -FolderScope Calendar | Select-Object -First 1).Name)

          Set-MailboxFolderPermission -User “Default” -AccessRights $AccessRights -Identity $calendar

          Start-sleep 10
          Set-Mailbox $Mailbox -ExternalOofOptions InternalOnly
          }

  6. Jeremy Bradshaw

    Woops, forgot to subscribe to replies.

  7. Jeremy Bradshaw

    Hi Paul,

    I’m hoping you will take a stab at solving the multiple DC’s scenario where the scripting agent fails to find the newly enabled or created mailbox. There are several ways demonstrated to accomplish finding the necessary DC where the new object exists around various forums but in my testing none of them work.

    I wonder if you can offer some advice?

    Thanks!

    1. Paul Cunningham

      The most reliable method I found was to run regular schedule tasks to check and set the attributes I needed, instead of using the scripting agent.

      The scripting agent works fine for many environments, others maybe not so much.

      1. Jeremy Bradshaw

        Sounds good. At least there is that. Too bad my environment is one of those ones. But I will do a premier support case report back with any magic bullets.

        1. Jeremy Bradshaw

          I have finally solved this! I actually opened a Sev. C case with Microsoft but solved it via trial in error while waiting for a contact back from them. In order for the $ReadOnlyIConfigurable parameter/variable to be available, in order to get the OriginatingServer value, you MUST include the call to the Validate API inside the SAME feature where the OnComplete API is called. Example (which is working 100% with Exchange 2010 SP3 Rollup 5:

          …..<—: THIS IS VITAL
          !!!NOT MANY CMDLETS WILL WORK IN HERE IF YOU PLAN ON TESTING!!!
          …………………………………<—: THIS IS VITAL

          If ($succeeded)
          {

          if (!($provisioningHandler.UserSpecifiedParameters.Archive -eq $true))
          {

          $Alias= $provisioningHandler.UserSpecifiedParameters[“Alias”]

          $Mailbox = Get-Mailbox -Identity “$($Alias)” -DomainController:$ReadOnlyIConfigurable.OriginatingServer

          if ($Mailbox)
          {

          Set-CASMailbox -Identity:$Mailbox -ActiveSyncEnabled:$false -PopEnabled:$false -ImapEnabled:$false -DomainController:$ReadOnlyIConfigurable.OriginatingServer

          }
          }
          }

  8. Rocky

    Hi Paul,

    I left out the actual line from the sample xml file:

    #parameter list:
    #param([ProvisioningHandler]$provisioningHandler, [IConfigurable]$readOnlyIConfigurable)

    $newObjectGuid = $readOnlyIConfigurable.Guid.ToString();

    #parameter list:
    #param([ProvisioningHandler]$provisioningHandler, [bool]$succeeded, [Exception]$exception)

    if($succeeded)
    {
    WriteToSQL($newObjectGuid);
    }

  9. Rocky

    Hi Paul,

    I’m trying to enable automatic auditing of mailboxes upon creation and I read your other posts on scripting agent config.xml. In the install directory of one of my Exchange 2013 SP1 boxes, I found the “scriptingagentconfig.xml.sample” file and renamed it to “scriptingagentconfig.xml”. I see that there is a section for auditing – “cmdlets=”new-mailbox””:

    #parameter list:
    #param([ProvisioningHandler]$provisioningHandler, [IConfigurable]$readOnlyIConfigurable)

    $newObjectGuid = $readOnlyIConfigurable.Guid.ToString();

    #parameter list:
    #param([ProvisioningHandler]$provisioningHandler, [bool]$succeeded, [Exception]$exception)

    if($succeeded)
    {
    WriteToSQL($newObjectGuid);
    }

    Does this mean I just need to push this “xml” file to all my Exchange 2013 SP1 boxes and run “Enable-cmdletextensionagent”

  10. shishir

    Hi Paul,
    I am trying to allow large items for all mailbox moves in a same domain through scripting agent.I am using the API “OnComplete” here. I am not sure whether I am right or I should be using different API.I am trying to use following script but it is not including the -allowlargeitems parameter on the completion of move.

    If($succeeded) {
    [string]$id = $provisioningHandler.UserSpecifiedParameters[“Identity”]

    New-MoveRequest $id -AllowLargeItems $true
    }

    Kindly suggest how to make this possible.Please correct me if I am missing any parameter or if I am makingany mistake in the above script.
    Thank you.

  11. Tim West

    Hi Paul,
    I am trying to implement the ScriptingAgentConfig.xml and I get an error when I enable the cmdlet extension or change the send as properties of a mailbox. Would you mind advising please if you have a second?

    For what it’s worth XMLSpy errors on validation with: “Unable to locate a reference to a supported schema type (DTD, W3C Schema) within this document instance.”

    Exchange 2013 CU3:
    Name : SERVER1
    ServerRole : Mailbox, ClientAccess
    Edition : Enterprise
    AdminDisplayVersion : Version 15.0 (Build 775.38)

    Path: …Exchange ServerV15BinCmdletExtensionAgentsScriptingAgentConfig.xml:

    If ($succeeded)
    {
    $Alias= $provisioningHandler.UserSpecifiedParameters [“Alias”]
    $mailbox = Get-Mailbox $Alias
    Set-Mailbox $mailbox -AuditEnabled:$true
    }

  12. Hasan Rahman

    Hi Paul, great post. Is it necessary to specify a dc in the script? I have made a script which sets mapiblockoutlookrpchttp each time enable-mailbox is used. This works great on 2 servers but on 2 other servers I get an error saying alias not found on the dc. If I use start-sleep for something above 15 seconds it works on all servers. I guess it is because there is an ad latency somewhere?

Leave a Reply