Wednesday, February 9, 2011

Exchange Accepted Mail Domains and User Primary SMTP Addresses

In large organizations, Exchange environments can handle numerous mail enabled domains. It is not uncommon to configure Exchange to accept mail for hundreds of domains. Keeping abreast of what domains are enabled and which users have them as their primary SMTP address is important. Companies launch products & services only to abandon them later. You might want to make a business decision to purge them from your mail system and no longer pay to own a domain. In the code sample below, I accomplish a few things. First, I discover which domains are configured in Exchange for the acceptance of e-mail by searching the Global Catalog for objects of the msExchAcceptedDomain class. Once those objects are discovered, I load those objects and obtain the domain through the msExchAcceptedDomainName attribute, sort them alphabetically and save them to a text file. Since I stored the enabled domains in an array, I can loop through them in a foreach loop and use them to discover users that have them as their primary SMTP address -- the goal I had when I wrote this script. I create two comma separated value text files from the results. The first is an audit of the domains and the number of users that have them as their primary SMTP. The second is an detailed export of those users.

Be aware that looking at just the users does not give you a complete picture of what objects in the forest are using mail enabled domains. Distribution Lists and Mail Enabled Security Groups can also accept mail from the Internet redirecting the message to the population of the members attribute and might be of interest in a review. To add this information to your query, change the LDAP filter to include them.
$ldapFilter = "(&(|(objectClass=user)(objectClass=group))(mail=*@$acceptedMailDomain))"
Another query that might be of interest is to expand the search beyond the primary SMTP address of the user object to include all proxy addresses associated to the user account. To accomplish this, change the LDAP filter to swap the mail attribute for the proxyAddresses multi-valued string attribute and include proxyAddresses in the returned attributes.
$ldapFilter = "(&(objectClass=user)(proxyAddresses=smtp:*@$acceptedMailDomain)(homeMDB=*))"
$ldapAttr = "distinguishedName,sAMAccountName,givenName,sn,proxyAddresses,telephoneNumber,streetAddress,l,st,postalCode,c"
You will also want to represent all matching e-mail addresses for that mail domain in your returned data file.
Add-Member -inputObject $mailDomainUser -type NoteProperty -name "eMail" -value [System.String]::join(";", ((($objectRecordSet.Fields.Item('proxyaddresses').Value) | Where-Object { $_ -match "smtp:(.*)@$acceptedMailDomain" }) | ForEach-Object { $_ -replace "smtp:","" }))
If your environment does handle a large number of accepted mail domains, expect this script to take some time to complete. I have included some Write-Host statements in the code to provide assurance that it is operating.
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 "/","\/"))
}
#--------------------------------------------------------------------------------------------------#
Set-Variable -name forestRootDn -option Constant -value ([ADSI]("LDAP://" + (([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()).name) + "/rootDSE")).defaultNamingContext
#--------------------------------------------------------------------------------------------------#
$acceptedMailDomains = @()
$mailDomainUsers = @()
$mailDomainsInfo = @()

$objectConnection = New-Object -comObject "ADODB.Connection"
$objectCommand = New-Object -comObject "ADODB.Command"
$objectConnection.Open("Provider=ADsDSOObject;")
$objectCommand.ActiveConnection = $objectConnection

$ldapBase = "GC://$forestRootDn"
$ldapFilter = "(objectClass=msExchAcceptedDomain)"
$ldapAttr = "distinguishedName"
$ldapScope = "subtree"
$ldapQuery = "<$ldapBase>;$ldapFilter;$ldapAttr;$ldapScope"

Write-Host "Exchange Mail Domains: " -noNewLine

$objectCommand.CommandText = $ldapQuery
$objectRecordSet = $objectCommand.Execute()

Write-Host $objectRecordSet.RecordCount

while(!$objectRecordSet.EOF) {
 $acceptedDomainObject = Get-ActiveDirectoryObject $objectRecordSet.Fields.Item('distinguishedName').Value
 $acceptedMailDomains += (($acceptedDomainObject.msExchAcceptedDomainName).ToString()).ToLower()
 $objectRecordSet.MoveNext()
}

$acceptedMailDomains = $acceptedMailDomains | Sort-Object

Set-Content -path "acceptedMailDomains.txt" -value ($acceptedMailDomains | Out-String)

foreach($acceptedMailDomain in $acceptedMailDomains) {
 Write-Host $acceptedMailDomain -noNewLine
 Write-Host ": " -noNewLine 

 $ldapFilter = "(&(objectClass=user)(mail=*@$acceptedMailDomain)(homeMDB=*))"
 $ldapAttr = "distinguishedName,sAMAccountName,givenName,sn,mail,telephoneNumber,streetAddress,l,st,postalCode,c"
 $ldapQuery = "<$ldapBase>;$ldapFilter;$ldapAttr;$ldapScope"
 $objectCommand.CommandText = $ldapQuery
 $objectRecordSet = $objectCommand.Execute()
 $userCount = $objectRecordSet.RecordCount
 
 Write-Host $userCount
 
 $mailDomainInfo = New-Object -typeName PSObject
 Add-Member -inputObject $mailDomainInfo -type NoteProperty -name "mailDomain" -value $acceptedMailDomain
 Add-Member -inputObject $mailDomainInfo -type NoteProperty -name "count" -value $userCount
 $mailDomainsInfo += $mailDomainInfo
 
 while(!$objectRecordSet.EOF) {
  $userObjectDomain = Get-ObjectADDomain $objectRecordSet.Fields.Item('distinguishedName').Value

  $mailDomainUser = New-Object -typeName PSObject
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "mailDomain" -value $acceptedMailDomain
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "domain" -value $userObjectDomain.Split(".")[0]
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "sAMAccountName" -value $objectRecordSet.Fields.Item('sAMAccountName').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "firstName" -value $objectRecordSet.Fields.Item('givenName').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "lastName" -value $objectRecordSet.Fields.Item('sn').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "eMail" -value $objectRecordSet.Fields.Item('mail').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "telephoneNumber" -value $objectRecordSet.Fields.Item('telephoneNumber').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "streetAddress" -value ($objectRecordSet.Fields.Item('streetAddress').Value -replace "`r`n",", ")
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "city" -value $objectRecordSet.Fields.Item('l').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "state" -value $objectRecordSet.Fields.Item('st').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "zipCode" -value $objectRecordSet.Fields.Item('postalCode').Value
  Add-Member -inputObject $mailDomainUser -type NoteProperty -name "country" -value $objectRecordSet.Fields.Item('c').Value
  $mailDomainUsers += $mailDomainUser

  $objectRecordSet.MoveNext() 
 }
}

$mailDomainUsers | Export-Csv -path "mailDomainUsers.csv" -noTypeInformation
$mailDomainsInfo | Export-Csv -path "mailDomainInformation.csv" -noTypeInformation

No comments:

Post a Comment