Recent experience with Exchange 2007 and Cross-Forest account management

I wanted to share some lessons learned recently as a result of working a case where the goal was to create a new mail contact in a remote forest.  Existing contacts were able to be edited, so permissions didn’t appear to be the issue.  I was able to set up a cross-forest trust in my lab, and reproduced the problem.  This problem really only exists in Exchange 2007, as Exchange 2010 supports opening a Remote Powershell instance where you could connect directly to the remote forest from a server in the source forest.

Here I am trying to create a new mail contact.  I tried to keep the parameters I used pretty simple.  By specifying the domain controller as a DC in the remote forest, I ensure that I am talking to that forest when I attempt to create the contact.  I’ve highlighted a few things that stood out to me.

[PS] C:\WINDOWS\system32>New-MailContact -Name "Blah Test" -ExternalEmailAddress blahblah@blah.com -PrimarySmtpAddress blah@mydomain.com –DomainController <Remote Forest DC> -Verbose –OrganizationalUnit <Remote Forest OU>
VERBOSE: New-MailContact : Beginning processing.
VERBOSE: New-MailContact : Searching objects "<Remote Forest OU>" of type "ExchangeOrganizationalUnit" under the root "$null".
VERBOSE: New-MailContact : Previous operation run on domain controller <Remote ForestDC>.
VERBOSE: New-MailContact : Administrator Active Directory session settings are:  View Entire Forest: 'False', Default Scope: ‘<Source Forest>’, Configuration Domain Controller: '<Source Forest DC>',
VERBOSE: New-MailContact : Applying RUS policy to the given recipient "<Remote Forest>/Contacts/Blah Test" with the home domain controller "<Remote Forest DC>".
VERBOSE: New-MailContact : The RUS server that will apply policies on the specified recipient is "<Remote Forest MBX server>".
VERBOSE: New-MailContact : Searching objects of type "ADRecipient" with filter "(&((!((Id Equal <Remote Forest>/Contacts/Blah Test)))(|((EmailAddresses Equal SMTP:blah@<Remote forest.com>)))))", scope "SubTree" under the root "$null".
VERBOSE: New-MailContact : Processing object "<Remote Forest>/Contacts/Blah Test".
VERBOSE: Creating Mail Contact "Blah Test" with External E-mail Address "SMTP:blahblah@blah.com", Organizational Unit "<Remote Forest>/contacts".
VERBOSE: New-MailContact : The properties changed are: "{ DisplayName='Blah Test', AddressListMembership={ '\Default Global Address List' }, Alias='BlahTest', EmailAddresses={ 'SMTP:blah@<remote forest.com>' }, RawExternalEmailAddress='SMTP:blahblah@blah.com', PoliciesExcluded={ '{26491cfc-9e50-4857-861b-0cb8df22b5d7}' }, Id=’<Remote Forest>/Contacts/Blah Test', RawName='Blah Test', ObjectCategory='<Source Forest>/Configuration/Schema/person' }".
VERBOSE: New-MailContact : Saving object "<Remote Forest>/Contacts/Blah Test" of type "ADContact" and state "New".
VERBOSE: New-MailContact : Previous operation run on domain controller ‘<Remote Forest DC>’. New-MailContact : Active Directory operation failed on <Remote Forest DC>. This error could have been caused by user input or by the Active Directory server being unavailable. Please retry at a later time. Additional information: Additional information: The global catalog verification failed. The global catalog is not available or does not support the operation. Some part of the directory is currently not available. Active directory response: 000020E1: SvcErr: DSID-032005F2, problem 5002 (UNAVAILABLE), data 0. At line:1 char:16 + New-MailContact  <<<< -Name "Blah Test" -ExternalEmailAddress blahblah@blah.com -PrimarySmtpAddress blah@<RemoteForest.com> –DomainController <Remote Forest DC> -Verbose –OrganizationalUnit <Remote Forest>/contacts
VERBOSE: New-MailContact : Ending processing.

I was capturing a Netmon trace during this after disabling LDAP encryption (see , and this was the frame that showed the LDAP add request (creating the mail contact).  Note the highlighted part below.

Frame: Number = 233, Captured Frame Length = 1035, MediaType = ETHERNET
+ Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-15-5D-41-BD-00],SourceAddress:[00-15-5D-41-BD-0B]
+ Ipv4: Src = 10.10.100.16, Dest = 10.10.0.200, Next Protocol = TCP, Packet ID = 13162, Total IP Length = 1021
+ Tcp: Flags=...AP..., SrcPort=33110, DstPort=LDAP(389), PayloadLen=981, Seq=1117411596 - 1117412577, Ack=4214889466, Win=64154
- Ldap: Add Request, MessageID: 119
  + SASLBuffer: 
  - Parser: Add Request, MessageID: 119
   + ParserHeader: 
   + MessageID: 119
   + OperationHeader: Add Request, 8(0x8)
   - AddRequest: Entry: CN=Blah Test,OU=Contacts,DC=<remote forest>,DC=com
    - Entry: CN=Blah Test,OU=Contacts,DC=<remote forest>,DC=com
     + AsnOctetStringHeader: 
       OctetStream: CN=Blah Test,OU=Contacts,DC=<remote forest>,DC=com
    - Attributes: 13 Partial Attributes
     + SequenceHeader: 
     + PartialAttribute: CountryCode=( 0 )
     + PartialAttribute: displayName=( Blah Test )
     + PartialAttribute: showInAddressBook=( CN=Default Global Address List,CN=All Global Address Lists,CN=Address Lists Container,CN=<ORG Name>,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=<remote forest>,DC=com )
     + PartialAttribute: mailNickname=( BlahTest )
     + PartialAttribute: proxyAddresses=( SMTP:blah@<remote forest>.com )
     + PartialAttribute: targetAddress=( SMTP:blahblah@blah.com )
     + PartialAttribute: internetEncoding=( 1310720 )
     + PartialAttribute: msExchPoliciesExcluded=( {26491cfc-9e50-4857-861b-0cb8df22b5d7} )
     + PartialAttribute: msExchRecipientDisplayType=( 6 )
     + PartialAttribute: distinguishedName=( CN=Blah Test,OU=Contacts,DC=<remote forest>,DC=com )
     + PartialAttribute: msExchVersion=( 4535486012416 )
     + PartialAttribute: objectCategory=( CN=person,CN=Schema,CN=Configuration,DC=<source forest>,DC=com )

In response to this, I got the LDAP error seen in the Powershell window.

LDAP:Add Response, MessageID: 119, Status: Unavailable ErrorMessage: 000020E1: SvcErr: DSID-032005F2, problem 5002 (UNAVAILABLE), data 0

If you see the same thing I did (well, since I’ve been nice and highlighted it), you probably know why the operation failed.  Yes indeed, the LDAP Add request is passing an attribute value that contains the source forest.  No wonder why the remote domain controller was responding with an error!

Luckily, Powershell allows you to control some additional settings via $AdminSessionADSettings.  Checking the current settings, I found the following listed

[PS] C:\WINDOWS\system32>$adminsessionadsettings
ViewEntireForest              : False
DefaultScope                  : <source domain>
PreferredGlobalCatalog        :
ConfigurationDomainController : <souce domain DC>
PreferredDomainControllers    : {}

On a whim, I changed the config DC to point to one in the remote forest by running the cmd

$adminsessionadsettings.configurationdomaincontroller = ‘<remote forest DC>’

[PS] C:\WINDOWS\system32>$adminsessionadsettings
ViewEntireForest              : False
DefaultScope                  : <source domain>
PreferredGlobalCatalog        :
ConfigurationDomainController : <remote forest DC>
PreferredDomainControllers    : {}

After making this change, I ran the cmdlet once again, expecting it to fail, but it succeeded.

[PS] C:\WINDOWS\system32>New-MailContact -Name "Blah Test" -ExternalEmailAddress blahblah@blah.com -PrimarySmtpAddress blah@mydomain.com –DomainController <remote forest DC> -Verbose –OrganizationalUnit <remote forest OU>
VERBOSE: New-MailContact : Beginning processing.
VERBOSE: New-MailContact : Searching objects "<remote forest OU>" of type "ExchangeOrganizationalUnit" under the root "$null".
VERBOSE: New-MailContact : Previous operation run on domain controller '<remote forest DC>'.
VERBOSE: New-MailContact : Administrator Active Directory session settings are:  View Entire Forest: 'False', Default Scope: '<source forest>', Configuration Domain Controller: '<remote forest DC>',
VERBOSE: New-MailContact : Applying RUS policy to the given recipient "<remote forest OU>/Blah Test" with the home domain controller "<remote forest DC>".
VERBOSE: New-MailContact : The RUS server that will apply policies on the specified recipient is "<remote forest MBX server>".
VERBOSE: New-MailContact : Searching objects of type "ADRecipient" with filter "(&((!((Id Equal <remote forest>/Contacts/Blah Test)))(|((EmailAddresses Equal SMTP:blah@<remote forest>)))))", scope "SubTree" under the root "$null".
VERBOSE: New-MailContact : Processing object "<remote forest OU>/Blah Test".
VERBOSE: Creating Mail Contact "Blah Test" with External E-mail Address "SMTP:blahblah@blah.com", Organizational Unit "<remote forest OU>".
VERBOSE: New-MailContact : The properties changed are: "{ DisplayName='Blah Test', AddressListMembership={ '\All Contacts', '\Default Global Address List' }, Alias='BlahTest', EmailAddresses={ 'SMTP:blah@<remote forest>' }, RawExternalEmailAddress='SMTP:blahblah@blah.com', LegacyExchangeDN='/o=<ORG name>/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=BlahTest', PoliciesExcluded={ '{26491cfc-9e50-4857-861b-0cb8df22b5d7}' }, Id='<remote forest>/Contacts/Blah Test', RawName='Blah Test', ObjectCategory='<remote forest>/Configuration/Schema/person' }".
VERBOSE: New-MailContact : Saving object "<remote forest>/Contacts/Blah Test" of type "ADContact" and state "New".
VERBOSE: New-MailContact : Previous operation run on domain controller '<remote forest DC>’.
VERBOSE: New-MailContact : Reading new object "<remote forest>/Contacts/Blah Test" of type "ADContact".
VERBOSE: New-MailContact : Previous operation run on domain controller '<remote forest DC>'.
Name                      Alias                                          RecipientType
----                      -----                                          -------------
Blah Test                 BlahTest                                       MailContact
VERBOSE: New-MailContact : Ending processing.

This time, both Netmon and the verbose output from the cmdlet show that the Configuration partition being referenced to set the objectcategory is for the correct domain/forest, and the add request succeeds.