Forum Discussion
Migrating On-Prem Distribution Groups to Exchange Online in Hybrid Mode
######## Global Variables ############ Set-Location -Path $env:USERPROFILE\Documents #Get-PSSession | Remove-PSSession $UserCredential = Get-Credential $ListOfGroupsToMigrate = Import-csv .\GroupMigration.csv ####################################### $ListOfGroupsToMigrate | ForEach-Object { $SingleGroupToMigratePSMTP = $_.GroupEmailAddress $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ExhangeServerFQDN.com/PowerShell/ -Authentication Kerberos -Credential $UserCredential Import-PSSession $Session -Allowclobber $distrotomovedetails = Get-DistributionGroup -Identity $SingleGroupToMigratePSMTP $distrotomovedetails | Export-csv .\singlegroupdetailsbeforedelete.csv -NoTypeInformation $distrotomovedetails | ForEach-Object{ $DistributionGroupName = $_.PrimarySmtpAddress Get-DistributionGroupMember -Identity $DistributionGroupName | ForEach-Object{ [PSCustomObject]@{ DistributionGroup = $DistributionGroupName MemberName = $_.DisplayName EmailAddress = $_.PrimarySmtpAddress #Other recipient properties here } } } | Export-csv .\GroupmembersBeforeDel.csv -NoTypeInformation ######################################### $groupowner = $distrotomovedetails.ManagedBy $GroupOwnerCorrected = $groupowner.split('/')[-1] $GroupOwnerCorrected.ToString() $Managedby = Get-ADuser -Filter "displayName -eq '$GroupOwnerCorrected'" $distrotomovedetails | fl # Extract All Email Addresses for single group one per line so you can easily add back in EXO $addresses = @() Foreach ($mbx in $distrotomovedetails) { Foreach ($address in $mbx.EmailAddresses) { $obj = "" | Select-Object Identity,Alias,EmailAddress,RecipientType $obj.Alias = $mbx.Alias $obj.Identity = $mbx.Identity $obj.RecipientType = $mbx.RecipientType $obj.EmailAddress = $address.ToString().SubString(0) $addresses += $obj } } $addresses | Export-Csv .\SingleDistroGroupsmtpaddresses.csv -NoTypeInformation $addresses #Remove OnPremises Group Remove-DistributionGroup -Identity $distrotomovedetails.Identity -Confirm:$false -Verbose Start-Sleep 120 #Create On-Premises Contact $ExternalEmailAddress = $distrotomovedetails.Alias + "@tenant.mail.onmicrosoft.com" New-MailContact -DisplayName $distrotomovedetails.DisplayName -Alias $distrotomovedetails.Alias -ExternalEmailAddress $ExternalEmailAddress -OrganizationalUnit "OU=Contacts,OU=Exchange Accounts,DC=lge-mdr,DC=com" Set-MailContact -Identity $distrotomovedetails.PrimarySmtpAddress -HiddenFromAddressListsEnabled $true #Close Session with OnPremise Exchange Get-PSSession | Remove-PSSession -Verbose #Connect EXO Import-Module ExchangeOnlineManagement Connect-ExchangeOnline -Credential $UserCredential Write-Host -ForgroundColor Cyan "Running AAD Connect Sync" #Remotely Run AAD Connect Delta Sync $session = New-PSSession -ComputerName FQDNAADServer.com Invoke-Command -Session $session -ScriptBlock {Import-Module -Name 'ADSync'} Invoke-Command -Session $session -ScriptBlock {Start-ADSyncSyncCycle -PolicyType Delta} Remove-PSSession $session #Pause until AAD Connect Sync can run and Azure AD to catch up Write-Host -ForgroundColor Green "Pausing for AAD Connect to run and then we check EXO for the group" function Start-Sleep($seconds) { $doneDT = (Get-Date).AddSeconds($seconds) while($doneDT -gt (Get-Date)) { $secondsLeft = $doneDT.Subtract((Get-Date)).TotalSeconds $percent = ($seconds - $secondsLeft) / $seconds * 100 Write-Progress -Activity "Sleeping" -Status "Sleeping..." -SecondsRemaining $secondsLeft -PercentComplete $percent [System.Threading.Thread]::Sleep(500) } Write-Progress -Activity "Sleeping" -Status "Sleeping..." -SecondsRemaining 0 -Completed } Start-Sleep 200 Write-host -ForegroundColor Cyan "Verifing the group is gone from Azure AD, command will proceed once group is not showing in EXO" $distrotomovedetails.PrimarySmtpAddress while($GetDistroFinder -ne $null){ Write-Host -ForegroundColor Cyan "Checking EXO for the old synced Distro Group" $GetDistroFinder = Get-DistributionGroup -Identity $distrotomovedetails.PrimarySmtpAddress Start-Sleep 10 } Write-Host -ForegroundColor Green "Group Appears to have been removed please verify on Azure AD" Read-Host -Prompt "Hit Enter To Proceed" ############ Recreate Group in the cloud ########################################################################################################################################### Write-Host -ForegroundColor Cyan "Recreating the group in EXO" #Create the EXO Distro group New-DistributionGroup -DisplayName $distrotomovedetails.DisplayName -Alias $distrotomovedetails.Alias -Name $distrotomovedetails.Name -MemberDepartRestriction $distrotomovedetails.MemberDepartRestriction -MemberJoinRestriction $distrotomovedetails.MemberJoinRestriction -PrimarySmtpAddress $distrotomovedetails.PrimarySmtpAddress -RequireSenderAuthenticationEnabled:$false -ManagedBy $Managedby.UserPrincipalName -Verbose #Add additional SMTP and x500 addresses to the group. Write-Host -ForegroundColor Green "Adding SMTP and x500 Addresses Back to" $distroprimarysmtp $EmailAddressesToAdd = Import-Csv .\SingleDistroGroupsmtpaddresses.csv $EmailAddressesToAdd | ForEach-Object { $AliasOfGroup = $_.Alias $AddressToAdd = $_.EmailAddress $x500 = "x500:"+ $distrotomovedetails.LegacyExchangeDN $GroupLookup = Get-DistributionGroup -Identity $AliasOfGroup Set-DistributionGroup -Identity $GroupLookup.Identity -EmailAddresses @{Add=$AddressToAdd} -Verbose } #Add Group Members Back to Group Write-Host -ForegroundColor Magenta "Adding Members Back to Group" $GroupMembers = Import-Csv .\GroupmembersBeforeDel.csv $GroupMembers | ForEach-Object { $Distroprimarysmtp = $_.DistributionGroup $MemberPrimarySMTP = $_.EmailAddress Write-Host "Adding $memberprimarysmtp to $Distroprimarysmtp" Add-DistributionGroupMember -Identity $Distroprimarysmtp -Member $MemberPrimarySMTP } #Confirm Group Get-DistributionGroup $distroprimarysmtp | Select Alias,PrimarySmtpAddress,ManagedBy,IsDirsynced,WhenCreated | FT }
Thanks for the script, but the $Session string has http://ExchangeServerFQDN.com as a session option, and I no longer have an on-prem exchange server to connect to, so the script doesn't flow. I have a feeling I'm going to have to bite the bullet and start transferring them all manually.
- Gregory HallJan 26, 2024Copper Contributor
######## Global Variables ############
Set-Location -Path $env:USERPROFILE\Documents
#Get-PSSession | Remove-PSSession
$UserCredential = Get-Credential
$ListOfGroupsToMigrate = Import-csv .\GroupMigration.csv
#######################################$ListOfGroupsToMigrate | ForEach-Object {
$SingleGroupToMigratePSMTP = $_.GroupEmailAddress# Get the group details from Active Directory
$group = Get-ADGroup -Filter "mail -eq '$SingleGroupToMigratePSMTP'"
$groupMembers = Get-ADGroupMember -Identity $group | Get-ADUser | Select-Object DisplayName, UserPrincipalName# Export group details
$group | Select-Object Name, GroupScope, GroupCategory | Export-Csv .\singlegroupdetailsbeforedelete.csv -NoTypeInformation# Export group members
$groupMembers | Export-Csv .\GroupmembersBeforeDel.csv -NoTypeInformation# Managed by details
$groupOwner = (Get-ADGroup $group -Properties ManagedBy).ManagedBy
$Managedby = Get-ADUser -Identity $groupOwner# Connect to Exchange Online
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -Credential $UserCredential# Recreate the group in Exchange Online
$newGroupParams = @{
DisplayName = $group.Name
Alias = $group.SamAccountName
Name = $group.Name
PrimarySmtpAddress = $group.mail
RequireSenderAuthenticationEnabled = $false
ManagedBy = $Managedby.UserPrincipalName
}
New-DistributionGroup @newGroupParams -Verbose# Add group members in Exchange Online
foreach ($member in $groupMembers) {
Add-DistributionGroupMember -Identity $group.mail -Member $member.UserPrincipalName
}# Verify group creation
Get-DistributionGroup $group.mail | Select Alias,PrimarySmtpAddress,ManagedBy,IsDirsynced,WhenCreated | Format-Table
}