The CDOEXM Object Model
Figure 18-2 depicts the object model for CDOEXM. CDOEXM does not have many methods and properties, so the object model is easy to learn. The methods and properties make the most common administrative tasks easy to automate. To add a reference to CDOEXM in Microsoft Visual Basic, you just need to include the Microsoft CDO for Exchange Management Library (CDOEXM.DLL). You get this library wherever you install Exchange Server or the Exchange System Manager. The code can run either client-side or server-side as long as you have this object library on your machine.
Figure 18-2: The CDOEXM object model
What About ADSI?
CDOEXM and Chapter 13), because they will help you investigate and configure Active Directory settings. One word of caution, though: do not try to set Exchange settings in Active Directory yourself for complex operations such as creating storage groups. Use CDOEXM to do the work because certain properties and processes must be implemented to ensure that the system does not become unstable or is not forced into an inconsistent state.
Accessing Exchange Server Information
When you write code, you'll generally want to understand what kind of information about an Exchange server you can access programmatically. CDOEXM provides the ExchangeServer object, which has properties that return the version number, storage groups, and directory server that the Exchange server uses. Table 18-1 lists the properties of the ExchangeServer object. This object has no methods.
The sample file named EMOSample.vbp, which you can find in the book's companion content, makes this clearer. Figure 18-3 shows the user interface for the sample.

Figure 18-3: The CDOEXM sample application
Here is some of the code from the sample that uses the ExchangeServer object to determine server-specific information:
Dim oExchangeServer As New CDOEXM.ExchangeServer
Dim arrSGs() As CDOEXM.StorageGroup
Private Sub cmdConnect_Click()
On Error GoTo errHandler:
If txtExServerName.Text = " Then
MsgBox "You must enter a name in the Exchange Server name box!", _
vbCritical + vbOKOnly
Exit Sub
End If
If Right(txtExServerName.Text, 7) = "LDAP://" Then
'Remove the LDAP
txtExServerName.Text = Mid(txtExServerName.Text, 8)
End If
'Try to connect
oExchangeServer.DataSource.Open txtExServerName.Text
'Try to fill in Exchange Server info
FillInExchangeServerInfo
'Retrieve the storage groups
FillInStorageGroups
Exit Sub
errHandler:
MsgBox "There was an error in cmdConnect_Click(). Error#" _
& Err.Number & " Description:" & Err.Description, _
vbCritical + vbOKOnly
End
End Sub
Sub FillInExchangeServerInfo()
On Error GoTo errHandler
lblLogRemoval.Caption = oExchangeServer.DaysBeforeLogFileRemoval
lblDirServer.Caption = oExchangeServer.DirectoryServer
lblVersion.Caption = oExchangeServer.ExchangeVersion
lblMsgTracking.Caption = oExchangeServer.MessageTrackingEnabled
lblSubjectLogging.Caption = oExchangeServer.SubjectLoggingEnabled
lblSGCount.Caption = UBound(oExchangeServer.StorageGroups) + 1
If oExchangeServer.ServerType = cdoexmBackEnd Then
lblServerType.Caption = "Backend"
Else
lblServerType.Caption = "Frontend"
End If
Exit Sub
errHandler:
MsgBox "There was an error in FillInExchangeServerInfo. Error#" _
& Err.Number & " Description:" & Err.Description, _
vbCritical + vbOKOnly
End Sub
Working with Storage Groups
The StorageGroup object allows you to work with storage groups. From this interface, you can retrieve the log file paths for the database, figure out how many databases and what types of databases are in the storage group, and create new storage groups. Table 18-2 lists the methods and properties of the StorageGroup object.
The StorageGroup object is straightforward. The following code shows how to use this interface. The following code from the EMOSample application opens a StorageGroup object and queries for the properties of the storage group.
Sub FillInStorageGroups()
On Error GoTo errHandler
'Scroll through the array of storage groups and
'open each one into a SG object
arrEXSG = oExchangeServer.StorageGroups
Dim oTmpSG As CDOEXM.StorageGroup
ReDim arrSGs(UBound(arrEXSG))
For i = LBound(arrEXSG) To UBound(arrEXSG)
Set oTmpSG = CreateObject("CDOEXM.StorageGroup")
oTmpSG.DataSource.Open "LDAP://" & arrEXSG(i)
Set arrSGs(i) = oTmpSG
'Fill in the combo box
comboSG.AddItem oTmpSG.Name
Set oTmpSG = Nothing
Next
comboSG.ListIndex = 0
Exit Sub
errHandler:
MsgBox "There was an error in FillInStorageGroups. Error#" &
Err.Number _
& " Description:" & Err.Description, vbCritical + vbOKOnly
End Sub
Sub FillInSGInfo(iIndex)
lblCL.Caption = arrSGs(iIndex).CircularLogging
lblLFPath.Caption = arrSGs(iIndex).LogFilePath
lblMBDB.Caption = UBound(arrSGs(iIndex).MailboxStoreDBs) + 1
lblPFDB.Caption = UBound(arrSGs(iIndex).PublicStoreDBs) + 1
lblZeroDB.Caption = arrSGs(iIndex).ZeroDatabase
lblSFPath.Caption = arrSGs(iIndex).SystemFilePath
End Sub
Creating New Storage Groups
To create a new storage group in your system, all you do is figure out the right Active Directory path to pass to the SaveTo method of the DataSource object on the StorageGroup object. This is not difficult, but the path will be long because the location where Exchange Server stores its information in Active Directory is buried a couple of layers deep in the hierarchy. Here's an example path to a storage group reference in Active Directory:
CN=First Storage Group,CN=InformationStore,
CN=SERVERNAME,CN=Servers,CN=First Ad
ministrative Group,CN=Administrative Groups,
CN=First Organization,CN=Microsoft
Exchange,CN=Services,CN=Configuration,
DC=DOMAIN,DC=com
As you can see, storage groups are stored under Services, then Exchange, then your organization, then the administrative group, then the server, and finally the information store. Figure 18-4 shows this storage group object in ADSI Edit.

Figure 18-4: The location of storage group objects in Active Directory
To create a new storage group, you just create a new StorageGroup object, generate the correct Active Directory path, and add a CN=MyStorageGroup name at the beginning. The following code creates a new storage group called MyNewSG using CDOEXM:
Dim oNewSG As New CDOEXM.StorageGroup
oNewSG.DataSource.SaveTo "LDAP://server/CN=
MyNewSG,CN=InformationStore," _
& "CN=SERVERNAME,CN=Servers,
CN=First Administrative Group," _
& "CN=Administrative Groups,CN=First
Organization,CN=Microsoft " _
& "Exchange, CN=Services,CN=Configuration,
DC=DOMAIN, ,DC=com"
If you do not want to hardcode the path, you can just grab an existing storage group from the ExchangeServer object and parse it to get the path. The following code from the Training application does this:
'cut out the Storage Group name from the URL
strTemp = oCDOEXMServer.StorageGroups(0)
strTemp = Mid(strTemp, InStr(2, UCase(strTemp), "CN"))
' Build the URL to the StorageGroup
strSGURL = "LDAP://" & oCDOEXMServer.DirectoryServer & "/CN=" _
& strFolderStoreName & "," & strTemp
A blank storage group is an interesting beginning to your application. You'll see later in the chapter how to create a new mailbox or public folder databases in a storage group. You'll also learn how to create a folder tree. Finally, you'll see how to create a new mailbox.
Deleting Storage Groups
Deleting empty storage groups is no problem. You just open the storage group that you want to delete by using the Open method of the DataSource object on the StorageGroup object. If you find any databases in the storage group, delete them—you cannot delete a storage group that contains any databases. Then call the Delete method of the DataSource object, as shown in the following code:
Dim oNewSG As New CDOEXM.StorageGroup
oNewSG.DataSource.Open "LDAP://SERVER/CN=
MyNewSG,CN=InformationStore," _
& "CN=SERVERNAME,CN=Servers,CN=First Administrative Group," _
& "CN=Administrative Groups,CN=First Organization," _
& "CN=Microsoft Exchange,CN=Services,
CN=Configuration,DC=DOMAIN,DC=com"
oNewSG.DataSource.Delete
Working with Folder Trees
Before we talk about working with databases, let's briefly discuss how to work with public folders. If you don't plan to do anything with public folders, you can skip this section.To create a new public folder database, you first create a new public folder tree that the database will be associated with. By having a separate tree, you can associate different databases with different public folder trees. This gives you the flexibility to build many different hierarchies of public folders for your applications. Mailbox databases do not have this requirement.To work with folder trees, you use the FolderTree object. This interface has just three unique properties beyond the DataSource, Fields, and Name properties you saw earlier. These properties are listed in Table 18-3.
Creating a New Folder Tree
To create a new folder, you create a new FolderTree object. You set the name property on that object, and then you figure out the right Active Directory path to save your folder tree to, using the Save method of the FolderTree object's DataSource object. A typical path for a folder tree differs from that for a storage group. Here is an example path for the public folders folder tree. You would also use this path to open a folder tree.
LDAP://SERVER/
CN=Public Folders,CN=Folder Hierarchies,
CN=First Administrative Group,CN=Admini
strative Groups,CN=First Organization,
CN=Microsoft Exchange,CN=Services,CN=Conf
iguration,DC=DOMAIN,DC=com
The following code creates a new folder tree called MyNewFT. Note that you must use the SaveTo method and save to the Folder Hierarchies container as well as add a CN=MyNewFT to the path.
Dim oNewSG As New CDOEXM.FolderTree
oNewSG.Name = "MyNewFT"
oNewSG.DataSource.SaveTo "
LDAP://SERVER/CN=MyNewFT,CN=Folder Hierarchies," _
& "CN=First Administrative
Group,CN=Administrative Groups," _
& "CN=First Organization,CN=Microsoft Exchange," _
& "CN=Services,CN=Configuration
,DC=DOMAIN,DC=com"
Deleting a Folder Tree
To delete a folder tree, you open the folder tree and then call the Delete method on the DataSource object for the FolderTree object. You cannot orphan public folder databases, so you must first delete the database or disassociate the database with the folder tree before attempting to delete the folder tree. The following code deletes the folder tree we created earlier:
Dim oNewSG As New CDOEXM.FolderTree
oNewSG.DataSource.Open "LDAP://SERVER/CN=
MyNewFT,CN=Folder Hierarchies," _
& "CN=First Administrative Group
,CN=Administrative Groups," _
& "CN=First Organization,CN=Microsoft Exchange," _
& "CN=Services,CN=Configuration
,DC=DOMAIN,DC=com"
oNewSG.DataSource.Delete
Working with Public Folder Databases
You can work with two types of databases in Exchange: mailbox databases and public folder databases. We'll look at public folder databases first. When you work with public folder databases, you use the PublicStoreDB object. Table 18-4 lists the properties and methods of this interface.
Creating a New Public Folder Database
To create a new public folder database, you must have created your folder tree. You then create the Active Directory path to your public folder database. Next you create a PublicFolderDB object. Then you set the FolderTree property to the folder tree you created. Next you call the SaveTo method on the PublicFolderDB object with the Active Directory path. If you want to mount the database, you can then call the Mount method on the PublicFolderDB object. The following code shows how to create a new public folder database called MyNewPFDB. The folder tree MyNewFT must already exist.
Dim oPFDB As New CDOEXM.PublicStoreDB
oPFDB.FolderTree = "LDAP://SERVER/CN=MyNewFT,
CN=Folder Hierarchies," _
& "CN=First Administrative Group,CN=Administrative Groups," _
& "CN=First Organization,CN=Microsoft Exchange," _
& "CN=Services,CN=Configuration,DC=DOMAIN,DC=com"
oPFDB.DataSource.SaveTo "LDAP://SERVER/CN=
MyNewPFDB,CN=MyNewSG," _
& "CN=InformationStore,CN=SERVER,CN=
Servers,CN=First Administrative " _
& "Group,CN=Administrative Groups,
CN=First Organization," _
& "CN=Microsoft Exchange,CN=Services,
CN=Configuration," _
& "DC=DOMAIN,DC=microsoft,DC=com"
oPFDB.Mount
Deleting Public Folder Databases
To delete a public folder database, you first open the database by passing the Active Directory path to the database, and then you call the Open method on the DataSource object for the PublicFolderDB object. Next you call the Delete method on the DataSource object. The following code deletes the MyNewPFDB database:
Dim oPFDB As New CDOEXM.PublicStoreDB
oPFDB.DataSource.Open "LDAP://SERVER/CN=
MyNewPFDB,CN=MyNewSG," _
& "CN=InformationStore,CN=SERVER,CN=
Servers,CN=First Administrative " _
& "Group,CN=Administrative Groups,CN
=First Organization," _
& "CN=Microsoft Exchange,CN=Services,
CN=Configuration," _
& "DC=DOMAIN,DC=microsoft,DC=com"
oPFDB.DataSource.Delete
Creating Exchange Server Virtual Directories
When you create virtual directory entries in Internet Information Services (IIS) that point to Web files or folders that are stored in an Exchange database, IIS does not automatically add the proper Exchange ISAPI extension called Davex.dll to the virtual directory. This happens because you must create an Exchange virtual directory. If you just create a new virtual directory through Microsoft Internet Information Services (IIS), the virtual directory information will be stored in the IIS metabase, not in Active Directory. Exchange Server replicates information stored in Active Directory to the IIS metabase for creation of Exchange virtual directories. Therefore, the easiest way for you to create Exchange virtual directories programmatically is by creating them in Active Directory to begin with. Then you do not have to worry about creating the pointer to the Exchange Internet Server Application Programming Interface (ISAPI) yourself. If you want a graphical tool for creating Exchange virtual directories, use the Exchange System Manager.Figure 18-5 shows the Exchange System Manager interface for creating a new Exchange virtual directory.

Figure 18-5: Creating an Exchange virtual directory in the Exchange System Manager
To programmatically create the entries in Active Directory using ADSI, you must get the container called 1 under the HTTP protocols section under the Microsoft Exchange section in Active Directory. Then you must create a new entry of class msExchProtocolCfgHTTPVirtualDirectory and set its properties appropriately. The following code from the Training application does this:
Function SetNewWeb(strComputerName, strFolderName, strDomainName,_
strVirDirName, bAddTrainingApp)
On Error Resume Next
Dim iServer As New CDOEXM.ExchangeServer
Dim strFHname As String
Dim NewWeb As IADsContainer
Dim ExchFolder As Object
Dim ADCont As IADsContainer
Result = True
'Create an Exchange Virtual Directory so that OWA
'is the default view for the virtual directory
iServer.DataSource.Open strComputerName
Result = Result And GetFolderTreeURL(strComputerName, strFHname)
WriteLog "Getting Object: LDAP://" & iServer.DirectoryServer _
& "/CN=1,CN=HTTP,CN=Protocols," & _
Mid(iServer.DataSource.SourceURL, _
InStr(1, iServer.DataSource.SourceURL, "CN="))
Set ADCont = GetObject("LDAP://" & iServer.DirectoryServer _
& "/CN=1,CN=HTTP,CN=Protocols," _
& Mid(iServer.DataSource.SourceURL, _
InStr(1, iServer.DataSource.SourceURL, "CN=")))
Set NewWeb = ADCont.Create("msExchProtocolCfgHTTPVirtualDirectory", _
"CN=" & strVirDirName)
NewWeb.Put "HTTPPubGAL", CBool(0)
'NewWeb.Put "anonymousAccount", "IUSR_MSEX2K"
If bAddTrainingApp Then
strFolderName = strFolderName & "\trainingapplication"
End If
NewWeb.Put "folderPathname", CStr(strFolderName)
'Allow Write access in Access Flags so user can create folders
NewWeb.Put "msExchAccessFlags", CInt(535)
NewWeb.Put "msExchAuthenticationFlags", CInt(6)
NewWeb.Put "msExchBasicAuthenticationDomain", CStr(strDomainName)
NewWeb.Put "msExchDefaultLogonDomain", CStr(strDomainName)
NewWeb.Put "msExchDirBrowseFlags", -1073741794
NewWeb.Put "msExchLogonMethod", CInt(3)
NewWeb.Put "msExchLogType", CInt(0)
NewWeb.Put "msExchServerAutoStart", CBool(True)
NewWeb.Put "msExchServerRole", CInt(0)
NewWeb.Put "name", CStr(strVirDirName)
NewWeb.SetInfo
If Err <> 0 Then
If Err.Number <> &H80071392 Then 'If virtual dir exists
'no need to raise an error
MsgBox "Error creating virtual directory for " _
& strFolderName, vbInformation + vbOKOnly, App.Title
WriteLog "Error creating virtual directory " & strVirDirName _
& " for folder tree " & strFolderName
SetNewWeb = -1
End If
Else
SetNewWeb = 0
End If
Set iServer = Nothing
End Function
Table 18-5 lists the properties you must set (except those that are always the same value, such as msExchLogonMethod).
Any future changes you make to the virtual directory should be made through the Exchange System Manager and not through the IIS tools because those changes will not be replicated back into Active Directory. If you do make changes in the IIS tools and Exchange replicates the changes from Active Directory, the changes you make with the IIS tools might be overwritten and lost.
Working with Mailbox Databases
To work with a mailbox database, you use the MailboxStoreDB object. This object is similar in its properties to the PublicStoreDB object, and the methods are exactly the same. Table 18-6 lists the properties of this object that are different from those of the PublicStoreDB object.
Creating Mailbox Databases
To create a mailbox database, you just create a MailboxStoreDB object, create an Active Directory path to the new database, and call the SaveTo method on the DataSource object for the MailboxStoreDB object. If you want, you can then call the Mount method to mount the new database. The following code creates a new mailbox database called MyNewMailboxDB:
Dim oMB As New CDOEXM.MailboxStoreDB
oMB.DataSource.SaveTo "LDAP://SERVER/CN=MyNewMailboxDB," _
& "CN=First Storage Group,CN=InformationStore,CN=SERVER," _
& "CN=Servers,CN=First Administrative Group," _
& "CN=Administrative Groups,CN=First Organization," _
& "CN=Microsoft Exchange,CN=Services,CN
=Configuration,DC=DOMAIN,DC=com"
oMB.Mount
Deleting a Mailbox Database
Before you can delete a mailbox database, you must first be sure that there are no active mailboxes on that database. You can do this by moving all the mailboxes to a new mailbox database or by mail-disabling any of the users in the database. To delete the mailbox database, you just open the database using the Open method on the DataSource object for the MailboxStoreDB object, and then you call the Delete method.
Creating New Mailboxes
Before you create a new mailbox, you should probably create a new user in Active Directory. The easiest way to create a new user programmatically is to use ADSI. Then you can create a new mailbox for that new user.To create a new user using ADSI, you retrieve the container where you want to add the user. In the simplest case, this is the Users container. Then you create a new object in that container of the user class. You must set some properties, such as first name, last name, and account name. Then you call the SetInfo method to save the information into Active Directory.The next step is to set the MailboxStore object you created to the IADsUser object you just created for the new user. This aggregates the MailboxStore object onto the IADsUser object. Then you can call the CreateMailbox method over the MailboxStore object. You pass the Active Directory path to the mailbox database where the new mailbox will be created. You then call the SetInfo method again to make sure the changes CDOEXM has made to the IADsUser object are saved back to Active Directory. The following code does all of this:
Dim objUser As IADsUser
Dim objContainer As IADsContainer
Dim objMailbox As CDOEXM.IMailboxStore
Dim recipname As String, recip As String
recip = "CN=New User"
' get the container
Set objContainer = GetObject("LDAP://CN=users,DC=thomriznt5dom2," _
& "DC=extest,DC=microsoft,DC=com")
' create a recipient
Set objUser = objContainer.Create("User", recip)
objUser.Put "samAccountName", "newuser"
objUser.Put "sn", "User"
objUser.Put "givenName", "New"
objUser.Put "userPrincipalName", "newuser"
objUser.SetInfo
objUser.SetPassword "password"
objUser.AccountDisabled = False
Set objMailbox = objUser
'Create a mailbox for the recipient
'You cannot create a mailbox using ADSI, so use CDOEXM
objMailbox.CreateMailbox "LDAP://thomriznt52.thomriznt5dom2.extest." _
& "microsoft.com/CN=Mailbox Store (THOMRIZNT52)," _
& "CN=First Storage Group,CN=
InformationStore,CN=THOMRIZNT52," _
& "CN=Servers,CN=First Administrative Group," _
& "CN=Administrative Groups,CN=First Organization," _
& "CN=Microsoft Exchange,CN=Services,CN=Configuration," _
& "DC=thomriznt5dom2,DC=extest,DC=microsoft,DC=com"
objUser.SetInfo
Using the MailboxStore object, you can also delete and move mailboxes as well as set properties on the mailbox. Table 18-7 lists the properties and methods of the MailboxStore object.
To access a mailbox, you use both ADSI and the MailboxStore object. The following code opens a user in Active Directory and retrieves the MailboxStore-related object for that user:
Dim oMB As CDOEXM.IMailboxStore
Dim objUser As ActiveDs.IADsUser
Set objUser = GetObject("LDAP://CN=new user,CN=users," _
& "DC=thomriznt5dom2,DC=extest,DC=microsoft,DC=com")
Set oMB = objUser
The Recipient Update Service
Before any object can become truly mailbox- or mail-enabled in the system, you must run a component of Exchange called the Recipient Update Service (RUS). The RUS populates a number of properties, such as the proxy address of the new user. The RUS can take seconds or hours to run, but you configure how often it runs through the Exchange System Manager. It runs asynchronously, so it will not fire on new mailbox creation. The following code sets the RUS to start processing immediately by setting the msExchReplicateNow attribute to true. Because the RUS is asynchronous, it will not run that very second, but this code can significantly reduce the time you have to wait for the RUS to run.
strDomainName = "domain"
strDomain = "DC=domain,DC=com"
strServer = "MyServer"
'Kick off the Recipient Update Service
' >>>> ToDo: Make sure the following string
is correct by finding the RUS for
' your domain via ADSIEdit.
strRUS = "CN=Recipient Update Service (" & strDomainName _
& "),CN=Recipient Update Services," _
& "CN=Address Lists Container,CN=Microsoft," _
& "CN=Microsoft Exchange,CN=Services," _
& "CN=Configuration," & strDomain
set objRUS = GetObject("LDAP://" & strServer & "/" & strRUS)
objRUS.Put "msExchReplicateNow", True
objRUS.SetInfo
Combining CDOEXM and CDO for Exchange
One of the most common programming tasks you will perform is to combine CDOEXM with CDO for Exchange (CDOEX). Some of the objects in CDOEX expose interfaces that you can use to retrieve certain CDOEXM interfaces. For example, the Person object in CDOEX also implements the IMailboxStore interface, so if the CDOEX Person object you are working with has a mailbox, you can retrieve the IMailboxStore interface for that person by using the GetInterface method on the Person object or by forcing CDOEX to do this for you by setting a MailboxStore object equal to a CDOEX Person object. An example is shown here:
Dim oPerson As CDO.Person
Dim oMailbox As CDOEXM.IMailboxStore
Set oPerson = CreateObject("CDO.Person")
oPerson.DataSource.Open
"mailto:thomriz
@thomriznt5dom2.extest.microsoft.com"
'Set oMailbox = oPerson.GetInterface("IMailboxStore")
'Or you could coerce CDOEX to do it for you
Set oMailbox = oPerson
MsgBox oMailbox.RecipientLimit
Working with Mailbox Rights
To programmatically modify the permissions on your Exchange mailboxes, you can use the new MailboxRights property on the IExchangeMailbox interface in Exchange 2000 Service Pack 2 and later. This is a read/write property that can take an ADSI security descriptor. The following code uses this new property to set full control permissions for another user on a mailbox. You need the ADSI security DLL from the ADSI Resource Kit to run this code.
Dim SecurityDescriptor As IADsSecurityDescriptor
Dim Dacl As IADsAccessControlList
Dim newace As New AccessControlEntry
Dim objUser As CDOEXM.IExchangeMailbox
Dim objMailboxSD As IADsSecurityDescriptor
Set objUser = GetObject("LDAP://domain.com/CN=users," _
& "CN=users,DC=domain,DC=com")
Set objMailboxSD = objUser.MailboxRights
Set Dacl = objMailboxSD.DiscretionaryAcl
For Each obj In Dacl
Debug.Print "Trustee:", obj.Trustee
Debug.Print "AccessMask:", obj.AccessMask
Debug.Print "AceFlags:", obj.AceFlags
Debug.Print "AceType:", obj.AceType
Next
'AceTypes:
'ADS_ACETYPE_ACCESS_DENIED = 1
'ADS_ACETYPE_ACCESS_ALLOWED = 0
newace.AceType = ADS_ACETYPE_ACCESS_ALLOWED
'Inheritance Flags
'CONTAINER_INHERIT_ACE = 2
newace.AceFlags = 2
'Set the AccessMask from ADSI
'ADS_RIGHT_DELETE = 0x10000,
'ADS_RIGHT_READ_CONTROL = 0x20000,
'ADS_RIGHT_WRITE_DAC = 0x40000,
'ADS_RIGHT_WRITE_OWNER = 0x80000,
'ADS_RIGHT_SYNCHRONIZE = 0x100000,
'ADS_RIGHT_ACCESS_SYSTEM_SECURITY = 0x1000000,
'ADS_RIGHT_GENERIC_READ = 0x80000000,
'ADS_RIGHT_GENERIC_WRITE = 0x40000000,
'ADS_RIGHT_GENERIC_EXECUTE = 0x20000000,
'ADS_RIGHT_GENERIC_ALL = 0x10000000,
'ADS_RIGHT_DS_CREATE_CHILD = 0x1,
'ADS_RIGHT_DS_DELETE_CHILD = 0x2,
'ADS_RIGHT_ACTRL_DS_LIST = 0x4,
'ADS_RIGHT_DS_SELF = 0x8,
'ADS_RIGHT_DS_READ_PROP = 0x10,
'ADS_RIGHT_DS_WRITE_PROP = 0x20,
'ADS_RIGHT_DS_DELETE_TREE = 0x40,
'ADS_RIGHT_DS_LIST_OBJECT = 0x80,
'ADS_RIGHT_DS_CONTROL_ACCESS = 0x100
'Exchange permissions correspond to
Const ACE_MB_FULL_ACCESS = &h1
Const ACE_MB_DELETE_STORAGE = &h10000
Const ACE_MB_READ_PERMISSIONS = &h20000
Const ACE_MB_CHANGE_PERMISSIONS = &h40000
Const ACE_MB_TAKE_OWNERSHIP = &h80000
newace.AccessMask = 983041
'Set a valid user account
newace.Trustee = "domain\user"
'Add the ACE to the DACL
Dacl.AddAce newace
'Set changed DACL to Object
objMailboxSD.DiscretionaryAcl = Dacl
'Set the MailboxRights property
objUser.MailboxRights = Array(objMailboxSD)
objUser.SetInfo