如何将通讯组迁移到 Microsoft 365

Jacki

所有邮箱都迁移到 Exchange Online。但是,通讯组仍然位于本地,我们希望将它们移动到 Microsoft 365 以直接在 Exchange Online 中管理它们。在本文中,您将了解如何将通讯组迁移到 Microsoft 365。

当所有邮箱迁移到 Microsoft 365 中的 Exchange Online 时,您希望在云中管理通讯组。

Exchange 本地或 Exchange Online 中没有选项可将本地通讯组迁移到 Exchange Online。执行此操作的唯一方法是手动重新创建 DG 或使用 PowerShell 自动创建。

如果您只有几个 DG,那么手动是一个不错的方法。但是,如果您有很多 DG,这将花费您大量的时间,最好的选择是使用 PowerShell。

重要的:仅当您拥有 Microsoft 365 中的所有邮箱并且本地 Exchange 中不再有邮箱时,才应执行这些步骤。只要您在 Exchange 混合环境中拥有本地邮箱,就应该在本地创建通讯组。

步骤 1. 导出本地通讯组

第一步是将所有通讯组导出到 CSV 文件。

PowerShell 脚本将导出以下 DG 组类型:

  • 分布组
  • 保安组
  • 房间列表(只能使用 PowerShell 获取)

以下是 DG 在本地 Exchange 管理中心中的外观。同样,房间列表不会出现在这里。

下载 Export-DGs.ps1 PowerShell 脚本并将其放入C:脚本文件夹。该脚本会将 CSV 文件导出到C:温度文件夹。如果你没有温度文件夹,创建一个。

# V1.1
# Export-DGs.ps1
# https://www.alitajran.com/migrate-distribution-groups-to-microsoft-365/

# CSV file export path
$Csvfile = "C:tempDGs.csv"

# Get all distribution groups
$Groups = Get-DistributionGroup -ResultSize Unlimited

# Count the total number of distribution groups
$totalGroups = $Groups.Count
$currentGroupIndex = 0

# Initialize a List to store the data
$Report = [System.Collections.Generic.List[Object]]::new()

# Loop through distribution groups
foreach ($Group in $Groups) {
    $currentGroupIndex++
    $GroupDN = $Group.DistinguishedName

    # Check ManagedBy and get the primary SMTP address of managers
    $managersList = $null
    if ($group.ManagedBy) {
        $managers = foreach ($managerDN in $group.ManagedBy) {
            $recipient = Get-Recipient -Identity $managerDN -ErrorAction SilentlyContinue
            if ($recipient) {
                $recipient.PrimarySmtpAddress
            }
        }
        $managersList = $managers -join ','
    }

    # Update progress bar
    $progressParams = @{
        Activity        = "Processing Distribution Groups"
        Status          = "Processing Group $currentGroupIndex of $totalGroups"
        PercentComplete = ($currentGroupIndex / $totalGroups) * 100
    }

    Write-Progress @progressParams

    # Get required attributes directly within the output object
    $ReportLine = [PSCustomObject]@{
        DisplayName                            = $Group.DisplayName
        Name                                   = $Group.Name
        PrimarySmtpAddress                     = $Group.PrimarySmtpAddress
        EmailAddresses                         = ($Group.EmailAddresses -join ',')
        Domain                                 = $Group.PrimarySmtpAddress.ToString().Split("@")[1]
        Alias                                  = $Group.Alias
        GroupType                              = $Group.GroupType
        RecipientTypeDetails                   = $Group.RecipientTypeDetails
        Members                                = (Get-DistributionGroupMember $GroupDN -ResultSize Unlimited).Name -join ','
        MembersPrimarySmtpAddress              = (Get-DistributionGroupMember $GroupDN -ResultSize Unlimited).PrimarySmtpAddress -join ','
        ManagedBy                              = $managersList
        HiddenFromAddressLists                 = $Group.HiddenFromAddressListsEnabled
        MemberJoinRestriction                  = $Group.MemberJoinRestriction
        MemberDepartRestriction                = $Group.MemberDepartRestriction
        RequireSenderAuthenticationEnabled     = $Group.RequireSenderAuthenticationEnabled
        AcceptMessagesOnlyFrom                 = ($Group.AcceptMessagesOnlyFrom.Name -join ',')
        AcceptMessagesOnlyFromDLMembers        = ($Group.AcceptMessagesOnlyFromDLMembers -join ',')
        AcceptMessagesOnlyFromSendersOrMembers = ($Group.AcceptMessagesOnlyFromSendersOrMembers -join ',')
        ModeratedBy                            = ($Group.ModeratedBy -join ',')
        BypassModerationFromSendersOrMembers   = ($Group.BypassModerationFromSendersOrMembers -join ',')
        ModerationEnabled                      = $Group.ModerationEnabled
        SendModerationNotifications            = $Group.SendModerationNotifications
        GrantSendOnBehalfTo                    = ($Group.GrantSendOnBehalfTo.Name -join ',')
        Notes                                  = (Get-Group $GroupDN).Notes
    }
    $Report.Add($ReportLine)
}

# Clear progress bar
Write-Progress -Activity "Processing Distribution Groups" -Completed

# Sort the output by DisplayName and export to CSV file
$Report | Sort-Object DisplayName | Export-CSV -Path $Csvfile -NoTypeInformation -Encoding UTF8 #-Delimiter ";"

在 Exchange 命令行管理程序中运行脚本,将所有本地 DG 导出到 CSV 文件。

C:Scripts.Export-DGs.ps1

步骤 2. 编辑本地通讯组 CSV 文件

打开 CSV 文件DG.csvC:温度

这部分非常重要,因为 CSV 文件是后续步骤中的脚本将要处理的内容。因此,如果您没有为属性设置所有正确的值,则会出现错误。

因此,请花点时间正确填写所有内容。确保 CSV 文件位于C:温度并有名字DG.csv

以下示例说明了导入 DG 时可能出现错误的原因:

管理员可以是该组的所有者,如果你没有具有该名称的 Microsoft 365 帐户,它不会将其添加为所有者。因此,您应该在 CSV 文件中为每个通讯组添加一个用户作为所有者。假设通讯组由管理员拥有。在这些字段中填写 Microsoft 365 管理员名称。

您可以将组所有者留空,但在下一步导入 DG 并将运行脚本的管理员帐户设置为默认帐户时,您会看到错误。

步骤 3. 在 Microsoft 365 中导入通讯组

创建通讯组并保留原始通讯组的唯一方法是为组添加不同的名称。我们将在稍后阶段更改此设置。

创建通讯组并将其隐藏在全局地址列表 (GAL) 中非常重要,这样这些 DG 就不会出现在用户的组织中。检查完所有内容后,您将在最后一步中使其对用户可见。

我们将添加C-我们创建的每个通讯组的前缀。这样,我们可以轻松识别组或在必要时对它们进行排序。这C代表

下载 Import-DGs.ps1 PowerShell 脚本并将其放入C:脚本文件夹。

# V1.1
# Import-DGs.ps1
# https://www.alitajran.com/migrate-distribution-groups-to-microsoft-365/

# Path to the CSV file containing distribution group data
$Csvfile = "C:tempDGs.csv"

# Import CSV file
$GroupsData = Import-Csv -Path $Csvfile

# Connect Exchange Online
Connect-ExchangeOnline

# Iterate through each row of the CSV file
foreach ($GroupData in $GroupsData) {
    # Check if the distribution group already exists
    $ExistingGroup = Get-DistributionGroup -Identity ("C-" + $GroupData.DisplayName) -ErrorAction SilentlyContinue

    if ($ExistingGroup) {
        Write-Host "Distribution group $($ExistingGroup.DisplayName) already exists." -ForegroundColor Yellow
    }
    else {
        if ($GroupData.RecipientTypeDetails -eq "MailUniversalSecurityGroup") {
            # Construct parameters for New-DistributionGroup cmdlet
            $NewGroupParams = @{
                DisplayName        = "C-" + $GroupData.DisplayName
                Name               = "C-" + $GroupData.Name
                Alias              = "C-" + $GroupData.Alias
                PrimarySMTPAddress = "C-" + $GroupData.PrimarySmtpAddress
                Type               = "Security"
            }

            # Create a new distribution group
            $NewGroup = New-DistributionGroup @NewGroupParams

            # Construct parameters for Set-DistributionGroup cmdlet
            $SetGroupParams = @{
                Identity                           = $NewGroup.DisplayName
                HiddenFromAddressListsEnabled      = $True
                MemberJoinRestriction              = $GroupData.MemberJoinRestriction
                MemberDepartRestriction            = $GroupData.MemberDepartRestriction
                RequireSenderAuthenticationEnabled = [System.Convert]::ToBoolean($GroupData.RequireSenderAuthenticationEnabled)
                Description                        = if (-not [string]::IsNullOrWhiteSpace($GroupData.Notes)) { $GroupData.Notes } else { $null }
                ManagedBy                          = $GroupData.ManagedBy -split ','
            }

            # Set additional properties
            Set-DistributionGroup @SetGroupParams

            # Display success message
            Write-Host "Distribution group $($NewGroup.DisplayName) created successfully." -ForegroundColor Green
        }
        elseif ($GroupData.RecipientTypeDetails -eq "MailUniversalDistributionGroup") {
            # Construct parameters for New-DistributionGroup cmdlet
            $NewGroupParams = @{
                DisplayName        = "C-" + $GroupData.DisplayName
                Name               = "C-" + $GroupData.Name
                Alias              = "C-" + $GroupData.Alias
                PrimarySMTPAddress = "C-" + $GroupData.PrimarySmtpAddress
            }

            # Create a new distribution group
            $NewGroup = New-DistributionGroup @NewGroupParams

            # Construct parameters for Set-DistributionGroup cmdlet
            $SetGroupParams = @{
                Identity                           = $NewGroup.DisplayName
                HiddenFromAddressListsEnabled      = $True
                MemberJoinRestriction              = $GroupData.MemberJoinRestriction
                MemberDepartRestriction            = $GroupData.MemberDepartRestriction
                RequireSenderAuthenticationEnabled = [System.Convert]::ToBoolean($GroupData.RequireSenderAuthenticationEnabled)
                Description                        = if (-not [string]::IsNullOrWhiteSpace($GroupData.Notes)) { $GroupData.Notes } else { $null }
                ManagedBy                          = $GroupData.ManagedBy -split ','
            }

            # Set additional properties
            Set-DistributionGroup @SetGroupParams

            # Display success message
            Write-Host "Distribution group $($NewGroup.DisplayName) created successfully." -ForegroundColor Green
        }
        elseif ($GroupData.RecipientTypeDetails -eq "RoomList") {
            # Construct parameters for New-DistributionGroup cmdlet
            $NewGroupParams = @{
                DisplayName        = "C-" + $GroupData.DisplayName
                Name               = "C-" + $GroupData.Name
                Alias              = "C-" + $GroupData.Alias
                PrimarySMTPAddress = "C-" + $GroupData.PrimarySmtpAddress
                Roomlist           = $True
            }

            # Create a new distribution group
            $NewGroup = New-DistributionGroup @NewGroupParams

            # Construct parameters for Set-DistributionGroup cmdlet
            $SetGroupParams = @{
                Identity                           = $NewGroup.DisplayName
                HiddenFromAddressListsEnabled      = $True
                MemberJoinRestriction              = $GroupData.MemberJoinRestriction
                MemberDepartRestriction            = $GroupData.MemberDepartRestriction
                RequireSenderAuthenticationEnabled = [System.Convert]::ToBoolean($GroupData.RequireSenderAuthenticationEnabled)
                Description                        = if (-not [string]::IsNullOrWhiteSpace($GroupData.Notes)) { $GroupData.Notes } else { $null }
                ManagedBy                          = $GroupData.ManagedBy -split ','
            }

            # Set additional properties
            Set-DistributionGroup @SetGroupParams

            # Display success message
            Write-Host "Distribution group $($NewGroup.DisplayName) created successfully." -ForegroundColor Green
        }
    }
}

以管理员身份运行 PowerShell 并连接到 Exchange Online PowerShell。

Connect-ExchangeOnline

在 Exchange Online PowerShell 中运行脚本,使用以下命令从 CSV 文件创建 DG:C-Exchange Online – Microsoft 365 中的前缀。

C:Scripts.Import-DGs.ps1

登录到交易所管理中心。验证C-通讯组已成功创建通讯组列表并在支持邮件的安全性

单击一个总干事并选择一般的。验证值是否设置成功。

点击会员并验证DG所有者是否添加成功。

点击设置并验证“从全局地址列表中隐藏该组”值是否已启用。

步骤 4. 将成员添加到通讯组

下载 Add-MembersDGs.ps1 PowerShell 脚本并将其放入C:脚本文件夹。

# V1.0
# Add-MembersDGs.ps1
# https://www.alitajran.com/migrate-distribution-groups-to-microsoft-365/

# Path to the CSV file containing distribution group data
$Csvfile = "C:tempDGs.csv"

# Import CSV file
$GroupsData = Import-Csv -Path $Csvfile

# Iterate through each row of the CSV file
foreach ($GroupData in $GroupsData) {
    # Check if the distribution group already exists
    $ExistingGroup = Get-DistributionGroup -Identity ("C-" + $GroupData.DisplayName) -ErrorAction SilentlyContinue

    if ($null -eq $ExistingGroup) {
        Write-Host "Distribution group $($GroupData.DisplayName) does not exist." -ForegroundColor Yellow
    }
    else {
        # Check if MemberPrimarySmtpAddress is provided and not empty
        if (-not [string]::IsNullOrEmpty($GroupData.MembersPrimarySmtpAddress)) {
            # Split the member email addresses if there are multiple addresses
            $Members = $GroupData.MembersPrimarySmtpAddress -split ","
            foreach ($Member in $Members) {
                # Trim whitespace from each member's email address
                $Member = $Member.Trim()

                Write-Host "Attempting to add member $Member to $($ExistingGroup.DisplayName)." -ForegroundColor Cyan
                
                # Add member to the distribution group
                try {
                    Add-DistributionGroupMember -Identity $ExistingGroup.PrimarySmtpAddress -Member $Member -BypassSecurityGroupManagerCheck -ErrorAction Stop
                    Write-Host "Member $Member added to $($ExistingGroup.DisplayName)." -ForegroundColor Green
                }
                catch {
                    Write-Host "Failed to add member $Member to $($ExistingGroup.DisplayName). $_" -ForegroundColor Red
                }
            }
        }
        else {
            Write-Host "No member provided for $($ExistingGroup.DisplayName)." -ForegroundColor Yellow
        }
    }
}

在 Exchange Online PowerShell 中运行脚本,将 CSV 文件中的成员添加到具有前缀的 DGC-在 Exchange Online – Microsoft 365 中。

C:Scripts.Add-MembersDGs.ps1

单击 DG,然后单击会员。验证成员是否出现在C-分销集团。

步骤 5. 将 DG 移至单独的 OU

如果您没有 Exchange 混合环境,可以跳过此步骤。但最有可能的是,您已在本地和 Microsoft 365 之间运行并同步 Microsoft Entra Connect Sync。

如果通讯组位于不同的 OU 中,请使用以下脚本将它们全部移动到新的 OU。当您在下一步中禁用 OU 与 Microsoft Entra ID 的同步时,这将使管理变得更加容易。

改变6号线到您也想要将 DG 移动到的 OU。

下载 Move-DGs.ps1 PowerShell 脚本并将其放入C:脚本文件夹。

# V1.0
# Move-DGs.ps1
# https://www.alitajran.com/migrate-distribution-groups-to-microsoft-365/

# Specify distinguished name (DN) of target OU
$TargetOU = "OU=DG,OU=Groups,OU=Company,DC=exoip,DC=local"

# Get all distribution groups
$DistributionGroups = Get-DistributionGroup -ResultSize Unlimited

# Go through each distribution group
foreach ($DistributionGroup in $DistributionGroups) {
    # Move distribution group to target OU
    Move-ADObject -Identity $DistributionGroup.DistinguishedName -TargetPath $TargetOU -Confirm:$false
    Write-Host "Distribution group $($DistributionGroup.DisplayName) moved to $TargetOU." -ForegroundColor Green
}

在 PowerShell(本地)中运行脚本以将 DG 移动到总干事Active Directory 中的组织单位。

C:Scripts.Move-DGs.ps1

完成后,打开Active Directory 用户和计算机并验证 DG 是否出现在 OU 中总干事

步骤 6. 取消同步本地通讯组

登录 Microsoft Entra Connect 同步服务器。接下来,启动Azure AD 连接工具。

取消选中总干事组织单位 (OU) 与所有通讯组,以便它不再同步到 Microsoft 365。

如果将 DG 移至已取消同步到 Microsoft 365 的 OU,则必须强制同步 Microsoft Entra Connect 或等待最多 30 分钟,然后才会自动运行同步。

Start-ADSyncSyncCycle -PolicyType Delta

等待十分钟,检查所有原始本地通讯组是否不再出现在 Microsoft 365 中。只会显示云通讯组。在继续下一步之前,这一点非常重要。

步骤 7. 最终确定通讯组

您现在可以成功运行下面的脚本,这将删除C-来自云通讯组的前缀和添加主 SMTP 地址和所有辅助地址到云分发组。它还会在从 CSV 文件获取的 DG 上设置从地址列表中隐藏的启用值。

下载 Finalize-DGs.ps1 PowerShell 脚本并将其放入C:脚本文件夹。

另请阅读:使用 PowerShell 将 Microsoft 365 通讯组成员导出到 CSV

# V1.0
# Finalize-DGs.ps1
# https://www.alitajran.com/migrate-distribution-groups-to-microsoft-365/

# Path to the CSV file containing distribution group data
$Csvfile = "C:tempDGs.csv"

# Import CSV file
$GroupsData = Import-Csv -Path $Csvfile

# Iterate through each row of the CSV file
foreach ($GroupData in $GroupsData) {
    # Check if the distribution group already exists
    $ExistingGroup = Get-DistributionGroup -Identity ("C-" + $GroupData.DisplayName) -ErrorAction SilentlyContinue

    if ($ExistingGroup) {
        Write-Host "Distribution group $($ExistingGroup.DisplayName) exists. Proceed." -ForegroundColor Green

        # Construct parameters for Set-DistributionGroup cmdlet
        $SetGroupParams = @{
            Identity                      = $ExistingGroup.DisplayName
            DisplayName                   = $GroupData.DisplayName.Replace("C-", "")
            Name                          = $GroupData.Name.Replace("C-", "")
            Alias                         = $GroupData.Alias.Replace("C-", "")
            EmailAddresses                = ($GroupData.EmailAddresses -split ',')
            HiddenFromAddressListsEnabled = [System.Convert]::ToBoolean($GroupData.HiddenFromAddressLists)
        }
        try {
            # Set additional properties
            Set-DistributionGroup @SetGroupParams -ErrorAction Stop

            # Display success message
            Write-Host "Distribution group $($ExistingGroup.DisplayName) updated successfully to $($GroupData.DisplayName)." -ForegroundColor Green
        }

        catch {
            Write-Host "Error updating distribution group $($ExistingGroup.DisplayName): $_" -ForegroundColor Red
        }
    }
    else {
        Write-Host "Distribution group C-$($GroupData.DisplayName) does not exist. Skipping update." -ForegroundColor Red
    }
}

在 Exchange Online PowerShell 中运行脚本以删除C-来自所有 DG 的前缀并导入所有电子邮件地址。

C:Scripts.Finalize-DGs.ps1

在 Exchange 管理中心 (Microsoft 365) 中验证所有通讯组是否正确显示,且没有C-前缀。

检查电子邮件地址是否已成功添加到通讯组。

验证“从全局地址列表中隐藏此组”值是否正确地从 CSV 文件中获取并在通讯组上设置。

步骤 8. 测试发送至通讯组的邮件流

将电子邮件发送到您创建的几个通讯组,并验证电子邮件是否已成功发送到组中的收件人。

就是这样!

结论

您了解了如何将通讯组迁移到 Microsoft 365。执行此操作的唯一方法是在 Microsoft 365 管理中心或使用 PowerShell 脚本手动重新创建它们。没有其他方法。

您喜欢这篇文章吗?您可能还喜欢使用 PowerShell 将 Microsoft 365 通讯组成员导出到 CSV。不要忘记关注我们并分享这篇文章。