Copy Members From One DL to Another

This commit is contained in:
AdminDroid 2025-04-09 10:24:55 +05:30
parent 4a646ed5aa
commit c777e13869

View File

@ -0,0 +1,211 @@
<#
=============================================================================================
Name: Copy Members from One Distribution List to Another
Version: 1.0
Website: o365reports.com
Script Highlights:
~~~~~~~~~~~~~~~~~
1. Fetches members and owners from the source DL and adds them to the target DL.
2. Helps to copy DL members from one to another. (if not present already).
3. Can copy managers from one DL to another. (if not present already).
4. The script automatically verifies and installs the Exchange Online PowerShell module (if not installed) upon your confirmation.
5. Exports an output log file in TXT format that shows the result of the operation.
6. The script can be executed with MFA enabled account too.
7. The script supports certificate-based authentication (CBA) too.
8. The script is schedular-friendly.
For detailed Script execution: https://o365reports.com/2025/04/08/copy-members-from-one-distribution-list-to-another/
============================================================================================
#>
Param
(
[Parameter(Mandatory = $False)]
[string]$SourceGroup=$Null,
[string]$TargetGroup=$Null,
[Switch]$CopyOwnersOnly,
[Switch]$CopyMembersOnly,
[string]$UserName=$Null,
[string]$Password=$Null,
[string]$Organization,
[string]$ClientId,
[string]$CertificateThumbPrint
)
#Connection module
Function Connect_Module {
#Check for Exchange Online module installation
$ExchangeModule = Get-Module ExchangeOnlineManagement -ListAvailable
if($ExchangeModule.count -eq 0) {
Write-Host ExchangeOnline module is not available -ForegroundColor Yellow
$confirm = Read-Host Do you want to Install ExchangeOnline module? [Y] Yes [N] No
if($confirm -match "[Yy]") {
Write-Host "Installing ExchangeOnline module ..."
Install-Module ExchangeOnlineManagement -Repository PSGallery -AllowClobber -Force -Scope CurrentUser
Import-Module ExchangeOnlineManagement
}
else {
Write-Host "ExchangeOnline Module is required. To Install ExchangeOnline module use 'Install-Module ExchangeOnlineManagement' cmdlet."
Exit
}
}
#Connect Exchange Online
Write-Host "`nConnecting Exchange Online module ..."
if(($UserName -ne "") -and ($Password -ne "")) {
$SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force
$Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword
Connect-ExchangeOnline -Credential $Credential
}
elseif($Organization -ne "" -and $ClientId -ne "" -and $CertificateThumbprint -ne "") {
Connect-ExchangeOnline -AppId $ClientId -CertificateThumbprint $CertificateThumbprint -Organization $Organization -ShowBanner:$false
}
else {
Connect-ExchangeOnline -ShowBanner:$false
}
}
#Output log function
Function Log-Data {
param ([string]$UserName,$UserType,$Status,$Message = "")
$Result = if ($Status -eq "Failed") {
"- Failed to copy $UserName as a $UserType to the target group. Error: $Message"
} elseif(($Status -eq "Already a Member") -or ($Status -eq"Already a Owner")){
"- Skipped adding $UserName as $UserType. The user is already a $UserType in the target group."
} else {
"- $UserName has been successfully copied as $UserType to the target group."
}
Add-Content -Path $OutputLog -Value $Result
}
$Script:CopiedMembersCount = 0
$Script:CopiedOwnersCount = 0
$Script:ExistingMembersCount = 0
$Script:ExistingOwnersCount = 0
#Funtion to copy members only to another distribution group
Function Copy_Members
{
$ProcessedUserCount=0
$SourceGroupMemberNames = Get-DistributionGroupMember -Identity $SourceGroup
$TargetGroupMemberNames = Get-DistributionGroupMember -Identity $TargetGroup
ForEach($SourceGroupMemberName in $SourceGroupMemberNames)
{
$SourceMemberName = $SourceGroupMemberName.DisplayName
Write-Progress -Activity "Copying Members From $SourceGroup to $TargetGroup " -Status "Processed member Count : $ProcessedUserCount" -CurrentOperation " Currently Processing Member $($SourceMemberName)"
Try
{
if($SourceGroupMemberName.Guid -in $TargetGroupMemberNames.Guid){
Log-Data -UserName $SourceGroupMemberName.DisplayName -UserType "member" -Status "Already a Member"
$Script:ExistingMembersCount++
}
else{
Add-DistributiongroupMember -Identity $TargetGroup -Member $($SourceGroupMemberName.DistinguishedName) -ErrorAction Stop
Log-Data -UserName $SourceGroupMemberName.DisplayName -UserType "member" -Status "Successfully Copied"
$Script:CopiedMembersCount++
}
}
Catch
{
Log-Data -UserName $Member.DisplayName -UserType "member" -Status "Failed" -Message $_.Exception.Message
}
$ProcessedUserCount++
}
}
#Funtion to copy owners only to another distribution group
Function Copy_Owners
{
$ProcessedUserCount=0
$SourceGroupOwnerNames = Get-DistributionGroup -Identity $SourceGroup | Select -ExpandProperty ManagedBy
$TargetGroupOwnerNames = Get-DistributionGroup -Identity $TargetGroup | Select -ExpandProperty ManagedBy
ForEach($SourceGroupOwnerName in $SourceGroupOwnerNames)
{
$Owner = Get-Recipient -Identity $SourceGroupOwnerName
Write-Progress -Activity "Copying owner From $SourceGroup To $TargetGroup " -Status "Processed owner Count: $ProcessedUserCount" -CurrentOperation "Currently Processing Owner $($Owner.Displayname)"
try{
if($SourceGroupOwnerName -in $TargetGroupOwnerNames)
{
Log-Data -UserName $Owner.DisplayName -UserType "owner" -Status "Already a Owner"
$Script:ExistingOwnersCount++
}
else
{
Set-DistributionGroup -Identity $TargetGroup -ManagedBy @{Add="$($Owner.PrimarySmtpAddress)"} -ErrorAction Stop
Log-Data -UserName $Owner.DisplayName -UserType "owner" -Status "Successfully Copied"
$Script:CopiedOwnersCount++
}
}
catch{
Log-Data -UserName $Owner.DisplayName -UserType "owner" -Status "Failed" -Message $_.Exception.Message
}
$ProcessedUserCount++
}
}
#Function to return output log file
Function OpenOutputLog
{
Write-Host "`nSummary of Distribution List Membership Changes" -ForegroundColor DarkYellow
Write-Host "`n$($ExistingMembersCount) member(s) and $($ExistingOwnersCount) owner(s) from source DL is already present in target DL."
#Write-Host "`n$($ExistingMembersCount) members and $($ExistingOwnersCount) owners already present in both distribution lists."
Write-Host "`nThe script successfully copied $($CopiedMembersCount) members and $($CopiedOwnersCount) owners to the target DL."
#Open Output file after execution
If((Test-Path -Path $OutputLog) -eq "True")
{
Write-Host `nThe log file available in :`n -NoNewline -ForegroundColor Yellow
Write-Host $OutputLog
Write-Host `n~~ Script prepared by AdminDroid Community ~~`n -ForegroundColor Green
Write-Host "~~ Check out " -NoNewline -ForegroundColor Green; Write-Host "admindroid.com" -ForegroundColor Yellow -NoNewline; Write-Host " to get access to 1800+ Microsoft 365 reports. ~~" -ForegroundColor Green `n`n
$Prompt = New-Object -ComObject wscript.shell
$UserInput = $Prompt.popup("Do you want to open log file?",` 0,"Open log File",4)
If($UserInput -eq 6)
{
Invoke-Item "$OutputLog"
}
}
}
#Execution starts here
Connect_Module
If($SourceGroup -eq "" -or ($TargetGroup -eq ""))
{
If($SourceGroup -eq "")
{
$SourceGroup = Read-Host "`nEnter the source DL mail Id"
}
If($TargetGroup -eq "")
{
$TargetGroup = Read-Host "`nEnter the target DL mail Id"
}
}
$Location = Get-Location
$OutputLog="$Location\Copy_DL_Membership_Log_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).txt"
If($CopyOwnersOnly.IsPresent)
{
Copy_Owners
}
ElseIf($CopyMemberOnly.IsPresent)
{
Copy_Members
}
Else
{
Copy_Owners
Copy_Members
}
#Open output log file
OpenOutputLog
#Disconnect Exchange Online session
Disconnect-ExchangeOnline -Confirm:$false | Out-Null