-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathTeamsGroupsActivityReport.ps1
214 lines (196 loc) · 9.74 KB
/
TeamsGroupsActivityReport.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
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
212
213
# Original: https://gallery.technet.microsoft.com/Check-for-obsolete-Office-c0020a42
# A script to check the activity of Office 365 Groups and Teams and report the groups and teams that might be deleted because they're not used.
# We check the group mailbox to see what the last time a conversation item was added to the Inbox folder.
# Another check sees whether a low number of items exist in the mailbox, which would show that it's not being used.
# We also check the group document library in SharePoint Online to see whether it exists or has been used in the last 90 days.
# And we check Teams compliance items to figure out if any chatting is happening.
# Created 29-July-2016 Tony Redmond
# V2.0 5-Jan-2018
# V3.0 17-Dec-2018
# Check that we are connected to Exchange Online
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 }
# And check that we're connected to SharePoint Online as well
Try { $SPOCheck = (Get-SPOTenant -ErrorAction SilentlyContinue ) }
Catch {
Write-Host "Your PowerShell session is not connected to SharePoint Online."
Write-Host "Please connect to SharePoint Online using an administrative account and retry."
Break }
# And finally the Teams module
Try { $TeamsCheck = (Get-Team) }
Catch {
Write-Host "Please connect to the Teams PowerShell module before proceeeding."
Break }
# OK, we seem to be fully connected to both Exchange Online and SharePoint Online...
Write-Host "Checking for Obsolete Office 365 Groups in the tenant:" $OrgName
# Setup some stuff we use
$WarningDate = (Get-Date).AddDays(-90)
$WarningEmailDate = (Get-Date).AddDays(-365)
$Today = (Get-Date)
$Date = $Today.ToShortDateString()
$TeamsEnabled = $False
$ObsoleteSPOGroups = 0
$ObsoleteEmailGroups = 0
$Report = @()
$ReportFile = ".\TeamsGroupsActivityReport.html"
$CSVFile = ".\TeamsGroupsActivityReport.csv"
$htmlhead="<html>
<style>
BODY{font-family: Arial; font-size: 8pt;}
H1{font-size: 22px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
H2{font-size: 18px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
H3{font-size: 16px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
TABLE{border: 1px solid black; border-collapse: collapse; font-size: 8pt;}
TH{border: 1px solid #969595; background: #dddddd; padding: 5px; color: #000000;}
TD{border: 1px solid #969595; padding: 5px; }
td.pass{background: #B7EB83;}
td.warn{background: #FFF275;}
td.fail{background: #FF2626; color: #ffffff;}
td.info{background: #85D4FF;}
</style>
<body>
<div align=center>
<p><h1>Office 365 Groups and Teams Activity Report</h1></p>
<p><h3>Generated: " + $date + "</h3></p></div>"
# Get a list of all Office 365 Groups in the tenant
Write-Host "Extracting list of Office 365 Groups for checking..."
$Groups = Get-UnifiedGroup -ResultSize Unlimited | Sort-Object DisplayName
# And create a hash table of Teams
$TeamsList = @{}
Get-Team | ForEach { $TeamsList.Add($_.GroupId, $_.DisplayName) }
Write-Host "Processing" $Groups.Count "groups"
# Progress bar
$ProgDelta = 100/($Groups.count)
$CheckCount = 0
$GroupNumber = 0
# Main loop
ForEach ($G in $Groups) {
$GroupNumber++
$GroupStatus = $G.DisplayName + " ["+ $GroupNumber +"/" + $Groups.Count + "]"
Write-Progress -Activity "Checking group" -Status $GroupStatus -PercentComplete $CheckCount
$CheckCount += $ProgDelta
$ObsoleteReportLine = $G.DisplayName
$SPOStatus = "Normal"
$SPOActivity = "Document library in use"
$NumberWarnings = 0
$NumberofChats = 0
$TeamChatData = $Null
$TeamsEnabled = $False
$LastItemAddedtoTeams = "No chats"
$MailboxStatus = $Null
# Check who manages the group
$ManagedBy = $G.ManagedBy
If ([string]::IsNullOrWhiteSpace($ManagedBy) -and [string]::IsNullOrEmpty($ManagedBy)) {
$ManagedBy = "No owners"
Write-Host $G.DisplayName "has no group owners!" -ForegroundColor Red}
Else {
$ManagedBy = (Get-Mailbox -Identity $G.ManagedBy[0]).DisplayName}
# Fetch information about activity in the Inbox folder of the group mailbox
$Data = (Get-MailboxFolderStatistics -Identity $G.Alias -IncludeOldestAndNewestITems -FolderScope Inbox)
$LastConversation = $Data.NewestItemReceivedDate
$NumberConversations = $Data.ItemsInFolder
$MailboxStatus = "Normal"
If ($Data.NewestItemReceivedDate -le $WarningEmailDate) {
Write-Host "Last conversation item created in" $G.DisplayName "was" $Data.NewestItemReceivedDate "-> Obsolete?"
$ObsoleteReportLine = $ObsoleteReportLine + " Last conversation dated: " + $Data.NewestItemReceivedDate + "."
$MailboxStatus = "Group Inbox Not Recently Used"
$ObsoleteEmailGroups++
$NumberWarnings++ }
Else
{# Some conversations exist - but if there are fewer than 20, we should flag this...
If ($Data.ItemsInFolder -lt 20) {
$ObsoleteReportLine = $ObsoleteReportLine + " Only " + $Data.ItemsInFolder + " conversation item(s) found."
$MailboxStatus = "Low number of conversations"
$NumberWarnings++}
}
# Loop to check SharePoint document library
If ($G.SharePointDocumentsUrl -ne $Null) {
$SPOSite = (Get-SPOSite -Identity $G.SharePointDocumentsUrl.replace("/Shared Documents", ""))
$AuditCheck = $G.SharePointDocumentsUrl + "/*"
$AuditRecs = 0
$AuditRecs = (Search-UnifiedAuditLog -RecordType SharePointFileOperation -StartDate $WarningDate -EndDate $Today -ObjectId $AuditCheck -SessionCommand ReturnNextPreviewPage)
If ($AuditRecs -eq $null) {
#Write-Host "No audit records found for" $SPOSite.Title "-> Potentially obsolete!"
$ObsoleteSPOGroups++
$ObsoleteReportLine = $ObsoleteReportLine + " No SPO activity detected in the last 90 days." }
}
Else
{
# The SharePoint document library URL is blank, so the document library was never created for this group
#Write-Host "SharePoint has never been used for the group" $G.DisplayName
$ObsoleteSPOGroups++
$ObsoleteReportLine = $ObsoleteReportLine + " SPO document library never created."
}
# Report to the screen what we found - but only if something was found...
If ($ObsoleteReportLine -ne $G.DisplayName)
{
Write-Host $ObsoleteReportLine
}
# Generate the number of warnings to decide how obsolete the group might be...
If ($AuditRecs -eq $Null) {
$SPOActivity = "No SPO activity detected in the last 90 days"
$NumberWarnings++ }
If ($G.SharePointDocumentsUrl -eq $Null) {
$SPOStatus = "Document library never created"
$NumberWarnings++ }
$Status = "Pass"
If ($NumberWarnings -eq 1)
{
$Status = "Warning"
}
If ($NumberWarnings -gt 1)
{
$Status = "Fail"
}
# If Team-Enabled, we can find the date of the last chat compliance record
If ($TeamsList.ContainsKey($G.ExternalDirectoryObjectId) -eq $True) {
$TeamsEnabled = $True
$TeamChatData = (Get-MailboxFolderStatistics -Identity $G.Alias -IncludeOldestAndNewestItems -FolderScope ConversationHistory)
If ($TeamChatData.ItemsInFolder[1] -ne 0) {
$LastItemAddedtoTeams = $TeamChatData.NewestItemReceivedDate[1]
$NumberofChats = $TeamChatData.ItemsInFolder[1]
If ($TeamChatData.NewestItemReceivedDate -le $WarningEmailDate) {
Write-Host "Team-enabled group" $G.DisplayName "has only" $TeamChatData.ItemsInFolder[1] "compliance record(s)" }
}
}
# Generate a line for this group for our report
$ReportLine = [PSCustomObject][Ordered]@{
GroupName = $G.DisplayName
ManagedBy = $ManagedBy
Members = $G.GroupMemberCount
ExternalGuests = $G.GroupExternalMemberCount
Description = $G.Notes
MailboxStatus = $MailboxStatus
TeamEnabled = $TeamsEnabled
LastChat = $LastItemAddedtoTeams
NumberChats = $NumberofChats
LastConversation = $LastConversation
NumberConversations = $NumberConversations
SPOActivity = $SPOActivity
SPOStatus = $SPOStatus
NumberWarnings = $NumberWarnings
Status = $Status}
# And store the line in the report object
$Report += $ReportLine
#End of main loop
}
# Create the HTML report
$PercentTeams = ($TeamsList.Count/$Groups.Count)
$htmlbody = $Report | ConvertTo-Html -Fragment
$htmltail = "<p>Report created for: " + $OrgName + "
</p>
<p>Number of groups scanned: " + $Groups.Count + "</p>" +
"<p>Number of potentially obsolete groups (based on document library activity): " + $ObsoleteSPOGroups + "</p>" +
"<p>Number of potentially obsolete groups (based on conversation activity): " + $ObsoleteEmailGroups + "<p>"+
"<p>Number of Teams-enabled groups : " + $TeamsList.Count + "</p>" +
"<p>Percentage of Teams-enabled groups: " + ($PercentTeams).tostring("P") + "</body></html>"
$htmlreport = $htmlhead + $htmlbody + $htmltail
$htmlreport | Out-File $ReportFile -Encoding UTF8
# Summary note
Write-Host $ObsoleteSPOGroups "obsolete group document libraries and" $ObsoleteEmailGroups "obsolete email groups found out of" $Groups.Count "checked"
Write-Host "Summary report available in" $ReportFile "and CSV file saved in" $CSVFile
$Report | Export-CSV -NoTypeInformation $CSVFile