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
}