-
Notifications
You must be signed in to change notification settings - Fork 573
/
ArchiveMicrosoft365Groups.PS1
134 lines (118 loc) · 8.21 KB
/
ArchiveMicrosoft365Groups.PS1
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
# https://github.com/12Knocksinna/Office365itpros/blob/master/ArchiveMicrosoft365Groups.PS1
# A script to process a set of Microsoft 365 Groups and Archive them so that the information is kept and available
# online for eDiscovery but can't be accessed nby users
# Uses the Exchange Online Module. Must be run by a tenant admin.
# Also needs the Microsoft Teams module to check for private channels - updated 17-Jul-2020
# Check that we're connected to Exchange Online and Teams
Write-Host "Checking that prerequisite PowerShell modules are loaded..."
Try { $OrgName = (Get-OrganizationConfig).Name }
Catch {
Write-Host "Your PowerShell session is not connected to Exchange Online."
Write-Host "Please connect to Exchange Online using an administrative account and retry."
Break }
$TeamsCheck = Get-Module -Name MicrosoftTeams
If ($TeamsCheck -eq $Null) {
Write-Host "Your PowerShell session is not connected to Microsoft Teams."
Write-Host "Please connect to Microsoft Teams using an administrative account and retry."; Break }
Write-Host "Preparing to archive" $ArchiveGroups.Count "Microsoft 365 Groups"
# Find list of groups to be archived
[array]$ArchiveGroups = Get-UnifiedGroup -Filter {CustomAttribute1 -eq "Archive"} -ResultSize 1000 | Select DisplayName, DistinguishedName, Alias, PrimarySmtpAddress, SensitivityLabel, ExternalDirectoryObjectId
# If you don't want to use custom attributes to mark groups to be archived, you can export the groups to a CSV file
# review them with Excel, remove groups that you don't want to archive, and use the remaining set as the input to the
# script. To do this, create the CSV file with:
# $Groups = Get-UnifiedGroup -ResultSize Unlimited | Select DisplayName, Notes, DistinguishedName, Alias, PrimarySmtpAddress, SensitivityLabel, ExternalDirectoryObjectId
# $Groups | Sort DisplayName | Export-CSV -NoTypeInformation c:\temp\GroupsForReview.CSV
# and after the review is done, replace the call to Get-UnifiedGroup above with:
# $ArchiveGroups = Import-CSV c:\temp\GroupsForReview.CSV
If ($ArchiveGroups.Count -eq 0) {
Write-Host "No groups found to archive"; break}
# This is the address of the account that will continue to access the group
$AdminAccount = "[email protected]"
# If you use sensitivity labels, we need to define a label to assign to the archived groups
$SensitivityLabel = "27451a5b-5823-4853-bcd4-2204d03ab477"
$ProgressDelta = 100/($ArchiveGroups.Count); $PercentComplete = 0; $GroupNumber = 0
$Report = [System.Collections.Generic.List[Object]]::new()
CLS
# Main Loop
Foreach ($Group in $ArchiveGroups) {
$GroupNumber++
$CurrentStatus = $Group.DisplayName + " ["+ $GroupNumber +"/" + $ArchiveGroups.Count + "]"
Write-Progress -Activity "Archiving Microsoft 365 Group" -Status $CurrentStatus -PercentComplete $PercentComplete
$PercentComplete += $ProgressDelta
# Need to check if the group is team-enabled
Try {
$Team = Get-Team -GroupId $Group.ExternalDirectoryObjectId }
Catch
{ $Status = 0 }
# Get lists of current owners and members and add the compliance admin as an owner, then remove the existing owners and members
If ($Team) { # This group is team-enabled, so we process membership details with Teams cmdlets
$CurrentOwners = Get-TeamUser -GroupId $Group.ExternalDirectoryObjectId -Role Owner
$CurrentMembers = Get-TeamUser -GroupId $Group.ExternalDirectoryObjectId -Role Member
Add-TeamUser -GroupId $Group.ExternalDirectoryObjectId -User $AdminAccount -Role Owner
Start-Sleep -Seconds 2 # Let membership settle down
[array]$TeamPrivateChannels = Get-TeamChannel -GroupId $Group.ExternalDirectoryObjectId -Membershiptype Private
If ($TeamPrivateChannels) { # Add compliance admin as a member and owner for each private channel
ForEach ($Channel in $TeamPrivateChannels) {
Add-TeamChannelUser -GroupId $Group.ExternalDirectoryObjectId -User $AdminAccount -DisplayName $Channel.DisplayName
Add-TeamChannelUser -GroupId $Group.ExternalDirectoryObjectId -User $AdminAccount -DisplayName $Channel.DisplayName -Role Owner }
} #End TeamPrivateChannel If
# Check for shared channels
[array]$TeamSharedChannels = Get-TeamChannel -GroupId $Group.ExternalDirectoryObjectId -Membershiptype Shared
If ($TeamSharedChannels) { # Add compliance admin as a member and owner for each private channel
ForEach ($Channel in $TeamSharedChannels) {
Add-TeamChannelUser -GroupId $Group.ExternalDirectoryObjectId -User $AdminAccount -DisplayName $Channel.DisplayName
Add-TeamChannelUser -GroupId $Group.ExternalDirectoryObjectId -User $AdminAccount -DisplayName $Channel.DisplayName -Role Owner }
} #End TeamSharedChannel If
ForEach ($Owner in $CurrentOwners) {
Remove-TeamUser -GroupId $Group.ExternalDirectoryObjectId -User $Owner.User }
ForEach ($Member in $CurrentMembers) {
Remove-TeamUser -GroupId $Group.ExternalDirectoryObjectId -User $Member.User }
} # End If to process group using Teams cmdlets
Else { # it's a normal group, so use the EXO cmdlets to update group membership
$CurrentOwners = (Get-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Owners | Select Name)
$CurrentMembers = (Get-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Members | Select Name)
Add-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Members -Links $AdminAccount
Add-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Owners -Links $AdminAccount
Start-Sleep -Seconds 1
ForEach ($Owner in $CurrentOwners) {
Remove-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Owners -Links $Owner.Name -Confirm:$False }
ForEach ($Member in $CurrentMembers) {
Remove-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Members -Links $Member.Name -Confirm:$False }
} # End Else
# Create SMTP Address for the archived group
$OldSmtpAddress = $Group.PrimarySmtpAddress # Just for reporting
$NewSmtpAddress = $Group.PrimarySmtpAddress.Split("@")[0] + "_archived" + "@" + $Group.PrimarySmtpAddress.Split("@")[1]
$AddressRemove = "smtp:"+ $Group.PrimarySmtpAddress
# Update the archive info for the group… $O365Cred is a credentials object that we fetch
# the username from. Adjust the script for your own credentials.
$ArchiveInfo = "Archived " + (Get-Date) + " by " + $O365cred.username
$NewDisplayName = $Group.DisplayName + " (Archived)"
# Update Group properties
If ($Group.SensitivityLabel -eq $Null) {
Set-UnifiedGroup -Identity $Group.DistinguishedName -AccessType Private -RequireSenderAuthenticationEnabled `
$True -HiddenFromExchangeClientsEnabled -CustomAttribute1 $ArchiveInfo -PrimarySmtpAddress $NewSmtpAddress `
-DisplayName $NewDisplayName -HiddenFromAddressListsEnabled $True }
Elseif ($Group.SensitivityLabel -ne $Null) {
Set-UnifiedGroup -Identity $Group.DistinguishedName -RequireSenderAuthenticationEnabled `
$True -HiddenFromExchangeClientsEnabled -CustomAttribute1 $ArchiveInfo -PrimarySmtpAddress $NewSmtpAddress `
-DisplayName $NewDisplayName -HiddenFromAddressListsEnabled $True `
-SensitivityLabel $SensitivityLabel }
# Update Group email address
Set-UnifiedGroup -Identity $Group.DistinguishedName -EmailAddresses @{remove=$AddressRemove}
# Report what we've done
$ReportLine = [PSCustomObject] @{
Group = $Group.DisplayName
DN = $Group.DistinguishedName
NewName = $NewDisplayName
Info = $ArchiveInfo
Owner = $AdminAccount
OldSmtp = $OldSmtpAddress
NewSmtp = $NewSmtpAddress }
$Report.Add($ReportLine)
}
$Report | Out-GridView
$Report | Export-CSV -NoTypeInformation c:\temp\ArchivedGroups.csv
# An example script used to illustrate a concept. More information about the topic can be found in the Office 365 for IT Pros eBook https://gum.co/O365IT/
# and/or a relevant article on https://office365itpros.com or https://www.petri.com. See our post about the Office 365 for IT Pros repository # https://office365itpros.com/office-365-github-repository/ for information about the scripts we write.
# Do not use our scripts in production until you are satisfied that the code meets the needs of your organization. Never run any code downloaded from the Internet without
# first validating the code in a non-production environment.