使用 LDAP 启用 Exchange 2007 的邮件
如何使用 LDAP 和 Exchange 2007 启用 AD 帐户的邮件功能。
引言
本文展示了如何使用 LDAP 和 System.DirectoryServices
命名空间,在您使用 Exchange 2003 和 2007 时,为 Active Directory 用户帐户启用邮件功能。
背景
Exchange 2007 和许多新的 Microsoft 产品都严重依赖 Powershell 来脚本化和自动化任务。由于我们使用 LDAP 构建了多个连接器来自动化用户管理,因此我们花了一些时间研究为什么我们当前的 Exchange 2003 连接在新 Exchange 2007 环境中不起作用。当我们执行与 Exchange 2003 相同的例程时,我们最终得到了需要使用 Powershell 迁移到完全符合 2007 标准的旧版邮箱。事实证明,要满足 2007 年的规范,我们必须填充五个其他 Active Directory 属性,以便 Exchange 2007 接受 AD 用户帐户的邮件启用。
使用代码
要使用该代码,您需要向 MailEnable
方法提供两个参数。一个参数是 Active Directory 中用户对象的 LDAP 路径,另一个参数是 Exchange 邮箱存储的 LDAP 路径。
Exchange 部分
为了查找邮箱存储的路径,我们创建了三个方法来检索 Exchange 服务器、Exchange 邮箱存储组和 Exchange 邮箱存储。因为我们用 VB.NET 和 C# 编写代码,所以代码片段将使用其中一种语言。这些代码片段是一个庞大库的一部分,因此我无法为您提供完全运行它所需的所有代码。
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
在上面的函数中,Protocol
是一个属性,其中包含字符串值“LDAP://”。Server
是一个指定域控制器(例如,“UM-DC.LiQuick.net/”)的属性。此函数将返回 Active Directory 的用户/组/计算机/联系人部分的“根”(defaultNamingContext
),您可以使用 Active Directory 用户和计算机 MMC 查看它,以及存储您的域的配置设置的根(configurationNamingContext
)。配置根用于检索 Exchange 服务器、存储组和存储。
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
上面的函数返回您已成为域成员的所有 Exchange 服务器的 LDAP 路径。Find_DirectoryEntries
使用 System.DirectoryServices.DirectorySearcher
命名空间查找与 LDAP 查询(&(objectCategory=msExchExchangeServer)
)对应的对象。
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
使用具有 Exchange 服务器 LDAP 路径的 DirectoryEntry
指定上面的函数,将为您提供驻留在该特定 Exchange 服务器上的存储组。
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
选择一个通过 ExchangeServer_RetrieveStorageGroups
函数检索到的存储组后,您终于可以检索到备受期待的邮箱存储路径了。
上面的函数使用了下面的 Find_DirectoryEntries
函数。它接受一个条件字符串数组(例如,“objectCategory=msExchPrivateMDB
”),并将其格式化为 LDAP 查询(例如,“(&(objectCategory=msExchPrivateMDB))
”)。其余部分将在 MSDN 库中进行解释。
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
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
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
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
用户部分
我将不详细介绍如何检索 Active Directory 中用户对象的 LDAP 路径,因为有许多文章对此进行了介绍。以下代码将实际为 Exchange 2003 和 2007 环境启用 AD 用户帐户的邮件功能。您唯一需要做的、并且未包含在此代码中的是填充代理地址(用户对象的电子邮件地址)。此代码摘自我们提供多个 Active Directory 操作方法的 WebService。
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)
{
}
}
额外信息
在这一段中,我打算回答我在电子邮件或本文评论中收到的大部分问题。
“当我查看 Exchange 控制台中的新邮箱时,“常规”选项卡上的“别名”未设置。”您要查找的属性名为 mailNickname
。下面,我将展示用于设置 AD 中大多数文本属性的 AD_ObjectPropertySet
函数。在此示例中,我将使用 AD_ObjectPropertySet(myDirectoryEntry, "mailNickname", "LiQuick", false)
。
“...并且“电子邮件地址”选项卡为空。”要填写电子邮件地址,您应该做两件事。首先,您应该知道您需要设置 proxyAddresses
属性。这是 AD 中的多值属性,您可以使用下面的 AD_ObjectPropertySet
方法。当您仔细查看 Exchange 中的电子邮件地址时,您会发现标准的电子邮件地址以 smtp: 开头。第二件事是,您应该知道主电子邮件地址以大写字母 SMTP: 开头。此外,我在 AD DirectoryEntry
的单值 mail
属性中设置了主电子邮件地址。以下是如何设置电子邮件地址的示例。
//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);
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();
}
关注点
正如我所指出的:上面的代码并不是启用 AD 用户帐户邮件功能所需的所有内容,但我希望我已提供了足够的信息,能为您提供一个正确的方向。
历史
- 2008-10-09:首次尝试撰写文章。
- 2011-04-23:通过添加一些信息回答了电子邮件问题。