Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Mail Enable with Exchange 2007 using LDAP

4.75/5 (6 votes)
24 Apr 2011CPOL4 min read 1  
How to mail enable AD accounts using LDAP and Exchange 2007.

Introduction

This article shows you have you can use LDAP and the System.DirectoryServices namespace to mail enable an Active Directory user account when you are using Exchange 2003 and 2007.

Background

Exchange 2007 and a lot of new products of Microsoft rely heavily on Powershell to script and automate tasks. Due to the fact that we have built several connectors using LDAP to automate our user management, we have invested some time to research why our current Exchange 2003 connections wouldn't work with the new Exchange 2007 environment. When performing the same routines as we did in Exchange 2003, we ended up with Legacy Mailboxes that we had to migrate to full 2007 compliance using Powershell. Turns out that to fulfill the 2007 specs, we had to populate five other Active Directory properties in order for Exchange 2007 to accept the mail enabling of the AD User account.

Using the code

To use the code, you supply the MailEnable method with two parameters. One parameter is the LDAP path to the user object in the Active Directory, and the other parameter is the LDAP path to the Exchange Mailbox Store.

Exchange part

To find the paths to the mailbox stores, we have made three methods that can retrieve the Exchange Servers, Exchange Mailbox Storage Groups, and the Exchange Mailbox Stores. Because we code in VB.NET and C#, the code snippets will be in one or the other language. These snippets are part of a huge library, so I can't supply you with all the code that is necessary to fully run it.

VB
Protected Function Get_RootDSEProperty (ByVal PropertyName As String) _
          As String
    Dim _DirectoryEnTry As New System.DirectoryServices.DirectoryEntry
    _DirectoryEnTry.Path = Protocol + Server + "RootDSE"
    Return CType(_DirectoryEnTry.Properties(PropertyName)(0), String)
End Function

In the above function, Protocol is a property filled with the string value "LDAP://". Server is a property specifying a Domain Controller (e.g., "UM-DC.LiQuick.net/"). This function will return the "roots" of the User/Groups/Computers/Contacts part of Active Directory (defaultNamingContext), which you can view with the Active Directory User and Computers MMC, and the root in which the Configuration settings of your domain is stored (configurationNamingContext). The configuration root is used to retrieve the Exchange servers, storage groups, and stores.

VB
Public Function ExchangeServer_PathsGet() As System.DirectoryServices.SearchResultCollection
    Dim _configurationNamingContext As String = _
        Protocol + Server + Me.Get_RootDSEProperty("configurationNamingContext")
    Dim LDAPConditions() As String = New String(0) {}
    LDAPConditions(0) = "objectCategory=msExchExchangeServer"
    Return Find_DirectoryEntries(LDAPConditions, _
           SearchScope.Subtree, _configurationNamingContext)
End Function

The above function returns the LDAP paths of all the Exchange servers you have made a member of your domain. Find_DirectoryEntries uses the System.DirectoryServices.DirectorySearcher namespace to find the objects that correspond to the LDAP query (&(objectCategory=msExchExchangeServer)).

VB
Public Function ExchangeServer_RetrieveStorageGroups( _
        ByVal directoryEntryExchangeServer As DirectoryEntry _
        ) As System.DirectoryServices.SearchResultCollection
    Dim LDAPConditions() As String = New String(0) {}
    LDAPConditions(0) = "objectCategory=msExchStorageGroup"
    Return Find_DirectoryEntries(LDAPConditions, _
           SearchScope.Subtree, directoryEntryExchangeServer)
End Function

Specifying the above function with a DirectoryEntry, having an LDAP path to an Exchange server will provide you with the storage groups that reside on that particular Exchange server.

VB
Public Function ExchangeServer_RetrieveStores( _
        ByVal directoryEntryExchangeStorageGroup As DirectoryEntry _
        ) As System.DirectoryServices.SearchResultCollection
    Dim LDAPConditions() As String = New String(0) {}
    LDAPConditions(0) = "objectCategory=msExchPrivateMDB"
    Return Find_DirectoryEntries(LDAPConditions, SearchScope.Subtree, _
                                 directoryEntryExchangeStorageGroup)
End Function

After choosing a storage group which you have retrieved with the function ExchangeServer_RetrieveStorageGroups, you can finally retrieve the much desired Mailbox Store Paths.

The above functions use the Find_DirectoryEntries function below. It takes a string array of conditions (for example, "objectCategory=msExchPrivateMDB") and forms it into an LDAP query (e.g., "(&(objectCategory=msExchPrivateMDB))"). The rest is explained in the MSDN libraries.

VB
Public Function Find_DirectoryEntries( _
        ByVal Conditions() As String, _
        ByVal Scope As System.DirectoryServices.SearchScope, _
        ByVal FromDirectoryEntry As System.DirectoryServices.DirectoryEntry _
        ) As System.DirectoryServices.SearchResultCollection
    Dim Filter As String
    Filter = CreateFilterAND(Conditions)
    Return Find_DirectoryEntries(Filter, Scope, FromDirectoryEntry)
End Function
VB
Public Function Find_DirectoryEntries( _
        ByVal Filter As String, _
        ByVal Scope As System.DirectoryServices.SearchScope, _
        ByVal FromDirectoryEnTry As System.DirectoryServices.DirectoryEntry, _
        Optional ByVal PageSize As Integer = 0 _
        ) As System.DirectoryServices.SearchResultCollection
    Dim _DirectorySearcher As New System.DirectoryServices.DirectorySearcher
    Dim _SearchResultCollection As System.DirectoryServices.SearchResultCollection
    _DirectorySearcher.SearchRoot = FromDirectoryEnTry 
    _DirectorySearcher.Filter = Filter
    _DirectorySearcher.SearchScope = Scope
    If PageSize > 0 Then
        _DirectorySearcher.PageSize = PageSize
    End If
    Try
        _SearchResultCollection = _DirectorySearcher.FindAll()
    Catch ex As Exception
        _SearchResultCollection = Nothing
    End Try
    Return _SearchResultCollection
End Function
VB
Public Function CreateFilterAND( _
        ByVal Conditions() As String, _
        Optional ByVal StringPreFilter As String = "" _
        ) As String
    Dim Filter As String = "(&"
    Filter += CreateFilter(Conditions, StringPreFilter)
    Filter += ")"
    Return Filter
End Function
VB
Public Function CreateFilter( _
        ByVal Conditions() As String, _
        Optional ByVal StringPreFilter As String = "" _
        ) As String
    Dim Filter As String = ""
    Dim Condition As String
    For Each Condition In Conditions
        Filter += "(" + Condition + ") "
    Next
    Filter += StringPreFilter
    Return Filter
End Function

User part

I will not go into how you can retrieve the LDAP path to a user object in Active Directory, there are numerous articles about how you can do that. The following code will actually mail enable the AD user account for an Exchange 2003 and 2007 environment. The only other thing you have to do which is not covered in this code is populating the proxy addresses (e-mail address of the user object). This code is taken from our WebService that provides several Active Directory manipulation methods.

C#
public void User_MailEnable(string path, string pathMailStore)
{
    try
    {
        System.DirectoryServices.DirectoryEntry directoryEntryUser = 
            new System.DirectoryServices.DirectoryEntry(path);

        string userName = (string) directoryEntryUser.Properties["samaccountname"][0];

        if (directoryEntryUser.Properties.Contains("msExchMailboxGuid") == false)
        {
            if (directoryEntryUser.Properties.Contains("displayName") == false)
            {
                directoryEntryUser.Properties["displayName"].Add(userName);
            }
            System.DirectoryServices.DirectoryEntry directoryEntryMailStore = 
                new System.DirectoryServices.DirectoryEntry(pathMailStore);
            string homeMDB = 
               (string) directoryEntryMailStore.Properties["distinguishedName"][0];
            string msExchHomeServerNamePath = _AD.Protocol + _AD.Server + 
              (string) directoryEntryMailStore.Properties["msExchOwningServer"][0];
            System.DirectoryServices.DirectoryEntry directoryEntryMailServer = 
                new System.DirectoryServices.DirectoryEntry(msExchHomeServerNamePath);
            string msExchHomeServerName = 
               (string) directoryEntryMailServer.Properties["legacyExchangeDN"][0];
            string legacyExchangeDN = msExchHomeServerName.Substring(0, 
                msExchHomeServerName.IndexOf("cn=")) + "cn=Recipients/cn=" + userName;
            directoryEntryUser.Properties["homemdb"].Value= homeMDB;
            directoryEntryUser.Properties["msExchHomeServerName"].Value = 
                                                              msExchHomeServerName;
            directoryEntryUser.Properties["mailNickName"].Value = userName;
            directoryEntryUser.Properties["legacyExchangeDN"].Value = legacyExchangeDN;
            if (directoryEntryMailServer.Properties.Contains("msExchVersion"))
            {
               directoryEntryUser.Properties["msExchVersion"].Value = 
                 directoryEntryMailServer.Properties["msExchVersion"][0];
               //User Mailbox
               directoryEntryUser.Properties["msExchRecipientDisplayType"].Value = 
                                                                       1073741824;
               //User Mailbox
               directoryEntryUser.Properties["msExchRecipientTypeDetails"].Value = 1;
            }
            Guid guid = Guid.NewGuid();
            directoryEntryUser.Properties["msExchMailboxGuid"].Add(guid.ToByteArray());
         }
        directoryEntryUser.CommitChanges();
    }
    catch (Exception e)
    {
    }
}

Extra information

In this paragraph, I intend to answer most questions I received by e-mail or the comments below this article.

"When I look at the new mailbox in the Exchange Console, the "Alias" on the General Tab is not set." The property you are looking for is called mailNickname. Below, I'll show you the AD_ObjectPropertySet function I use to set most text properties in AD. In this example, I would use AD_ObjectPropertySet(myDirectoryEntry, "mailNickname", "LiQuick", false).

"...and the E-Mail Addresses tab is blank." To fill the e-mail addresses, you should do two things. First, you should know that you have to set the property proxyAddresses. This is a multi-valued property in AD and you could use the below method AD_ObjectPropertySet. When you look closely at the e-mail addresses in Exchange, you will see that the standard e-mail addresses start with smtp:. The second thing you should know is that the primary e-mail address starts with uppercase, SMTP:. Furthermore, I set the primary e-mail address in the single-valued mail property of the AD DirectoryEntry. Below is an example of how I would set the e-mail addresses:

C#
//I use false because I want to clear all other values in this property first
AD_ObjectPropertySet(dirEntryAD, "proxyAddresses", "SMTP:R.Samulski@LiQuick.net", false);
AD_ObjectPropertySet(dirEntryAD, "proxyAddresses", 
                     "smtp:IWishIWasTheBoss@LiQuick.net" , true);
AD_ObjectPropertySet(dirEntryAD, "mail", "R.Samulski@LiQuick.net", false);
C#
public static void AD_ObjectPropertySet(
       System.DirectoryServices.DirectoryEntry directoryEntry, 
       string propertyName, string propertyValue, bool IsMultiValued)
{
    if (propertyValue == "")
    {
        if (directoryEntry.Properties.Contains(propertyName) == true)
        {
            directoryEntry.Properties[propertyName].Clear();
        }
    }
    else
    {
        if (IsMultiValued == true)
        {
            try
            {
                directoryEntry.Properties[propertyName].Add(propertyValue);
            }
            catch
            {
                directoryEntry.Properties[propertyName].Value = propertyValue;
            }
        }
        else
        {
            if (directoryEntry.Properties.Contains(propertyName) == true)
            {
                if (directoryEntry.Properties[propertyName][0].ToString() != propertyValue)
                {
                    directoryEntry.Properties[propertyName].Clear();
                    directoryEntry.Properties[propertyName].Value = propertyValue;
                }
                else
                {
                    return;
                }
            }
            else
            {
                directoryEntry.Properties[propertyName].Value = propertyValue;
            }
        }
    }
    directoryEntry.CommitChanges();
}

Points of interest

As I pointed out: the above code is not all you need to mail enable an AD user account, but I hope I have provided you with enough information to give you a push into the right direction.

History

  • 2008-10-09: First attempt to write the article.
  • 2011-04-23: Answered an e-mails question by adding some information.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)