Thursday, March 17, 2011

Add a New Mail Domain to Multiple Users

In my work, it is not uncommon to have new domains purchased for business units and employees immediately needing e-mail addresses with the new domain. So after the MX record is created and Exchange is updated to accept mail for the new domain, its time to target the users that require the new mail domain to be included in the proxyAddresses attribute. The proxyAddresses attribute is multivalued so you must use treat it as an array and use PutEx to append to the attribute with the new address. In the code sample below, I take a file of e-mail addresses that users already use, split off the "local-part" from the domain using the at sign as the delimiter and append the $newMailDomain constant to the local-part to create the new e-mail address for the user.  When inserting the new e-mail address into the proxyAddresses attribute with PutEx, you will need to send it as an array even if it only has 1 element. To be on the safe side, which you should also do when modifying production data, a backup of all the current elements of the user's proxyAddresses attribute are dumped into a subdirectory called "backup" in a file name that matches their mail attribute (with ".txt" appended) and the script is set to not write to the directory by default. You must alter the $writeEnabled constant in order to actually update the user's object. The script also checks to see if the e-mail address you are trying to assign to the employee's account is already present and skips if so. I am using Write-Output to document the scripts behavior so you can easily pipe it out to a text file for review.

This script does not make the new address the employee's primary SMTP address. In order to do this, you would need to remove the current primary denoted by the "SMTP:" at the start of the proxyAddress and return it back with "smtp:" then add the new e-mail address with "SMTP:" at the start. I will provide a code sample in the future that will detail that swap out and how to do it safely.

And remember, this script modifies data! Use at your own risk! I might have the best of intentions but my skill may betray you. Test, test and further test before implementing this code in a production environment.
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
Set-Variable -name adsPropertyAppend -option Constant -value 3
Set-Variable -name newMailDomain -option Constant -value "@newdomain.local"
Set-Variable -name inputFile -option Constant -value "userlist.txt"
Set-Variable -name writeEnabled -option Constant -value $false
if(Test-Path -path $inputFile) { 
 $userList = Get-Content -path $inputFile
} else {
 Write-Host "Could not locate $inputFile. Exiting..." -foregroundColor Red
if(!(Test-Path -path "backup")) {
 New-Item -path "backup" -type directory | Out-Null

$objectConnection = New-Object -comObject "ADODB.Connection"
$objectCommand = New-Object -comObject "ADODB.Command"
$objectCommand.ActiveConnection = $objectConnection

foreach($user in $userList) {

 $ldapBase = "GC://$forestRootDn"
 $ldapAttr = "distinguishedName"
 $ldapScope = "subtree"
 $ldapFilter = "(&(objectClass=user)(proxyAddresses=smtp:$user))"
 $ldapQuery = "<$ldapBase>;$ldapFilter;$ldapAttr;$ldapScope"
 $objectCommand.CommandText = $ldapQuery
 $objectRecordSet = $objectCommand.Execute()
 if(!$objectRecordSet.EOF) {
  while(!$objectRecordSet.EOF) {
   $userObject = Get-ActiveDirectoryObject $objectRecordSet.Fields.Item('distinguishedName').Value
   $newEmailAddress = ("smtp:" + ($user.Split("@")[0]).ToLower() + $newMailDomain)
   Write-Output ($userObject.displayName).ToString()
   Write-Output "New Address: $newEmailAddress"
   $notFound = $true
   Set-Content -path ("backup\" + ($userObject.mail).ToString() + ".txt") -value $userObject.proxyAddresses
   foreach($proxyAddress in $userObject.proxyAddresses) {
    if($proxyAddress -eq $newEmailAddress) {
     $notFound = $false
   if($notFound -eq $true) {
    Write-Output "Adding $newEmailAddress"
    if($writeEnabled -eq $true) {
     $userObject.PutEx($adsPropertyAppend, "proxyAddresses", @($newEmailAddress))
   } else {
    Write-Output "Already has $newEmailAddress"
 } else {
  Write-Output "Could not locate $user in the forest."
 Write-Output ("-" * 50)

No comments:

Post a Comment