Skip to content

Commit 7bd08c3

Browse files
authored
Merge pull request #4 from 12Knocksinna/Development
Development
2 parents c63e035 + e168ebf commit 7bd08c3

File tree

2 files changed

+214
-1
lines changed

2 files changed

+214
-1
lines changed

SPOSitesRetention.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ ForEach ($P in $Policies) {
1313
# Check whether a rule is for advanced settings - either a KQL query or sensitive data types
1414
If (-not [string]::IsNullOrWhiteSpace($Rule.ContentMatchQuery) -and -not [string]::IsNullOrWhiteSpace($Rule.ContentMatchQuery)) {
1515
$Settings = "Advanced/KQL" }
16-
Elseif (-not [string]::IsNullOrWhiteSpace($Rule.ContentContainsSensitiveInformation) -and -not [string]::IsNullOrWhiteSpace($Rule.ContentContainsSensitiveInformation)) {
16+
Elseif (-not [string]::IsNullOrWhiteSpace($Rule.ContentContainsSensitiveInformation) -and -not [string]::IsNullOrEmpty($Rule.ContentContainsSensitiveInformation)) {
1717
$Settings = "Advanced/Sensitive Data" }
1818
# Handle retention policy that simply retains and doesn't do anything else
1919
If ($Rule.RetentionDuration -eq $Null -and $Rule.ApplyComplianceTag -ne $Null) {

TeamsGroupsActivityReport.ps1

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
# 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.
2+
# We check the group mailbox to see what the last time a conversation item was added to the Inbox folder.
3+
# Another check sees whether a low number of items exist in the mailbox, which would show that it's not being used.
4+
# We also check the group document library in SharePoint Online to see whether it exists or has been used in the last 90 days.
5+
# And we check Teams compliance items to figure out if any chatting is happening.
6+
7+
# Created 29-July-2016 Tony Redmond
8+
# V2.0 5-Jan-2018
9+
# V3.0 17-Dec-2018
10+
11+
# Check that we are connected to Exchange Online
12+
Write-Host "Checking that prerequisite PowerShell modules are loaded..."
13+
Try { $OrgName = (Get-OrganizationConfig).Name }
14+
Catch {
15+
Write-Host "Your PowerShell session is not connected to Exchange Online."
16+
Write-Host "Please connect to Exchange Online using an administrative account and retry."
17+
Break }
18+
19+
# And check that we're connected to SharePoint Online as well
20+
Try { $SPOCheck = (Get-SPOTenant -ErrorAction SilentlyContinue ) }
21+
Catch {
22+
Write-Host "Your PowerShell session is not connected to SharePoint Online."
23+
Write-Host "Please connect to SharePoint Online using an administrative account and retry."
24+
Break }
25+
26+
# And finally the Teams module
27+
Try { $TeamsCheck = (Get-Team) }
28+
Catch {
29+
Write-Host "Please connect to the Teams PowerShell module before proceeeding."
30+
Break }
31+
32+
# OK, we seem to be fully connected to both Exchange Online and SharePoint Online...
33+
Write-Host "Checking for Obsolete Office 365 Groups in the tenant:" $OrgName
34+
35+
# Setup some stuff we use
36+
$WarningDate = (Get-Date).AddDays(-90)
37+
$WarningEmailDate = (Get-Date).AddDays(-365)
38+
$Today = (Get-Date)
39+
$Date = $Today.ToShortDateString()
40+
$TeamsGroups = 0
41+
$TeamsEnabled = $False
42+
$ObsoleteSPOGroups = 0
43+
$ObsoleteEmailGroups = 0
44+
$Report = @()
45+
$ReportFile = "c:\temp\GroupsActivityReport.html"
46+
$CSVFile = "c:\temp\GroupsActivityReport.csv"
47+
$htmlhead="<html>
48+
<style>
49+
BODY{font-family: Arial; font-size: 8pt;}
50+
H1{font-size: 22px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
51+
H2{font-size: 18px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
52+
H3{font-size: 16px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
53+
TABLE{border: 1px solid black; border-collapse: collapse; font-size: 8pt;}
54+
TH{border: 1px solid #969595; background: #dddddd; padding: 5px; color: #000000;}
55+
TD{border: 1px solid #969595; padding: 5px; }
56+
td.pass{background: #B7EB83;}
57+
td.warn{background: #FFF275;}
58+
td.fail{background: #FF2626; color: #ffffff;}
59+
td.info{background: #85D4FF;}
60+
</style>
61+
<body>
62+
<div align=center>
63+
<p><h1>Office 365 Groups and Teams Activity Report</h1></p>
64+
<p><h3>Generated: " + $date + "</h3></p></div>"
65+
66+
# Get a list of all Office 365 Groups in the tenant
67+
Write-Host "Extracting list of Office 365 Groups for checking..."
68+
$Groups = Get-UnifiedGroup -ResultSize Unlimited | Sort-Object DisplayName
69+
# And create a hash table of Teams
70+
$TeamsList = @{}
71+
Get-Team | ForEach { $TeamsList.Add($_.GroupId, $_.DisplayName) }
72+
73+
Write-Host "Processing" $Groups.Count "groups"
74+
# Progress bar
75+
$ProgDelta = 100/($Groups.count)
76+
$CheckCount = 0
77+
$GroupNumber = 0
78+
79+
# Main loop
80+
ForEach ($G in $Groups) {
81+
$GroupNumber++
82+
$GroupStatus = $G.DisplayName + " ["+ $GroupNumber +"/" + $Groups.Count + "]"
83+
Write-Progress -Activity "Checking group" -Status $GroupStatus -PercentComplete $CheckCount
84+
$CheckCount += $ProgDelta
85+
$ObsoleteReportLine = $G.DisplayName
86+
$SPOStatus = "Normal"
87+
$SPOActivity = "Document library in use"
88+
$NumberWarnings = 0
89+
$NumberofChats = 0
90+
$TeamChatData = $Null
91+
$TeamsEnabled = $False
92+
$LastItemAddedtoTeams = "No chats"
93+
$MailboxStatus = $Null
94+
# Check who manages the group
95+
$ManagedBy = $G.ManagedBy
96+
If ([string]::IsNullOrWhiteSpace($ManagedBy) -and [string]::IsNullOrEmpty($ManagedBy)) {
97+
$ManagedBy = "No owners"
98+
Write-Host $G.DisplayName "has no group owners!" -ForegroundColor Red}
99+
Else {
100+
$ManagedBy = (Get-Mailbox -Identity $G.ManagedBy[0]).DisplayName}
101+
102+
# Fetch information about activity in the Inbox folder of the group mailbox
103+
$Data = (Get-MailboxFolderStatistics -Identity $G.Alias -IncludeOldestAndNewestITems -FolderScope Inbox)
104+
$LastConversation = $Data.NewestItemReceivedDate
105+
$NumberConversations = $Data.ItemsInFolder
106+
$MailboxStatus = "Normal"
107+
108+
If ($Data.NewestItemReceivedDate -le $WarningEmailDate) {
109+
Write-Host "Last conversation item created in" $G.DisplayName "was" $Data.NewestItemReceivedDate "-> Obsolete?"
110+
$ObsoleteReportLine = $ObsoleteReportLine + " Last conversation dated: " + $Data.NewestItemReceivedDate + "."
111+
$MailboxStatus = "Group Inbox Not Recently Used"
112+
$ObsoleteEmailGroups++
113+
$NumberWarnings++ }
114+
Else
115+
{# Some conversations exist - but if there are fewer than 20, we should flag this...
116+
If ($Data.ItemsInFolder -lt 20) {
117+
$ObsoleteReportLine = $ObsoleteReportLine + " Only " + $Data.ItemsInFolder + " conversation item(s) found."
118+
$MailboxStatus = "Low number of conversations"
119+
$NumberWarnings++}
120+
}
121+
122+
# Loop to check SharePoint document library
123+
If ($G.SharePointDocumentsUrl -ne $Null) {
124+
$SPOSite = (Get-SPOSite -Identity $G.SharePointDocumentsUrl.replace("/Shared Documents", ""))
125+
$AuditCheck = $G.SharePointDocumentsUrl + "/*"
126+
$AuditRecs = 0
127+
$AuditRecs = (Search-UnifiedAuditLog -RecordType SharePointFileOperation -StartDate $WarningDate -EndDate $Today -ObjectId $AuditCheck -SessionCommand ReturnNextPreviewPage)
128+
If ($AuditRecs -eq $null) {
129+
#Write-Host "No audit records found for" $SPOSite.Title "-> Potentially obsolete!"
130+
$ObsoleteSPOGroups++
131+
$ObsoleteReportLine = $ObsoleteReportLine + " No SPO activity detected in the last 90 days." }
132+
}
133+
Else
134+
{
135+
# The SharePoint document library URL is blank, so the document library was never created for this group
136+
#Write-Host "SharePoint has never been used for the group" $G.DisplayName
137+
$ObsoleteSPOGroups++
138+
$ObsoleteReportLine = $ObsoleteReportLine + " SPO document library never created."
139+
}
140+
# Report to the screen what we found - but only if something was found...
141+
If ($ObsoleteReportLine -ne $G.DisplayName)
142+
{
143+
Write-Host $ObsoleteReportLine
144+
}
145+
# Generate the number of warnings to decide how obsolete the group might be...
146+
If ($AuditRecs -eq $Null) {
147+
$SPOActivity = "No SPO activity detected in the last 90 days"
148+
$NumberWarnings++ }
149+
If ($G.SharePointDocumentsUrl -eq $Null) {
150+
$SPOStatus = "Document library never created"
151+
$NumberWarnings++ }
152+
153+
$Status = "Pass"
154+
If ($NumberWarnings -eq 1)
155+
{
156+
$Status = "Warning"
157+
}
158+
If ($NumberWarnings -gt 1)
159+
{
160+
$Status = "Fail"
161+
}
162+
163+
# If Team-Enabled, we can find the date of the last chat compliance record
164+
If ($TeamsList.ContainsKey($G.ExternalDirectoryObjectId) -eq $True) {
165+
$TeamsEnabled = $True
166+
$TeamChatData = (Get-MailboxFolderStatistics -Identity $G.Alias -IncludeOldestAndNewestItems -FolderScope ConversationHistory)
167+
If ($TeamChatData.ItemsInFolder[1] -ne 0) {
168+
$LastItemAddedtoTeams = $TeamChatData.NewestItemReceivedDate[1]
169+
$NumberofChats = $TeamChatData.ItemsInFolder[1]
170+
If ($TeamChatData.NewestItemReceivedDate -le $WarningEmailDate) {
171+
Write-Host "Team-enabled group" $G.DisplayName "has only" $TeamChatData.ItemsInFolder[1] "compliance record(s)" }
172+
}
173+
}
174+
175+
# Generate a line for this group for our report
176+
$ReportLine = [PSCustomObject][Ordered]@{
177+
GroupName = $G.DisplayName
178+
ManagedBy = $ManagedBy
179+
Members = $G.GroupMemberCount
180+
ExternalGuests = $G.GroupExternalMemberCount
181+
Description = $G.Notes
182+
MailboxStatus = $MailboxStatus
183+
TeamEnabled = $TeamsEnabled
184+
LastChat = $LastItemAddedtoTeams
185+
NumberChats = $NumberofChats
186+
LastConversation = $LastConversation
187+
NumberConversations = $NumberConversations
188+
SPOActivity = $SPOActivity
189+
SPOStatus = $SPOStatus
190+
NumberWarnings = $NumberWarnings
191+
Status = $Status}
192+
# And store the line in the report object
193+
$Report += $ReportLine
194+
#End of main loop
195+
}
196+
# Create the HTML report
197+
$PercentTeams = ($TeamsList.Count/$Groups.Count)
198+
$htmlbody = $Report | ConvertTo-Html -Fragment
199+
$htmltail = "<p>Report created for: " + $OrgName + "
200+
</p>
201+
<p>Number of groups scanned: " + $Groups.Count + "</p>" +
202+
"<p>Number of potentially obsolete groups (based on document library activity): " + $ObsoleteSPOGroups + "</p>" +
203+
"<p>Number of potentially obsolete groups (based on conversation activity): " + $ObsoleteEmailGroups + "<p>"+
204+
"<p>Number of Teams-enabled groups : " + $TeamsList.Count + "</p>" +
205+
"<p>Percentage of Teams-enabled groups: " + ($PercentTeams).tostring("P") + "</body></html>"
206+
$htmlreport = $htmlhead + $htmlbody + $htmltail
207+
$htmlreport | Out-File $ReportFile -Encoding UTF8
208+
209+
# Summary note
210+
Write-Host $ObsoleteSPOGroups "obsolete group document libraries and" $ObsoleteEmailGroups "obsolete email groups found out of" $Groups.Count "checked"
211+
Write-Host "Summary report available in" $ReportFile "and CSV file saved in" $CSVFile
212+
$Report | Export-CSV -NoTypeInformation $CSVFile
213+

0 commit comments

Comments
 (0)