Exchange 2010 – Automatically disable ActiveSync for mailboxes

For some reason Microsoft, in their infinite wisdom, decided to enable ActiveSync for all mailboxes by default. Not only did they make this the default, they did not provide any simple method for changing this feature. Luckily, there are little documented features called cmdlet extension agents that we can leverage to get around this limitation. The one we are going to use in this example is the “Scripting Agent.”

In order to use this, you will first need to enable the scripting agent by opening the Exchange Management Shell and executing this command:

Enable-CmdletExtensionAgent "Scripting Agent"

Next, you will need to create an xml file to be called every time a cmdlet is run on the server. There are a few APIs that can be used, but in our example we will be using the “OnComplete” API. You can take this text and use this to create the xml file:



    

         
              if($succeeded) {
                Set-CASMailbox $provisioningHandler.UserSpecifiedParameters["Alias"] -ActiveSyncEnabled $false
               }
         
     

In this example, whenever a new-mailbox or enable-mailbox command is run, the OnComplete API is called to run the command to disable the ActiveSync mailbox. You can easily modify this to run any other commands you would like whenever a mailbox is created or enabled. In our case, we also wanted to enable the single item recovery feature. Here is what that would look like:



    

         
              if($succeeded) {
                  Set-Mailbox $provisioningHandler.UserSpecifiedParameters["Alias"] -SingleItemRecoveryEnabled $true
                Set-CASMailbox $provisioningHandler.UserSpecifiedParameters["Alias"] -ActiveSyncEnabled $false
               }
         
     

Once you have the xml file created, you need to save it as ScriptingAgentConfig.xml. This file needs to be saved on all of your Exchange 2010 servers before it will work:

\V14\Bin\CmdletExtensionAgents\

In that path, you will also see a ScriptingAgentConfig.xml.sample. In this file, there are a few more sample ideas that might be beneficial for your environment.

12 thoughts on “Exchange 2010 – Automatically disable ActiveSync for mailboxes”

  1. This is a great tip, though one small gripe: you inject a load of junk into the copy-paste buffer, which means you can’t just copy the command and use it…

    1. I am not exactly sure what you mean. I tested this, and I was able to copy and paste out to notepad without issue and the code was clean. Can you give me some details on how you got the junk when trying to copy/paste?

      Thanks!
      Lucas

  2. In our environment, we have three Domain Controllers in our local AD site where our Exchange 2010 servers sit. When we attempt to use the Exchange Scripting Agent to perform an OnComplete and enable SIR, we get an error like:

    “The cmdlet extension agent with the index 5 has thrown an exception in OnComplete. The operation couldn’t be performed because object couldn’t be found on .”

    This is because the DC that the Scripting Agent is using hasn’t got the object changes replicated to it. Looking at other people experiencing the same issue, I attempted to introduce a 10 second delay into the .xml config file and this wasn’t sufficent:

    if($succeeded) {
    start-sleep -s 10
    Set-Mailbox $provisioningHandler.UserSpecifiedParameters[“Alias”] -SingleItemRecoveryEnabled $true
    }

    So in my opinion this doesn’t seem to be a real viable Enterprise option where you have multiple DCs in you AD site.

    The other thing I wanted to share is that because you need to copy the “ScriptingAgentConfig.xml” file to all you Exchange servers in your org I created a small PowerShell script that you can use to read all your servers in from a .txt file and copy a single source “ScriptingAgentConfig.xml” file to all your Exchange 2010 servers. All you need to do is modify the variables at the beginning to fit your environment. The code is:

    $SrvList = Get-Content “C:\temp\ExSrvList.txt”
    $SrcFile = “C:\temp\ScriptingAgentConfig.xml”
    $DstPath = “C$\Program Files\Microsoft\Exchange Server\V14\Bin\CmdletExtensionAgents”

    foreach ($Srv in $Srvlist) {
    Copy-Item $SrcFile -Destination \\$Srv\$DstPath -force
    }

    Hope that helps someone out there!

    1. Thanks for the comment Steven. I also noticed this happening after I wrote the article, but never had time to troubleshoot it. My hope is that there is some resolution to this in the future, as this is a very nice feature to have available to us. I never got around to trying to come up with a better way of doing it, though I do like your idea of a delay. It is unfortunate that this did not work. Have you tried a larger delay? Let me know if you come up with a resolution for this. I am interested to see how it turns out.

  3. We have come across the same issue as FinalRound. I modified the script by the following way:

    if($succeeded)
    {
    $DCs = “DC1.contoso.local”,”DC2.contoso.local”,”DC3.contoso.local”,”DC4.contoso.local”

    :find_dc foreach ($DC in $DCs)
    {
    if (@(Get-Mailbox -identity $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController $DC).count -eq 1) {break find_dc}
    }
    Set-CASMailbox $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController $DC -ActiveSyncEnabled $false
    }

    The above mentioned warning is still appearing (I don’t know why) but it always disables the ActiveSync in case of there multiple DCs too.

  4. I have a small script that I use to create mailboxes. I’m using this, because we’re in the middle of a migration, and have 20-50 users a night that we’re migrating from Groupwise to Exchange. The users already exist in AD, so I have the script look at a .csv that we’ve created, match the user, create the mailbox. I then have another script that I run to add a secondary SMTP.

    The Set-CASMailbox line, would that work, plugged into the first script, so that when it creates the mailbox, it then disables Activesync?

    1. It is worth a shot. You may need to play with it a bit to make it match up with your script, but it should get you in the right direction. Obviously, test it on a test account (or accounts) first until you get it dialed in.

  5. I got it to work. I have to put the line in the 2nd script that I run, which also adds a secondary smtp address. It fails if I run it right after enabling the mailbox, saying that user can’t be found. So there has to be a time gap between the two actions.

  6. This drove me to the brink today, finally worked it out based on this forum and a few others but this solution worked for us. (We have 4 DCs, 2 Mailbox Servers so there were some latency issues going on but they have been resolved below)
    This could be neatened up with an array for the servers and a foreach loop with a break but I spent too much time on it already, hope this help someone, since MS dropped the ball with this one.

    ———————————————————————–

    if($succeeded) {
    Start-Sleep 5
    if (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC1” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Name”]) -DomainController “DC1” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    elseif (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC2” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Name”]) -DomainController “DC2” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    elseif (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC3” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Name”]) -DomainController “DC3” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    elseif (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC4” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Name”]) -DomainController “DC4” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    }

    if($succeeded) {
    Start-Sleep 5
    if (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC1” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Alias”]).ToString() -DomainController “DC1” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    elseif (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC2” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Alias”]).ToString() -DomainController “DC2” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    elseif (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC3” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Alias”]).ToString() -DomainController “DC3” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    elseif (Get-User $provisioningHandler.UserSpecifiedParameters[“Alias”] -DomainController “DC4” -ErrorAction SilentlyContinue){
    Set-CASMailbox ($provisioningHandler.UserSpecifiedParameters[“Alias”]).ToString() -DomainController “DC4” -ActiveSyncEnabled $false -ErrorAction SilentlyContinue
    }
    }

  7. Patrick, you can do the following instead:
    do{
    $mbx = Get-Mailbox $provisioningHandler.UserSpecifiedParameters[“Alias”] -ErrorAction SilentlyContinue
    }while (!$mbx)
    Set-CASMailbox $provisioningHandler.UserSpecifiedParameters[“Alias”]).ToString() DomainController $mbx.OriginatingServer -ActiveSyncEnabled $false

    Your PowerShell session will then loop until the mailbox is found on whichever domain controller the session is connected to at the time. You can add 100 new DCs in that site and won’t have to modify your agent config file.

  8. I was working with this as well and this forum definately helped. However, I took what was here and combined several ideas and was able to get this to work by using a foreach to apply the settings to each DC one at a time. I’m also enabling Single Item Recovery, so be aware. We have 15 DCs so I also had to integrate the Sleep, but your mileage may vary. Here’s my XML that is working!

    if($succeeded) {
    start-sleep -s 20
    $mbx = $provisioningHandler.UserSpecifiedParameters[“Name”]
    $DCs = get-domaincontroller
    $dcs | foreach {if (get-user $mbx -domaincontroller $_.name -ErrorAction SilentlyContinue) {if ((get-mailbox $mbx).singleitemrecoveryenabled -eq $false) {Set-Mailbox $mbx -SingleItemRecoveryEnabled $true -DomainController $_.name -ErrorAction SilentlyContinue}}}
    $dcs | foreach {If (get-user $mbx -domaincontroller $_.name -ErrorAction SilentlyContinue) {if ((get-casmailbox $mbx).activesyncenabled -eq $true) {Set-CASMailbox $mbx -ActiveSyncEnabled $false -DomainController ($DC).originatingserver -ErrorAction SilentlyContinue}}}
    }

    In addition to this here’s a nice oneliner that will copy the XML to all your 2010 Exchange Servers….

    get-exchangeserver | where {$_.admindisplayversion -like “Version 14.3*” -and $_.name -notlike “Exchange Server you are running from” -and $_.serverrole -ne “edge”} | foreach {copy-item PATHTO\ScriptingAgentConfig.xml -Destination \\$_\PATHTO\cmdletextensionagents -force -verbose}

Leave a Reply

Your email address will not be published. Required fields are marked *