Background:
Environment:
Appox 200,000 user objects in Lotus Notes Address Book (NAB)
Exchange 2007 SP1 running on Windows 2008 Server.
Exchange and OCS are installed in a Resource Forest (2003 forest mode)
Users authenticate into a Windows 2000 AD User forest (2000 forest mode).
Lotus Notes 6.5
ILM MA’s connecting (AD MA) Exchange Resource Forest, (AD MA) User Forest, (Domino MA) Lotus Notes NAB.
Domino Mailbox users are provisioned as Disabled Mail User objects in the Exchange Resource Forest rather than a contact object.
Issue:
We ran into a challenge of being able to provision a large amount of mailboxes in a short amount of time. Additionally the large changes to the GAL were concerning me with regard to wide spread OAB downloads.
Solution:
Rather than using the traditional approach of using a contact forwarding to a notes mailbox, then upon migration, provisioning the mailbox, deleting the contact and copying the legacyExchangeDN from the contact and stamping it as an X.500 on the mailbox, this approach uses a mail-user object as the “contact” forwarding to the notes mailbox. We then surgically replace the key attributes in the directory to convert a mail-user to a mailbox user WITHOUT changing its representation in the GAL/OAB e.g. legacyExchangeDN never changes.
Caveat:
The only issue with this approach is that it effectively removes the ability to stage mail in the mailbox prior to the date of the actual user being migrated.
Roll-Forward
1. Clear targetAddress on the mail enabled user object.
2. Set homeMDB on the mail enabled user object.
3. Set msExchRecipientTypeDetails = 2 (see http://marksmith.netrends.com/Lists/Posts/ViewPost.aspx?ID=51 for more details on different mailbox types)
4. Set msExchMasterAccountSid = {SID of User Forest user object}
a. $LinkedAccountSID = ((new-object System.Security.Principal.NTAccount($UserForestAccount)).Translate([System.Security.Principal.SecurityIdentifier])).Value
b. ILM can flow the binary value of the User Forest object’s SID in the metaverse into this property.
5. Call powershell update-recipient {resource forest mailbox name}.
6. Call powershell Add-Mailboxpermission {resource forest mailbox name} -User [UserDomain]\[UserID] -AccessRights FullAccess,ExternalAccount
7. Call powershell Add-AdPermission {resource forest mailbox name} -User [UserDomain]\[UserID] -ExtendedRights Send-As
Roll-Back
1. Call powershell Remove-AdPermission {resource forest mailbox name} –User [UserDomain]\[UserID] –ExtendedRights Send-As (if using linked mailbox)
2. Call powershell Remove-Mailboxpermission {resource forest mailbox name} –User [UserDomain]\[UserID] –AccessRights FullAccess,ExternalAccount (if using linked mailbox)
3. Clear the following attributes:
a. homeMDB
b. homeMTA
c. msExchangeHomeServerName
d. msExchangeMailboxGuid
e. msExchMasterAccountSid (if using resource forest/linked mailbox)
f. msExchPoliciesIncluded
g. msExchPoliciesExcluded
i. IMPORTANT: If you are not using Exchange Address Policies, {26491CFC-9E50-4857-861B-0CB8DF22B5D7} Should not be removed.
h. msExchRecipientTypeDetails
i. We might need to add some additional attributes if other policies are included or excluded e.g. Activesync, etc.
j. msExchVersion
k. msExchUserAccountControl
l. msExchRecipientDisplayType
m. msExchMailboxSecurityDescriptor
4. set targetAddress = mail attribute (this should be the Notes internetAddress)
5. call powershell update-recipient {resource forest mailbox name}
References:
http://support.microsoft.com/kb/275636
Reasoning:
The big benefit I see to this approach over the traditional migration/coexistence approach (contact object points to Notes person doc, delete contact, mailbox enable user, flow attributes from one to the other) are the following:
1. Eliminates a number of complexities in the ILM implementation (having to manage a contact object and user object, attribute flow from one to the other, etc).
2. Much faster provisioning of mailboxes (In my tests, I was able to do about 20,000 in 3 mins).
3. OAB download issues. Flipping the contact object to a mailbox will result in changes to the OAB:
a. “In pre-OAB v4 versions of the offline address book, Outlook uses a default threshold of one-eighth to determine when to not perform a differential offline address book download and instead perform a full offline address book download. If you are using Outlook 2003 SP2 and OAB v4 [OR OUTLOOK 2007], this threshold has been increased to 50 percent.”
b. “The offline address book differential file contains an entire user record even if the changes to the record are small. For example, if the only change is the office location, the entire record including the certificates is added to the differential offline address book.”
c. “Outlook calculates a percentage ratio of the total size of all the compressed differential offline address book files on the server to the current total size of the compressed full offline address book on the server. If the percentage ratio exceeds the threshold value, Outlook performs a full download instead of downloading the differentials.”
http://technet.microsoft.com/en-us/library/aa996241(EXCHG.65).aspx
This approach would mean zero OAB differential changes because we’re not adding/deleting any objects from the OAB and we’re not modifying any attributes contained within the existing objects in the OAB. For example, when we convert “John Doe” mail user to “John Doe” linked mailbox, that attributes that are updated (homeMDB, homeMTA, etc.) aren’t attributes included in the OAB.
The net results would be a big savings in the timing of OAB generation, CAS replication, download, and thus network traffic when we provision mailboxes.
Conceptual Testing (convert to mailbox user rather than linked mailbox user):
makeMailUsers.ps1 creates 20,000 mail users in a given OU.
flipMailUserToMB.ps1 flips the user object from mail user to mailbox user.
flipMailUsertoMB.ps1 provisions a list of users from mail users to mailboxes
POWERSHELL SCRIPT: makeMailUsers.ps1
Edit the –OrganizationalUnit value to the domain and OU where the test users will be created.
When prompted for credentials, enter any username, and the password you would like to assign to the 20,000 user objects.
|
$password = get-credential
$top = 20
$ou = "domain.local/Clients/NETrends Systems/Notes DirSync/MigTest"
for ($i = 1;$i -le $top; $i++){
$name = "DUser$i"
$upn ="DUser$i@netrends.com"
$targetAddress = "SMTP:$name@notes.domain.com"
New-MailUser -Name $name -Alias $name -OrganizationalUnit "$ou" -UserPrincipalName $upn -SamAccountName $name -FirstName 'Mail' -LastName $name -Password $password.password -ExternalEmailAddress $targetAddress
} |
POWERSHELL SCRIPT: flipMailUsertoMB.ps1
Edit the $homeMDB variable to the DN of a mailbox database in your environment.
Edit the $ou variable to the OU you created your 20,000 mail users in makeMailUsers.ps1
|
# FQDN of GC
$gc = "GC01.domain.local"
# $migusers imports the csv file. Edit the filename/path in this line if necessary
$migUsers = Import-Csv .\migrationusers.csv
$curDir = get-location
# begin loop of users
foreach ($line in $migUsers) {
# get the homeMDB value from the CSV file
$homeMDB = $line.homeMDB
# use the user object based off of the username in the csv file
$migUser = Get-User $line.userName
# get the AD DN of the user object
$userDn = $migUser.DistinguishedName
# create the ldap query
$ldp = "LDAP://" + "$gc" + ":389/" + $userDn
# set an ADSI object that we can edit
$user = [ADSI]"$ldp"
# clear the target address
$user.putex(1, "targetAddress", 0)
$user.setinfo()
# set the recipient type to mailbox (note use 2 for linked mailbox and add the sid for the msexchange linked master sid in a resource forest mode)
$user.put("msExchRecipientTypeDetails", "1")
$user.setinfo()
# set homeMDB
$user.put("homeMDB", "$homeMDB")
$user.setinfo()
# call update-recipient (RUS) so exchange will stampt the missing attributes and make the user a mail-user again.
update-recipient -identity "$userDN" -domainController "$gc"
# this loop checks the status of the user object.
# prior to RU4 there was a bug in update-recipient where the -domaincontroller argument value was not used for both the DC and GC
# this loop runs update-recipient waits 3 seconds, if the user is still a mail user it will re-run. If it's a mailbox then it will exit.
get-user "$userDN" -domaincontroller "$gc" > tempfile2007.txt
[string]$userStatus = get-content tempfile2007.txt
$counter = 0
While ($userStatus.contains("MailUser") -AND $counter -lt 20)
{
update-recipient -identity "$userDN" -domainController "$gc"
if ($counter -gt 0) {start-sleep 3}
get-user "$userDN" -domaincontroller "$gc" > tempfile2007.txt
[string]$userStatus = get-content tempfile2007.txt
$counter = $counter + 1
}
if ($counter -lt 20) {write-host "Mailbox Provisioned in: " + $counter + " update-recipient calls" + chr(10) + chr(13)}
}} |