HOWTO: CDOEXM: Add Associated External Account permission to existing mailbox

If you ever tried to modify the msExchMailboxSecurityDescriptor attribute directory then you must be aware that this attribute exists on the user object in the Active Directory and stores a partial copy of the user's mailbox security descriptor. This attribute is not back linked to the user's mailbox security descriptor.

If msExchMailboxSecurityDescriptor is modified directly, the actual mailbox security descriptor on the user's mailbox in the information store is not updated if the mailbox is already created. You can modify this attribute before mailbox is created and those permissions will retain even after the mailbox is created.

To be able to modify this attribute for existing mailboxes you need to use CDOEXM and run the script on Exchange 2003 server itself. If the user's mailbox security descriptor is modified from ADUnC or as demonstrated in the code in this article, msExchMailboxSecurityDescriptor is automatically updated to reflect these changes

Here is the code that I have used in a recent support case to add Associated External Account (AEA) permission. AEA permission require you to also assign Full Mailbox permission. This script will add both ACE to the mailbox.

 Option Explicit

'Constant variable declarations
CONST ADS_ACETYPE_ACCESS_ALLOWED = 0
CONST ADS_ACETYPE_ACCESS_DENIED = 1
CONST ADS_ACETYPE_SYSTEM_AUDIT = 2
CONST ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 5
CONST ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6
CONST ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = 7
CONST ADS_ACETYPE_SYSTEM_ALARM_OBJECT = 8 
CONST ADS_RIGHT_DS_CREATE_CHILD = 1
CONST ADS_ACEFLAG_INHERIT_ACE = 2

'Used for Associate external account
Const E2K_MB_FULL_MB_ACCESS = &H1
Const E2K_MB_SEND_AS = &H2
Const E2K_MB_EXTERNAL_ACCOUNT = &H4
Const E2K_MB_READ_PERMISSIONS = &H20000
Const E2K_MB_TAKE_OWNERSHIP = &H80000


' ********************************************************************
' Change these variables according to your environment.

Const sUserADsPath = "LDAP://SERVER/CN=USER,CN=Users,DC=ExchangeLab,DC=com"
Const sTrustee = "NT AUTHORITY\SELF"
' ********************************************************************


Dim objUser
Dim oSecurityDescriptor 
Dim dacl 
Dim ace 

Dim bFound 

bFound = False
'Get directory user object.
Set objUser = GetObject(sUserADsPath)

' Get the Mailbox security descriptor (SD).
Set oSecurityDescriptor = objUser.MailboxRights

' Extract the Discretionary Access Control List (DACL) using the IADsSecurityDescriptor.
' Interface.
Set dacl = oSecurityDescriptor.DiscretionaryAcl
Set ace = CreateObject("AccessControlEntry")

AddAce dacl, sTrustee, E2K_MB_FULL_MB_ACCESS Or E2K_MB_EXTERNAL_ACCOUNT, ADS_ACETYPE_ACCESS_ALLOWED, ADS_ACEFLAG_INHERIT_ACE, 0, 0, 0


' Add the modified DACL to the security descriptor.
oSecurityDescriptor.DiscretionaryAcl = dacl

' Save new SD onto the user.
objUser.MailboxRights = oSecurityDescriptor

' Commit changes from the property cache to the information store.
objUser.SetInfo

wscript.echo "Done modifying the mailboxsecurity descriptor"



'********************************************************************
'*
'* Function AddAce(dacl, TrusteeName, gAccessMask, gAceType,
'*          gAceFlags, gFlags, gObjectType, gInheritedObjectType)
'*
'* Purpose: Adds an ACE to a DACL
'* Input:   dacl            Object's Discretionary Access Control List
'*          TrusteeName     SID or Name of the trustee user account
'*          gAccessMask     Access Permissions
'*          gAceType        ACE Types
'*          gAceFlags       Inherit ACEs from the owner of the ACL
'*          gFlags          ACE has an object type or inherited object type
'*          gObjectType     Used for Extended Rights
'*          gInheritedObjectType
'*
'* Output:  Object - New DACL with the ACE added
'*
'********************************************************************

Function AddAce(dacl, TrusteeName, gAccessMask, gAceType, gAceFlags, gFlags, gObjectType, gInheritedObjectType)
    Dim Ace1
    ' Create a new ACE object.
    Set Ace1 = CreateObject("AccessControlEntry")
    Ace1.AccessMask = gAccessMask
    Ace1.AceType = gAceType
    Ace1.AceFlags = gAceFlags
    Ace1.Flags = gFlags
    Ace1.Trustee = TrusteeName
    'See whether ObjectType must be set
    If CStr(gObjectType) <> "0" Then
       Ace1.ObjectType = gObjectType
    End If

    'See whether InheritedObjectType must be set.
    If CStr(gInheritedObjectType) <> "0" Then
        Ace1.InheritedObjectType = gInheritedObjectType
    End If

    dacl.AddAce Ace1



    ' Destroy objects.
    Set Ace1 = Nothing
End Function

Known Limitations: This script will throw an error if the same permissions (Associated External Mailbox) already exist on the mailbox.