Friday, February 4, 2011

Get the Fully Qualified Domain Name of a User's Exchange Server using the homeMDB Attribute

When you extend the schema to install Exchange (2003 & 2007), one of the attributes Microsoft doesn't add to the user object is an attribute to store the fully qualified domain name of Exchange server hosting the mailbox. That is really useful information! There are attributes that give you pretty good hints if you are aware of the environment such as homeMDB, homeMTA and msExchHomeServerName. The best you can glean from these attributes is the host name of the server. In a small forest, that might be good enough. In a large, global, multi-domain forest, that is not so great. Using homeMDB, we can determine the Mailbox Store of the user and obtain more information about it as an msExchMDB class object. From there, we look up the parent of this object, a Storage Group (msExchStorageGroup class object). At this point, we need to do another parental lookup, an Information Store (msExchInformationStore class object). And finally, if we look up the parental object of the information store, we discover the Exchange Server (msExchExchangeServer class object). Certainly, Microsoft would provide a dNSHostName attribute on the msExchExchangeServer object class. Right? That would make so much sense! WRONG! We are not beaten yet. There is an multi-valued attribute called networkAddress which stores information using the Microsoft Interface Definition Language. In the fifth element (remember the elements start at zero), we find ncacn_ip_tcp which in MIDL specifies the fully qualified domain name for the Exchange server. Finally! We are not done yet, however, we need to remove the "ncacn_ip_tcp" from the fifth element and to be fancy, return the resultant string in lower case.

In the example code below, I accomplish this minor feat of discovering the FQDN using the great-grandparent of the object whose distinguished name is stored in the homeMDB attribute of a user and use up a daily supply of parenthesizes in one line. I have tested this in an Exchange 2003 and Exchange 2007 environment. I have not in an Exchange 2010 environment. I am starting that project soon so I will update this blog post in the future or if you have such an environment handy, leave a comment on the success or failure of this code snippet.

I use techniques from my "Get Object Active Directory Domain from distinguishedName" and "Return a Local Domain Controller in the Current Site for a Specific Domain" blog entries and rolled them into functions. As shown in Enumerate Objects in an Organizational Unit, I use those two functions to easily return objects from Active Directory from a third function that relies on the other two.
Function Get-LocalDomainController($objectDomain) {
 return ([System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite()).Servers | Where-Object { $_.Domain.Name -eq $objectDomain } | ForEach-Object { $_.Name } | Select-Object -first 1
}

Function Get-ObjectADDomain($distinguishedName) {
 return ((($distinguishedName -replace "(.*?)DC=(.*)",'$2') -replace "DC=","") -replace ",",".")
}

Function Get-ActiveDirectoryObject($distinguishedName) {
 return [ADSI]("LDAP://" + (Get-LocalDomainController (Get-ObjectADDomain $distinguishedName)) + "/" + ($distinguishedName -replace "/","\/"))
}
#--------------------------------------------------------------------------------------------------#
$userDn = "CN=Doe\, John,CN=Users,DC=ad,DC=mydomain,DC=Local"
$userObject = Get-ActiveDirectoryObject $userDn
$mailServer = ((((((Get-ActiveDirectoryObject $userObject.homeMDB).psbase.parent).psbase.parent).psbase.parent).networkAddress[4]).ToString() -replace "ncacn_ip_tcp:","").ToLower()
Write-Host $mailServer

No comments:

Post a Comment