Programming Microsoft Outlook and Microsoft Exchange 2003, Third Edition [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming Microsoft Outlook and Microsoft Exchange 2003, Third Edition [Electronic resources] - نسخه متنی

Thomas Rizzo

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید

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.










































Table 18-1: Properties of the ExchangeServer Object

Property


Description


DataSource


Retrieves the IDataSource2 interface. From this interface, you can open a connection to an Exchange server by passing the name of the server to the Open method of the DataSource object.


DaysBeforeLogFileRemoval


Specifies the number of days before Exchange Server log files will be removed from the server. Please refer to the Exchange Server documentation for the types of log files that Exchange Server uses.


DirectoryServer


Returns the fully qualified domain name (FQDN) of the Active Directory domain controller that the Exchange server communicates with. This is a read-only property.


ExchangeVersion


Returns the version of Exchange Server that is running. An example of output from this property is Version 6.5 (Build 6944) for the Release to Manufacturer (RTM) version of Exchange 2003.


Fields


Returns the Fields collection. The fields you get back are mostly fields from Active Directory such as heuristics, whenCreated, whenChanged, and objectClass.


MessageTrackingEnabled


A Boolean that specifies whether message tracking is enabled on the Exchange server. For more information on message tracking, refer to the Exchange Server documentation.


Name


Returns the name of the Exchange server. This is a read-only property.


ServerType


Returns a CDOEXMServerType enumeration. There are only two types: CDOEXMBackEnd and CDOEXMFrontEnd. Front-End (FE) and Back-End (BE) Exchange servers are discussed in detail in the Exchange documentation.


StorageGroups


Returns an array that lists the Active Directory path to all storage groups on the server. You can then use these Active Directory paths with the StorageGroup object to open a specific storage group.


SubjectLogging


A Boolean that specifies whether subject logging is enabled.


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.













































Table 18-2: Methods and Properties of the StorageGroup Object

Method or Property


Description


CircularLogging


A Boolean property that specifies whether new log entries will overwrite the oldest log entries in the file.


DataSource


Returns the IDataSource2 interface. From this interface, you can use the Open method to open a storage group by passing the Active Directory path to the storage group, or you can use the SaveTo method to create a new storage group. You can also use the Delete method to delete a storage group.


Fields


Returns the ADO Fields collection for the storage group. Most of the interesting properties are already directly exposed by the StorageGroup object, so the Fields collection is not that interesting.


LogFilePath


A string that specifies where the database transaction log files are stored.


MailboxStoreDBs


An array of strings that contains the Active Directory path to any mailbox databases in the storage group. You can then use the Open method of the DataSource property on the MailboxStoreDB object to open the mailbox database.


Name


Specifies the name of the storage group.


PublicStoreDBs


An array of strings that contains the Active Directory path to any public folder databases in the storage group. You can then use the Open method of the DataSource property on the PublicStoreDB object to open the mailbox database.


SystemFilePath


A string that specifies where database system files are stored.


Zerodatabase


A Boolean that specifies whether deleted database pages will be overwritten with zeroes when you back up the server.


MoveLogFiles


A method that takes a string that specifies the new path to move the transaction log files to.


MoveSystemFiles


A method that takes a string that specifies the new path to move the database system files to.


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.





















Table 18-3: Properties of the FolderTree Interface

Property


Description


RootFolderURL


Specifies the URL to the root folder in the tree. Do not expect this to be the URL to use for your applications. For example, the public folders RootFolderURL value is http://SERVER/ExAdmin/ domain.com/Public%20Folders


StoreDBs


A string array of Active Directory paths of other public store databases that contain replicas of this folder tree.


TreeType


An enumeration that specifies the type of folder tree. The three possible values are cdoexmGeneralPurpose (a non-MAPI public folder tree), cdoexmMAPI, and cdoexmNNTPOnly.


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.































































Table 18-4: Properties and Methods of the PublicStoreDB Object

Element


Description


DataSource


Returns the IDataSource2 interface. From this interface, you can use the Open method to open a public folder database by passing the Active Directory path to the database or use the SaveTo method to create a new public folder database. You can also use the Delete method to delete the public folder database.


DaysBeforeGarbageCollection


Returns or sets the number of days before deleted items in the database will be permanently deleted. See the Exchange Server documentation for more information on garbage collection.


DaysBeforeItemExpiration


Returns or sets the number of days before items and folders will expire in the database.


DBPath


A read-only property that returns the file path to the database file. This file will end with the .edb extension.


Enabled


A Boolean property that specifies whether the database will be mounted at startup. A value of True means that the database will be mounted.


Fields


Returns the ADO Fields collection for the object.


FolderTree


A string property that returns or sets the Active Directory path to the folder tree associated with the public folder database.


GarbageCollectOnlyAfterBackup


A Boolean that specifies whether items that have not been backed up will be permanently deleted from the database. A value of True means that items cannot be deleted until they are backed up.


HardLimit


A property that specifies the size in kilobytes beyond which posting will be disabled.


ItemSizeLimit


A property that specifies the maximum allowable size (in kilobytes) of an item in the database.


Name


Specifies the name of the database.


SLVPath


A read-only string property that returns the path to the streaming file database. The streaming file database contains data stored in its Internet content format. For more information about the database architecture of Exchange Server, see the product documentation.


Status


A read-only property that returns a CDOEXMStoreDBStatus enumeration value that specifies whether the database is mounted. The enumeration contains four values: cdoexmOnline, cdoexmOffline, cdoexmMounting, and cdoexmDismounting.


StoreQuota


A property that specifies or returns the maximum size (in kilobytes) of the database.


Dismount


A method that dismounts the database. It takes an optional property that specifies the amount of time in seconds that the system will attempt to dismount the database.


Mount


A method that mounts the database. It takes an optional property that specifies the amount of time in seconds that the system will attempt to mount the database.


MoveDataFiles


A method that moves the data files for the database. It takes three parameters. The first is the new path for the database file. The second is the new path for the streaming files. The final parameter is optional and is a flags parameter reserved for future use.


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).

































Table 18-5: Required Properties for Exchange Virtual Directories

Property


Description


anonymousAccount


Specifies the Windows account that IIS will use to authenticate users when they are accessing the Web site anonymously.


folderPathname


Specifies the relative folder path. For example, a folder path to a folder called Helpdesk under Public Folders would be specified as Public Folders\Helpdesk.


msExchAccessFlags


An integer that specifies the access flag for the virtual directory. You can combine the following values to get different levels of access:

Read access (1)

Write access (2)

Script source access (16)

Execute permissions for scripts (512)

Execute permissions for scripts and executables (516)

For example, if you want read access to your virtual directory and you want to execute scripts, you can specify the value 513 for this property.


msExchAuthenticationFlags


Specifies whether Anonymous, Basic, and/or Integrated Windows Authentication is allowed for the virtual directory. These are the values:

Anonymous (1)

Basic (2)

Integrated Windows Authentication (4)

Digest Authentication (16)

For example, if you want all authentication methods, you can pass 7 as the value for this property. Remember, though, that IIS restricts machine hops when you use NTLM authentication, and this can affect what security mode you use in an FE/BE configuration. You should use Basic Authentication over SSL in that scenario.


msExchBasicAuthenticationDomain


If you're using Basic Authentication, you can specify the default Windows domain to try to validate the username and password against. If you do not specify this property, IIS will use the default domain on the server on which IIS is running.


msExchDefaultLogonDomain


Specifies the default domain to try Exchange Server authentication against. This property is used when a client does not specify a domain to log onto in the browser logon box.


msExchDirBrowseFlags


If you want to enable directory browsing, which allows users to look at the items in your folders pointed to by the IIS virtual directory, you must specify –1073741794 for this property. If you want to disallow directory browsing, you must specify 1073741854.


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.





















Table 18-6: Properties of the MailboxStoreDB Object

Property


Description


OfflineAddressList


A string that specifies an Active Directory path to the offline address list for mailboxes stored in this database.


OverQuotaLimit


Specifies the size limit (in kilobytes) for mailboxes in this database. If this limit is exceeded, the user cannot send mail.


PublicStoreDB


A string that specifies the Active Directory path to the default public folder database for this mailbox.


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.



















































Table 18-7: Properties and Methods of the MailboxStore Object

Property


Description


DaysBeforeGarbageCollection


Specifies the number of days that deleted mail will be retained before it is permanently deleted.


Delegates


Contains an array of string values that are the URLs of the other users who have access to this mailbox.


EnableStoreDefaults


A Boolean that specifies whether to use the database defaults for storage limits. A value of True means that the default limits will be used.


GarbageCollectOnlyAfterBackup


Specifies whether items can be permanently deleted only after the mailbox has been backed up.


HardLimit


Specifies the size (in kilobytes) beyond which the user can no longer send and receive mail.


HomeMDB


Specifies the Active Directory path to the mailbox store for the recipient.


OverQuotaLimit


Specifies a size limit (in kilobytes) of a mailbox. If this limit is exceeded, sending mail is disabled.


OverrideStoreGarbageCollection


Specifies whether this mailbox should use the garbage collection properties set on this mailbox or the properties set on the database.


RecipientLimit


An integer that specifies the maximum number of recipients this user can send a single e-mail to.


StoreQuota


Specifies the maximum size (in kilobytes) of the mailbox.


CreateMailbox


Takes the path to the mailbox database where you will create a new mailbox.


DeleteMailbox


Deletes the mailbox.


MoveMailbox


Moves the mailbox to a new mailbox database. You must specify as a parameter the Active Directory path of the new mailbox database where you want to move the mailbox.


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

/ 227