Background
In Exchange, moving a mailbox entails:
- Modifying attributes on the user object in Active Directory
that specify the user's mailbox store.
- Moving the physical mailbox of the user to the new store
location.
The CDOEXM::IMailboxStore interface is an interface that
enables programmatically performing mailbox-related tasks like creating
mailboxes for users, deleting mailboxes for users, and moving users' mailboxes
across mailbox stores in a Windows 2000 domain or a Windows 2003 domain. The
CDOEXM interfaces can be derived from either CDO interfaces or ADSI interfaces.
For additional
information about the advantages and disadvantages of using each of the
following approaches, click the following article number to view the article in
the Microsoft Knowledge Base:
297390�
INFO: Comparing Use of ADSI and CDO to Access CDOEXM Recipient-Related Methods
The IMailboxStore method,
MoveMailbox, performs two sets of tasks as follows:
- Directory-related tasks on the user object
- Updates the homeMTA attribute.
- Updates the store's distinguished name on the homeMDB attribute.
- Deletes the target e-mail address for the user object
stored in the targetAddress attribute. This will be updated by the Recipient Update Service
(RUS) when it runs against this user.
- Store-related tasks
- Copies the user's mailbox from the current store on an
Exchange server to a new store location specified on the same or another
Exchange server.
- Transfers the messages and content from the user's old
mailbox to the user's new mailbox.
- Marks the user's old mailbox to be deleted. The actual
mailbox is actually "tombstoned" (marked as deleted) once the Cleanup Agent is
run against the store. This is indicated by a red cross in front of the mailbox
when viewed from the Exchange System Manager.
If the user object has been set to be mailbox-enabled but the
RUS hasn't run against the user object yet, then
MoveMailbox forces the RUS to run against this user. Also, if this user's
physical mailbox is still nonexistent in the information store (if this mailbox
has not been accessed yet), this mailbox is created in the new mailbox store
after
MoveMailbox is called on the user.
Although the CDOEXM interfaces
can be derived either from ADSI or CDO interfaces, they cannot be directly used
to bind to an object in the Active Directory. The CDOEXM interfaces are
available in Cdoexm.dll, which is installed along with the Microsoft Exchange
System Management Tools. Do not manually register this file into the registry.
You can install the Exchange System Management component by running Exchange
Server Setup from the Exchange Server CD.
Using ADSI
This sample requires Adsiid.lib and Activeds.lib for the ADSI
interfaces, which can be found under the Libs folder in a Platform SDK
installation. The Platform SDK can be downloaded from the following Microsoft
Web site:
This sample, in addition to the ADSI libraries, requires
Cdoexm.dll, which is installed along with the Microsoft Exchange System
Management Tools. Therefore, it must be run on a Windows 2000 Server, a Windows
2000 Advanced Server member server, or a Windows Server 2003 server, in the
same domain as the Exchange server, that has at least the MS Exchange System
Management Tools component installed.
To build this sample, include
the Adsiid.lib and Activeds.lib libraries in the
Object/Library modules textbox, which is accessible from the
Project menu by pointing to
Settings and then clicking
Link.
Sample Code
#include "stdio.h"
#include "activeds.h"
//Importing the libraries required to use CDOEXM
//TODO: change the file path below to point to the file
#import <G:\Program Files\Exchsvr\BIN\cdoexm.dll> no_namespace raw_interfaces_only exclude("IDataSource2")
int main(void)
{
// Declare variables
HRESULT hr;
LPWSTR strUserLDAPPath;
LPWSTR strMailboxStore;
IADsUser *pUser = NULL;
IMailboxStore *pMailbox = NULL;
//TODO: change the string below to the LDAP path for the user to
//perform the MoveMailbox task on
strUserLDAPPath = L"LDAP://domain/CN=user1,OU=MyOU,DC=domain,DC=com";
//TODO: Change the string below to the Distinguished Name or LDAP path
// for the new mailbox store to move the user's mailbox to
strMailboxStore = L"CN=2nd Mailbox Store,CN=First Storage Group,CN=InformationStore,CN=EX2K,CN=Servers,CN=SITE1,CN=Administrative Groups,CN=Microsoft,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=dom,DC=com";
//Initialize COM
hr = CoInitialize(NULL);
if (FAILED(hr)) {
wprintf(L"Failed to CoInitialize: 0x%x\n", hr);
return hr;
}
//Bind to the existing mailbox enabled user using ADSI
hr = ADsGetObject(strUserLDAPPath, IID_IADsUser, (void**)&pUser);
if (FAILED(hr)) {
wprintf(L"Failed to get IADsUser: 0x%x\n", hr);
pUser->Release();
CoUninitialize();
return hr;
}
//Query for the IMailboxStore Interface using the IADsUser object
hr = pUser->QueryInterface(__uuidof(IMailboxStore), (void**)&pMailbox);
if (!SUCCEEDED(hr))
{
wprintf(L"QueryInterface of IMailboxStore failed!\n");
pUser->Release();
pMailbox->Release();
CoUninitialize();
return hr;
}
//Move the Mailbox
hr = pMailbox->MoveMailbox(strMailboxStore);
if (!SUCCEEDED(hr))
{
wprintf(L"MoveMailbox failed!\n");
pUser->Release();
pMailbox->Release();
CoUninitialize();
return hr;
}
//Apply changes made to the cache back onto the user object in the Active Directory
hr = pUser->SetInfo();
if (!SUCCEEDED(hr))
{
wprintf(L"SetInfo failed!\n");
pUser->Release();
pMailbox->Release();
CoUninitialize();
return hr;
}
//Cleanup and uninitialize COM
pUser->Release();
pMailbox->Release();
pUser = NULL;
pMailbox = NULL;
CoUninitialize();
return 0;
}
Using CDO
This sample requires Cdoex.dll for the IPerson interface on the
CDO.Person object. This .dll file is available only on an Exchange server. It
also requires Cdoexm.dll for the IMailboxStore interface on the CDOEXM object.
This .dll is available on Exchange servers as well. Therefore, this code can
only be run from an Exchange server. Do not manually attempt to register either
of these files into the registry to work around this limitation.
Sample Code
#include "stdio.h"
// Importing the libraries required to use CDOEXM
//TODO: change the path to the files location
#import <c:\program files\common files\system\ado\msado15.dll> no_namespace raw_interfaces_only
#import <C:\Program Files\Common Files\Microsoft Shared\CDO\cdoex.dll> no_namespace raw_interfaces_only rename("Folder","CDOEXFolder")
#import <G:\Program Files\Exchsvr\BIN\cdoexm.dll> no_namespace raw_interfaces_only
int main(void)
{
// Declare variables
HRESULT hr;
LPWSTR strUserLDAPPath;
LPWSTR strMailboxStore;
IPerson* pUser = NULL;
IDataSource* pDataSource = NULL;
IMailboxStore *pMailbox = NULL;
//TODO: Change this string to the LDAP path for the user to perform
//the MoveMailbox task on
strUserLDAPPath = L"LDAP://domain/CN=user2,OU=MyOU,DC=domain,DC=com";
//TODO: Change this string to the Distinguished Name or LDAP path for
// the new mailbox store to move the user's mailbox to
strMailboxStore = L"CN=2nd Mailbox Store,CN=First Storage Group,CN=InformationStore,CN=EX2K,CN=Servers,CN=SITE1,CN=Administrative Groups,CN=Microsoft,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=com";
//Initialize COM
hr = CoInitialize(NULL);
if (FAILED(hr)) {
wprintf(L"Failed to CoInitialize: 0x%x\n", hr);
return hr;
}
//Create Instance of IPerson interface
hr = CoCreateInstance( __uuidof(Person),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IPerson),
(void**) &pUser
);
if (FAILED(hr)) {
wprintf(L"Failed to Create Instance of IPerson object: 0x%x\n", hr);
pUser->Release();
pUser = NULL;
CoUninitialize();
return hr;
}
hr = pUser->get_DataSource(&pDataSource);
if (FAILED(hr)) {
wprintf(L"Failed to get_DataSource: 0x%x\n", hr);
pUser->Release();
pDataSource->Release();
pUser = NULL;
pDataSource = NULL;
CoUninitialize();
return hr;
}
//Bind to the existing mailbox enabled user
hr = pDataSource->Open(strUserLDAPPath,
NULL,
adModeReadWrite,
adFailIfNotExists,
adOpenSource,
L"",
L"");
if (FAILED(hr)) {
wprintf(L"Failed to bind to LDAP path: 0x%x\n", hr);
pUser->Release();
pDataSource->Release();
pUser = NULL;
pDataSource = NULL;
CoUninitialize();
return hr;
}
//Query for the IMailboxStore Interface using the IADsUser object
hr = pUser->QueryInterface(__uuidof(IMailboxStore), (void**)&pMailbox);
if (!SUCCEEDED(hr))
{
wprintf(L"QueryInterface of IMailboxStore failed!\n");
pUser->Release();
pDataSource->Release();
pMailbox->Release();
pUser = NULL;
pMailbox = NULL;
pDataSource = NULL;
CoUninitialize();
return hr;
}
//Move Mailbox
hr = pMailbox->MoveMailbox(strMailboxStore);
if (!SUCCEEDED(hr))
{
wprintf(L"MoveMailbox failed!\n");
pUser->Release();
pMailbox->Release();
pDataSource->Release();
pUser = NULL;
pMailbox = NULL;
pDataSource = NULL;
CoUninitialize();
return hr;
}
//Update changes made by CDOEXM by Saving DataSource
hr = pDataSource->Save();
if (!SUCCEEDED(hr))
{
wprintf(L"Failed to Save DataSource!\n");
pUser->Release();
pMailbox->Release();
pDataSource->Release();
pUser = NULL;
pMailbox = NULL;
pDataSource = NULL;
CoUninitialize();
return hr;
}
CoUninitialize();
return 0;
}