网站搜索

如何将通讯组迁移到 Microsoft 365


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

将本地通讯组迁移到 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:\scripts 文件夹中。该脚本会将 CSV 文件导出到 C:\temp 文件夹。如果您没有 Temp 文件夹,请创建一个。

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

# CSV file export path
$Csvfile = "C:\temp\DGs.csv"

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

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

# Initialize an empty array for output
$Output = @()

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

    # 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
    $Output += [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                              = ($Group.ManagedBy.Name -join ',')
        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
    }
}

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

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

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

C:\Scripts\.\Export-DGs.ps1

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

打开 C:\temp 中的 CSV 文件 DGs.csv。

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

因此,请花点时间正确填写所有内容。确保 CSV 文件位于 C:\temp 中且名称为 DGs.csv

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

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

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

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

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

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

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

下载 Import-DGs.ps1 PowerShell 脚本并将其放置在 C:\scripts 文件夹中。

# V1.0
# V1.1 - Fixed errors in PowerShell ISE
# Import-DGs.ps1
# https://www.alitajran.com/migrate-distribution-groups-to-microsoft-365/

# Path to the CSV file containing distribution group data
$Csvfile = "C:\temp\DGs.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 中运行脚本,从 Exchange Online - Microsoft 365 中带有 C- 前缀的 CSV 文件创建 DG。

C:\Scripts\.\Import-DGs.ps1

登录 Exchange 管理中心。验证是否已在通讯组列表和启用邮件的安全性中成功创建C-通讯组。

单击DG并选择常规。验证值是否设置成功。

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

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

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

下载 Add-MembersDGs.ps1 PowerShell 脚本并将其放置在 C:\scripts 文件夹中。

# 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:\temp\DGs.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 文件中的成员添加到 Exchange Online - Microsoft 365 中带有前缀 C- 的 DG。

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:\scripts 文件夹中。

# 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 中的 DG 组织单位。

C:\Scripts\.\Move-DGs.ps1

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

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

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

取消选中包含所有通讯组的 DG 组织单位 (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:\scripts 文件夹中。

# 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:\temp\DGs.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 中运行脚本以从所有 DG 中删除 C- 前缀并导入所有电子邮件地址。

C:\Scripts\.\Finalize-DGs.ps1

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

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

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

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

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

就是这样!

了解更多:删除组织中最后一个 Exchange Server »

结论

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

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

相关文章