-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCopyMembersandOwnersfromDL.ps1
More file actions
211 lines (190 loc) · 8.5 KB
/
CopyMembersandOwnersfromDL.ps1
File metadata and controls
211 lines (190 loc) · 8.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
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