122 lines
4.6 KiB
PowerShell
122 lines
4.6 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Copies group memberships from one user to another in Microsoft 365 with detailed logging.
|
|
.DESCRIPTION
|
|
This script connects to Exchange Online and copies all group memberships (both Microsoft 365 Groups and Distribution Lists)
|
|
from a source user to a destination user, with comprehensive logging.
|
|
.NOTES
|
|
Author : Kyle Pope
|
|
File Name : Copy-User365Groups.ps1
|
|
Prerequisite : ExchangeOnlineManagement PowerShell module
|
|
#>
|
|
|
|
# Input parameters
|
|
$source = "user@domain.com.au"
|
|
$destination = "user@domain.com.au"
|
|
|
|
# Logging configuration
|
|
$logFolder = "C:\Logs\365UserCopy"
|
|
$logDate = Get-Date -Format "ddMMyyyy_HHmm"
|
|
$logFile = "$logFolder\365UserGroupCopy_$logDate.log"
|
|
|
|
# Create log directory if it doesn't exist
|
|
if (-not (Test-Path $logFolder)) {
|
|
New-Item -ItemType Directory -Path $logFolder -Force | Out-Null
|
|
}
|
|
|
|
# Function for consistent logging
|
|
function Write-Log {
|
|
param (
|
|
[string]$Message,
|
|
[string]$Level = "INFO"
|
|
)
|
|
|
|
$timestamp = Get-Date -Format "dd-MM-yyyy HH:mm:ss"
|
|
$logEntry = "[$timestamp] [$Level] $Message"
|
|
Write-Output $logEntry | Out-File -FilePath $logFile -Append -Encoding utf8
|
|
|
|
# Also display to console
|
|
switch ($Level) {
|
|
"ERROR" { Write-Host $logEntry -ForegroundColor Red }
|
|
"WARNING" { Write-Host $logEntry -ForegroundColor Yellow }
|
|
"SUCCESS" { Write-Host $logEntry -ForegroundColor Green }
|
|
default { Write-Host $logEntry }
|
|
}
|
|
}
|
|
|
|
try {
|
|
# Start logging
|
|
Write-Log "Script started"
|
|
Write-Log "Source user: $source"
|
|
Write-Log "Destination user: $destination"
|
|
|
|
# Connect to Exchange Online
|
|
Write-Log "Connecting to Exchange Online..."
|
|
Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop
|
|
Write-Log "Successfully connected to Exchange Online"
|
|
|
|
# Get source user details
|
|
Write-Log "Retrieving source user information..."
|
|
$sourceMailbox = Get-EXOMailbox $source -ErrorAction Stop
|
|
if (-not $sourceMailbox) {
|
|
throw "Source user $source not found"
|
|
}
|
|
$dn = $sourceMailbox.DistinguishedName
|
|
Write-Log "Source user found: $($sourceMailbox.PrimarySmtpAddress) (DN: $dn)"
|
|
|
|
# Process Microsoft 365 Groups
|
|
Write-Log "Processing Microsoft 365 Groups..."
|
|
$o365Groups = Get-EXORecipient -Filter "Members -eq '$dn'" -RecipientTypeDetails GroupMailbox -ErrorAction Stop
|
|
Write-Log "Found $($o365Groups.Count) Microsoft 365 Groups for source user"
|
|
|
|
foreach ($group in $o365Groups) {
|
|
try {
|
|
Write-Log "Adding $destination to group: $($group.Name) ($($group.PrimarySmtpAddress))"
|
|
Add-UnifiedGroupLinks -Identity $group.Name -LinkType Member -Links $destination -ErrorAction Stop
|
|
Write-Log -Level "SUCCESS" "Successfully added $destination to Microsoft 365 Group: $($group.Name)"
|
|
}
|
|
catch {
|
|
Write-Log -Level "ERROR" "Failed to add $destination to Microsoft 365 Group $($group.Name): $_"
|
|
}
|
|
}
|
|
|
|
# Process Distribution Groups
|
|
Write-Log "Processing Distribution Groups..."
|
|
$distGroups = Get-EXORecipient -Filter "Members -eq '$dn'" -RecipientTypeDetails MailUniversalDistributionGroup -ErrorAction Stop
|
|
Write-Log "Found $($distGroups.Count) Distribution Groups for source user"
|
|
|
|
foreach ($group in $distGroups) {
|
|
try {
|
|
Write-Log "Adding $destination to distribution group: $($group.Name) ($($group.PrimarySmtpAddress))"
|
|
Add-DistributionGroupMember -Identity $group.Name -Member $destination -ErrorAction Stop
|
|
Write-Log -Level "SUCCESS" "Successfully added $destination to Distribution Group: $($group.Name)"
|
|
}
|
|
catch {
|
|
Write-Log -Level "ERROR" "Failed to add $destination to Distribution Group $($group.Name): $_"
|
|
}
|
|
}
|
|
|
|
# Summary report
|
|
Write-Log "Processing complete"
|
|
Write-Log "SUMMARY:"
|
|
Write-Log " Microsoft 365 Groups processed: $($o365Groups.Count)"
|
|
Write-Log " Distribution Groups processed: $($distGroups.Count)"
|
|
}
|
|
catch {
|
|
Write-Log -Level "ERROR" "Script encountered an error: $_"
|
|
Write-Log -Level "ERROR" "Error details: $($_.ScriptStackTrace)"
|
|
}
|
|
finally {
|
|
# Disconnect from Exchange Online
|
|
try {
|
|
Write-Log "Disconnecting from Exchange Online..."
|
|
Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
|
|
Write-Log "Disconnected from Exchange Online"
|
|
}
|
|
catch {
|
|
Write-Log -Level "WARNING" "Failed to properly disconnect from Exchange Online: $_"
|
|
}
|
|
|
|
Write-Log "Script completed"
|
|
Write-Log "Log file saved to: $logFile"
|
|
} |