This post continues the documentation of a single project – migration of a bunch of users between two 365 tenants. This is Part Six which goes over the user setup in the target tenant
Part One – Introduction and Approach
Part Two – Identifying Users and Objects
Part Three – Setup of New Tenant
Part Four – Data Migration with Quest-On-Demand
Part Five – Domain Migration
Part Six – Destination Tenant User Setup
All the scripts for this project are available at https://github.com/jmattmacd/O365-Tenant_to_tenant
Note – As per part three while I originally planned to do this work hence this section exists it was actually completed by the target tenant’s new provider – SoftCat1 and local IT. I will quickly outline the steps involved and a couple of scripts I had ready in case any assistance was required but this does not necessarily reflect the actual methodology. For on premise side work I will just list the work done as it was out of scope for the project.
We now have all of our users created with their @newdomain.onmicrosft.com addresses, the two migrated domains registered in the new tenant. Group membership, shared mailbox permissions and Teams membership has been created by Quest. Data in mailboxes, OneDrives, teams and office 365 groups has been migrated up to where we ran quest (lets call it a week ago for simplicity).
Our remaining tasks look like
- Set User UPNs and SMTP addresses
- Set Group SMTP Addresses
- Recreate Distribution Groups
- AD Connect
- Sync remaining data from new tenant
- Remove users from source tenant
- On Premise notes – Exchange, User profiles, etc
User UPNs and SMTP Addresses on Target
Our most urgent task is to get mailflow back up so we need to get those User UPNs and email addresses up and running. We will run through our original users export from part one to populate our users with the same UPNs and email addresses they had on the old tenant. We do this in two parts – UPN first due to slight lag in updating the UPNs and setting the new upn ads the primary smtp then using it to set the email addresses: [18-switch_new_tenant_users_upn.ps1]
($DomainName, $DomainName2 and $NewOnMicrosoftDomainName require populating)
# Connect-MSOLService
$DomainName1 = "*@thisdomain.com"
$DomainName2 = "*@thatdomain.com"
$NewOnMicrosoftDomainName = "newdomain.onmicrosoft.com"
$users = Import-csv ".\01-output-inscope_users.csv"
$i=0
ForEach ($user in $users) {
$i++
Write-Host "Rebuilding User " $i "of" $users.count $user.UserPrincipalName
$OnMSUPN = ($user.UserPrincipalName.Replace($DomainName1.Replace("*@",""),$NewOnMicrosoftDOmainName)).Replace($DomainName2.Replace("*@",""),$NewOnMicrosoftDOmainName)
Write-Host "Existing UPN" $OnMSUPN "reverting to original" -ForegroundColor yellow
Set-MsolUserPrincipalName -UserPrincipalName $OnMSUPN -NewUserPrincipalName $user.UserPrincipalName
}
Then: [19-switch_new_tenant_users_proxyaddresses.ps1]:
($DomainName, $DomainName2 and $NewOnMicrosoftDomainName require populating)
# connect-exchangeonline
$users = Import-csv ".\01-output-inscope_users.csv"
$i=0
ForEach ($user in $users) {
$i++
Write-Host "Rebuilding User " $i "of" $users.count $user.UserPrincipalName
$ProxyAddresses = $user.proxyaddresses.Split(";")
ForEach($Address in $ProxyAddresses){
If ($Address -clike "smtp*"){
Write-Host "Recreating Proxy Addresses" $Address -ForegroundColor Yellow
$arr_addresses = (Get-Mailbox -Identity $user.userprincipalname).EmailAddresses
If ($Address -notin $arr_addresses) {
$arr_addresses += $Address
write-host $arr_addresses
Set-Mailbox -Identity $user.userprincipalname -EmailAddresses $arr_addresses
}
}
If ($Address -clike "SMTP*"){
Write-Host "Recreating Proxy Addresses" $Address.Replace("SMTP","smtp") -ForegroundColor Yellow
$arr_addresses = (Get-Mailbox -Identity $user.userprincipalname).EmailAddresses
If ($Address -notin $arr_addresses) {
$arr_addresses += $Address.Replace("SMTP","smtp")
write-host $arr_addresses
Set-Mailbox -Identity $user.userprincipalname -EmailAddresses $arr_addresses
}
}
}
}
Group SMTP Addresses on Target
Next we need to get the original primary and proxy addresses rebuilt onto the migrated groups. We’ll just use the groups output from part two – .\03-output-groups_and_members.csv. The method is simlar to users, were going to add andy new secondary addresses and if there is a new primary add it and promote it: [20-add_new_tenant_group_emailaddresses.ps1]
# connect-exchangeonline
$GroupMembers = import-csv ".\03-output-groups_and_members.csv"
$groups = $GroupMembers | select GroupObjectID,GroupName,EmailAddresses -Unique
$i=0
ForEach ($Group in $Groups) {
$group.GroupName
$group.EmailAddresses
$i++
Write-Host "Rebuilding User " $i "of" $users.count $user.UserPrincipalName
$ProxyAddresses = $group.EmailAddresses.Split(";")
ForEach($Address in $ProxyAddresses){
If ($Address -clike "smtp*"){
Write-Host "Recreating Proxy Addresses" $Address -ForegroundColor Yellow
$arr_addresses = (Get-UnifiedGroup -Identity $Group.GroupObjectID).EmailAddresses
If ($Address -notin $arr_addresses) {
$arr_addresses += $Address
write-host $arr_addresses
# Set-UnifiedGroup -Identity $Group.GroupObjectID -EmailAddresses $arr_addresses
}
}
If ($Address -clike "SMTP*"){
Write-Host "Recreating Proxy Addresses" $Address.Replace("SMTP","smtp") -ForegroundColor Yellow
$arr_addresses = (Get-UnifiedGroup -Identity $Group.GroupObjectID).EmailAddresses
If ($Address -notin $arr_addresses) {
$arr_addresses = $arr_addresses.Replace("SMTP","smtp")
$arr_addresses += $Address
write-host $arr_addresses
Set-UnifiedGroup -Identity $Group.GroupObjectID -EmailAddresses $arr_addresses
}
}
}
}
Recreate Distribution Groups on target
Distribution groups are migrated by Quest so we need to recreate them then re-apply settings. We can just read in the output from part two – 06-output-distribution_group_members.CSV and 06-output-distribution_groups.CSV. First we create the groups and settings: [21-recreated_new_tenant_distribution_groups.ps1]
# connect-ExchangeOnline
$Groups = Import-Csv ".\06-output-distribution_groups_test.CSV"
$i=0
ForEach ($Group in $Groups) {
$i++
Write-Host "Rebuilding group" $i "of" $Groups.Count "-" $Group.DistroGroupName
If ($group.moderationenabled -eq "TRUE") {
$moderationenabled = 1
}
Else {
$moderationenabled = 0
}
$AcceptMessagesOnlyFrom = $Group.AcceptMessagesOnlyFrom.Split(";")
$ModeratedBy = $Group.ModeratedBy.Split(";")
$ManagedBY = $group.ManagedBy.Split(";")
$BypassModerationFromSendersOrMembers = $group.BypassModerationFromSendersOrMembers.Split(";")
If ($group.HiddenFromAddressListsEnabled -eq "TRUE") {
$HiddenFromAddressListsEnabled = 1
}
Else {
$HiddenFromAddressListsEnabled = 0
}
$AcceptMessagesOnlyFromSendersOrMembers = $Group.AcceptMessagesOnlyFromSendersOrMembers.Split(";")
New-DistributionGroup -Name $Group.Name -ModerationEnabled $moderationenabled -ModeratedBy $ModeratedBy -MemberJoinRestriction $group.MemberJoinRestriction -ManagedBy $managedby -Alias $group.Alias
Set-DistributionGroup -Identity $Group.Name -BypassModerationFromSendersOrMembers $BypassModerationFromSendersOrMembers -HiddenFromAddressListsEnabled $HiddenFromAddressListsEnabled -AcceptMessagesOnlyFromSendersOrMembers $AcceptMessagesOnlyFromSendersOrMembers
$ProxyAddresses = $group.EmailAddresses.Split(" ")
$arr_addresses =@()
ForEach($Address in $ProxyAddresses){
If ($Address -clike "smtp*"){
Write-Host "Recreating Proxy Addresses" $Address -ForegroundColor Yellow
$arr_addresses = (Get-DistributionGroup -Identity $Group.Name).EmailAddresses
If ($Address -notin $arr_addresses) {
$arr_addresses += $Address
write-host $arr_addresses
Set-DistributionGroup -Identity $Group.Name -EmailAddresses $arr_addresses
}
}
If ($Address -clike "SMTP*"){
Write-Host "Recreating Proxy Addresses" $Address.Replace("SMTP","smtp") -ForegroundColor Yellow
$arr_addresses = (Get-DistributionGroup -Identity $Group.Name).EmailAddresses
If ($Address -notin $arr_addresses) {
$arr_addresses += $Address
write-host $arr_addresses
Set-DistributionGroup -Identity $Group.Name -EmailAddresses $arr_addresses
}
}
}
}
Next we just run through the extract for the distribution group memberships: [22-add_new_tenant_distribution_group_members.ps1]
$GroupMembers = Import-CSv ".\06-output-distribution_group_members.CSV"
ForEach ($groupmember in $GroupMembers) {
Write-Host "Adding" $groupmember.Member "to" $groupmember.DistroGroupName
Add-DistributionGroupMember -Identity $groupmember.DistroGroupName -Member $groupmember.Member
}
AD Connect
I’m not running through an AD Connect build here, download it. stick an account in for both sides, pick some stuff to sync. When it runs soft-match will match up On-Prem to the new cloud accounts. I have a pretty huge AD Connect project coming up which I will document but a One to One setup is pretty simple.
Sync remaining data from new tenant
AD Connect is up, users are synced so have their proper passwords and all the info from On Prem. Mail can now be made live to the new tenant (in this example it would just be releasing it from the smart host.
Left over tasks is filling in the mail and other data generated bewteeen the migration jobs running and the switchover.
Go back in quest and follow the guide again – it needs to start right from discovery and matching as the UPNs on each side have now changed. You can of course set the date range int he migration jobs to migrate only the data since your start date.
Remove Users from Source Tenant
We kept our migrated user live with a temporary domain name, they are consuming licenses so to release them we just remove them: [22-remove migrated users.ps1]
($TempDomainNAme will require populating)
$TempDomainName = "tempdomain.com"
$Tempusers = get-msoluser -DomainName $TempDomainName -All
$i=0
ForEach ($Tempuser in $Tempusers) {
$i++
Write-Host $i.ToString() $Tempuser.UserPrincipalName
Remove-MsolUser -UserPrincipalName $Tempuser.UserPrincipalName -Force
}
On Premise notes – Exchange, User profiles, etc
So we’re done. Wasn’t that fun! There will still be work on the target tenant.
Stuff to consider is
- Resetting user mail profiles, teams profiles, onedrive sync clients and reactivation office subscription software software
- Resetting mobile devices mail, teams clients,etc
- Recreating exchange hybridisation
- Implementing retention polices for all the newly migrated data
Links
1- SoftCat – https://www.softcat.com/
Distribution groups are migrated by Quest so we need to recreate them then re-apply settings
why we need to do this?
Sorry you are right, the sentence “Distribution groups are migrated by Quest” should have read “Distribution groups are not migrated by Quest” which is why the scripts to rebuild them are here.
However Quest DOES now migrate distribution groups so you can do it in the client (although to be honest I would usually prefer the more manual method to double check things anyway)