-
Notifications
You must be signed in to change notification settings - Fork 572
/
GetGraphUserStatisticsReport.PS1
488 lines (436 loc) · 24.6 KB
/
GetGraphUserStatisticsReport.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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# GetGraphUserStatisticsReport.PS1
# A sample script showing how to gather user activity information from the Graph and assemble it into one report
# V1.3 2-Sep-2020
# V2.0 is the transitition from PowerShell lists to hash tables as the repository for data extracted from the Microsoft Graph
# with the intention of faster access for large data sets (more than 1,000 accounts in a tenant).
# V2.1 3-Aug-2022 (Increased date range for activities to go back 180 days instead of 90)
# Github link: https://github.com/12Knocksinna/Office365itpros/blob/master/GetGraphUserStatisticsReport.PS1
# Note: Guest user activity is not recorded by the Graph - only tenant accounts are processed
# There isn't a lot of error checking/handling in this script because it's designed to show the principles of how to grab and
# process Office 365 usage data from the Graph rather than being something that meets the needs of everyone. Have fun editing it!
# Needs the Reports.Read.All permission to get user data
# Needs the AuditLog.Read.All and Directory.Read.All permissions to read user signin data
# -------------------------------------------------------------------------------------------------------------------------------
function Get-GraphData {
# Based on https://danielchronlund.com/2018/11/19/fetch-data-from-microsoft-graph-with-powershell-paging-support/
# GET data from Microsoft Graph.
param (
[parameter(Mandatory = $true)]
$AccessToken,
[parameter(Mandatory = $true)]
$Uri
)
# Check if authentication was successful.
if ($AccessToken) {
$Headers = @{
'Content-Type' = "application\json"
'Authorization' = "Bearer $AccessToken"
'ConsistencyLevel' = "eventual" }
# Create an empty array to store the result.
$QueryResults = @()
# Invoke REST method and fetch data until there are no pages left.
do {
$Results = ""
$StatusCode = ""
do {
try {
$Results = Invoke-RestMethod -Headers $Headers -Uri $Uri -UseBasicParsing -Method "GET" -ContentType "application/json"
$StatusCode = $Results.StatusCode
} catch {
$StatusCode = $_.Exception.Response.StatusCode.value__
if ($StatusCode -eq 429) {
Write-Warning "Got throttled by Microsoft. Sleeping for 45 seconds..."
Start-Sleep -Seconds 45
}
else {
Write-Error $_.Exception
}
}
} while ($StatusCode -eq 429)
if ($Results.value) {
$QueryResults += $Results.value
}
else {
$QueryResults += $Results
}
$uri = $Results.'@odata.nextlink'
} until (!($uri))
# Return the result.
$QueryResults
}
else {
Write-Error "No Access Token"
}
}
Clear-Host
# Define the values applicable for the application used to connect to the Graph (change these for your tenant)
$AppId = "d816b32c-0edb-48be-9385-30a9cfd96155"
$TenantId = "a662313f-14fc-43a2-9a7a-d2e27f4f3478"
$AppSecret = 't_rkvIn1oZ1cNceUBvJ2or1lrrIsb*:='
$OutputCSV = "c:\temp\Office365TenantUsage.csv"
$StartTime1 = Get-Date
# Construct URI and body needed for authentication
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$body = @{
client_id = $AppId
scope = "https://graph.microsoft.com/.default"
client_secret = $AppSecret
grant_type = "client_credentials" }
# Get OAuth 2.0 Token
$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
# Unpack Access Token
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
# Base URL
$headers = @{Authorization = "Bearer $token"}
Write-Host "Fetching Teams user activity data from the Graph..."
# The Graph returns information in CSV format. We convert it to allow the data to be more easily processed by PowerShell
# Get Teams Usage Data - the replace parameter is there to remove three odd leading characters () in the CSV data returned by the
$TeamsUserReportsURI = "https://graph.microsoft.com/v1.0/reports/getTeamsUserActivityUserDetail(period='D180')"
[array]$TeamsUserData = (Invoke-RestMethod -Uri $TeamsUserReportsURI -Headers $Headers -Method Get -ContentType "application/json") -Replace "...Report Refresh Date", "Report Refresh Date" | ConvertFrom-Csv
Write-Host "Fetching OneDrive for Business user activity data from the Graph..."
# Get OneDrive for Business data
$OneDriveUsageUri = "https://graph.microsoft.com/v1.0/reports/getOneDriveUsageAccountDetail(period='D180')"
[array]$OneDriveData = (Get-GraphData -Uri $OneDriveUsageUri -AccessToken $Token) -Replace "...Report Refresh Date", "Report Refresh Date" | ConvertFrom-Csv
Write-Host "Fetching Exchange Online user activity data from the Graph..."
# Get Exchange Activity Data
$EmailReportsUri = "https://graph.microsoft.com/v1.0/reports/getEmailActivityUserDetail(period='D180')"
[array]$EmailData = (Get-GraphData -Uri $EmailReportsUri -AccessToken $Token) -Replace "...Report Refresh Date", "Report Refresh Date" | ConvertFrom-Csv
# Get Exchange Storage Data
$MailboxUsageReportsUri = "https://graph.microsoft.com/v1.0/reports/getMailboxUsageDetail(period='D180')"
[array]$MailboxUsage = (Get-GraphData -Uri $MailboxUsageReportsUri -AccessToken $Token) -Replace "...Report Refresh Date", "Report Refresh Date" | ConvertFrom-Csv
Write-Host "Fetching SharePoint Online user activity data from the Graph..."
# Get SharePoint usage data
$SPOUsageReportsUri = "https://graph.microsoft.com/v1.0/reports/getSharePointActivityUserDetail(period='D180')"
[array]$SPOUsage = (Get-GraphData -Uri $SPOUsageReportsUri -AccessToken $Token) -Replace "...Report Refresh Date", "Report Refresh Date" | ConvertFrom-Csv
Write-Host "Fetching Yammer user activity data from the Graph..."
# Get Yammer usage data
$YammerUsageReportsUri = "https://graph.microsoft.com/v1.0/reports/getYammerActivityUserDetail(period='D180')"
[array]$YammerUsage = (Get-GraphData -Uri $YammerUsageReportsUri -AccessToken $Token) -Replace "...Report Refresh Date", "Report Refresh Date" | ConvertFrom-Csv
# Create hash table for user sign in data
$UserSignIns = @{}
# And hash table for the output data
$DataTable = @{}
# Get User sign in data
Write-Host "Fetching user sign-in data from the Graph..."
$Uri = "https://graph.microsoft.com/V1.0/users?`$select=displayName,userPrincipalName, mail, id, CreatedDateTime,signInActivity,UserType&`$top=999"
[array]$SignInData = Get-GraphData -Uri $Uri -AccessToken $Token
# Filter out guest member sign-in records
[array]$UserSignInData = $SignInData | Where-Object {$_.UserType -eq "Member"} | Sort-Object UserPrincipalName -Unique
# Update the user sign in hash table
ForEach ($U in $UserSignInData) {
If ($U.SignInActivity.LastSignInDateTime) {
$LastSignInDate = Get-Date($U.SignInActivity.LastSignInDateTime) -format g
$UserSignIns.Add([String]$U.UserPrincipalName, $LastSignInDate)
} Else {
$UserSignIns.Add([String]$U.UserPrincipalName,$Null)
}
}
$StartTime2 = Get-Date
Write-Host "Processing activity data fetched from the Graph..."
# Process Teams Data
ForEach ($T in $TeamsUserData) {
If ([string]::IsNullOrEmpty($T."Last Activity Date")) {
$TeamsLastActivity = "No activity"
$TeamsDaysSinceActive = "N/A" }
Else {
$TeamsLastActivity = Get-Date($T."Last Activity Date") -format "dd-MMM-yyyy"
$TeamsDaysSinceActive = (New-TimeSpan($TeamsLastActivity)).Days }
$ReportLine = [PSCustomObject] @{
TeamsUPN = $T."User Principal Name"
TeamsLastActive = $TeamsLastActivity
TeamsDaysSinceActive = $TeamsDaysSinceActive
TeamsReportDate = Get-Date($T."Report Refresh Date") -format "dd-MMM-yyyy"
TeamsLicense = $T."Assigned Products"
TeamsChannelChats = $T."Team Chat Message Count"
TeamsPrivateChats = $T."Private Chat Message Count"
TeamsCalls = $T."Call Count"
TeamsMeetings = $T."Meeting Count"
TeamsRecordType = "Teams"}
$DataTable[$T."User Principal Name"] = $ReportLine}
# Process Exchange Data
ForEach ($E in $EmailData) {
$ExoDaysSinceActive = $Null
If ([string]::IsNullOrEmpty($E."Last Activity Date")) {
$ExoLastActivity = "No activity"
$ExoDaysSinceActive = "N/A" }
Else {
$ExoLastActivity = Get-Date($E."Last Activity Date") -format "dd-MMM-yyyy"
$ExoDaysSinceActive = (New-TimeSpan($ExoLastActivity)).Days }
$ReportLine = [PSCustomObject] @{
ExoUPN = $E."User Principal Name"
ExoDisplayName = $E."Display Name"
ExoLastActive = $ExoLastActivity
ExoDaysSinceActive = $ExoDaysSinceActive
ExoReportDate = Get-Date($E."Report Refresh Date") -format "dd-MMM-yyyy"
ExoSendCount = [int]$E."Send Count"
ExoReadCount = [int]$E."Read Count"
ExoReceiveCount = [int]$E."Receive Count"
ExoIsDeleted = $E."Is Deleted"
ExoRecordType = "Exchange Activity"}
[Array]$ExistingData = $DataTable[$E."User Principal Name"]
[Array]$NewData = $ExistingData + $ReportLine
$DataTable[$E."User Principal Name"] = $NewData }
ForEach ($M in $MailboxUsage) {
If ([string]::IsNullOrEmpty($M."Last Activity Date")) {
$ExoLastActivity = "No activity" }
Else {
$ExoLastActivity = Get-Date($M."Last Activity Date") -format "dd-MMM-yyyy"
$ExoDaysSinceActive = (New-TimeSpan($ExoLastActivity)).Days }
$ReportLine = [PSCustomObject] @{
MbxUPN = $M."User Principal Name"
MbxDisplayName = $M."Display Name"
MbxLastActive = $ExoLastActivity
MbxDaysSinceActive = $ExoDaysSinceActive
MbxReportDate = Get-Date($M."Report Refresh Date") -format "dd-MMM-yyyy"
MbxQuotaUsed = [Math]::Round($M."Storage Used (Byte)"/1GB,2)
MbxItems = [int]$M."Item Count"
MbxRecordType = "Exchange Storage"}
[Array]$ExistingData = $DataTable[$M."User Principal Name"]
[Array]$NewData = $ExistingData + $ReportLine
$DataTable[$M."User Principal Name"] = $NewData }
# SharePoint data
ForEach ($S in $SPOUsage) {
If ([string]::IsNullOrEmpty($S."Last Activity Date")) {
$SPOLastActivity = "No activity"
$SPODaysSinceActive = "N/A" }
Else {
$SPOLastActivity = Get-Date($S."Last Activity Date") -format "dd-MMM-yyyy"
$SPODaysSinceActive = (New-TimeSpan ($SPOLastActivity)).Days }
$ReportLine = [PSCustomObject] @{
SPOUPN = $S."User Principal Name"
SPOLastActive = $SPOLastActivity
SPODaysSinceActive = $SPODaysSinceActive
SPOViewedEdited = [int]$S."Viewed or Edited File Count"
SPOSyncedFileCount = [int]$S."Synced File Count"
SPOSharedExt = [int]$S."Shared Externally File Count"
SPOSharedInt = [int]$S."Shared Internally File Count"
SPOVisitedPages = [int]$S."Visited Page Count"
SPORecordType = "SharePoint Usage"}
[Array]$ExistingData = $DataTable[$S."User Principal Name"]
[Array]$NewData = $ExistingData + $ReportLine
$DataTable[$S."User Principal Name"] = $NewData }
# OneDrive for Business data
ForEach ($O in $OneDriveData) {
$OneDriveLastActivity = $Null
If ([string]::IsNullOrEmpty($O."Last Activity Date")) {
$OneDriveLastActivity = "No activity"
$OneDriveDaysSinceActive = "N/A" }
Else {
$OneDriveLastActivity = Get-Date($O."Last Activity Date") -format "dd-MMM-yyyy"
$OneDriveDaysSinceActive = (New-TimeSpan($OneDriveLastActivity)).Days }
$ReportLine = [PSCustomObject] @{
ODUPN = $O."Owner Principal Name"
ODDisplayName = $O."Owner Display Name"
ODLastActive = $OneDriveLastActivity
ODDaysSinceActive = $OneDriveDaysSinceActive
ODSite = $O."Site URL"
ODFileCount = [int]$O."File Count"
ODStorageUsed = [Math]::Round($O."Storage Used (Byte)"/1GB,4)
ODQuota = [Math]::Round($O."Storage Allocated (Byte)"/1GB,2)
ODRecordType = "OneDrive Storage"}
[Array]$ExistingData = $DataTable[$O."Owner Principal Name"]
[Array]$NewData = $ExistingData + $ReportLine
$DataTable[$O."Owner Principal Name"] = $NewData }
# Yammer Data
ForEach ($Y in $YammerUsage) {
If ([string]::IsNullOrEmpty($Y."Last Activity Date")) {
$YammerLastActivity = "No activity"
$YammerDaysSinceActive = "N/A" }
Else {
$YammerLastActivity = Get-Date($Y."Last Activity Date") -format "dd-MMM-yyyy"
$YammerDaysSinceActive = (New-TimeSpan ($YammerLastActivity)).Days
}
$ReportLine = [PSCustomObject] @{
YUPN = $Y."User Principal Name"
YDisplayName = $Y."Display Name"
YLastActive = $YammerLastActivity
YDaysSinceActive = $YammerDaysSinceActive
YPostedCount = [int]$Y."Posted Count"
YReadCount = [int]$Y."Read Count"
YLikedCount = [int]$Y."Liked Count"
YRecordType = "Yammer Usage"
}
[Array]$ExistingData = $DataTable[$Y."User Principal Name"]
[Array]$NewData = $ExistingData + $ReportLine
$DataTable[$Y."User Principal Name"] = $NewData }
Clear-Host
# Create set of users that we've collected data for - each of these users will be in the $DataTable with some information.
[System.Collections.ArrayList]$Users = @()
ForEach ($UserPrincipalName in $DataTable.Keys) {
If ($DataTable[$UserPrincipalName]) { #Info exists in datatable
$obj = [PSCustomObject]@{
UPN = $UserPrincipalName}
$Users.add($obj) | Out-Null }
}
$StartTime3 = Get-Date
# Set up progress bar
$ProgressDelta = 100/($Users.Count); $PercentComplete = 0; $UserNumber = 0
$OutData = [System.Collections.Generic.List[Object]]::new() # Create merged output file
# Process each user to extract Exchange, Teams, OneDrive, SharePoint, and Yammer statistics for their activity
ForEach ($UserPrincipalName in $Users) {
$U = $UserPrincipalName.UPN
$UserNumber++
$CurrentStatus = $U + " ["+ $UserNumber +"/" + $Users.Count + "]"
Write-Progress -Activity "Extracting information for user" -Status $CurrentStatus -PercentComplete $PercentComplete
$PercentComplete += $ProgressDelta
$UserData = $DataTable[$U] # Extract data for the user - everything is in a single keyed access to the hash table
# Process Exchange Data
[string]$ExoUPN = (Out-String -InputObject $UserData.ExoUPN).Trim()
[string]$ExoLastActive = (Out-String -InputObject $UserData.ExoLastActive).Trim()
If ([string]::IsNullOrEmpty($ExoUPN) -or $ExoLastActive -eq "No Activity") {
$ExoDaysSinceActive = "N/A"
$ExoLastActive = "No Activity"
} Else {
[string]$ExoLastActive = (Out-String -InputObject $UserData.ExoLastActive).Trim()
[string]$ExoDaysSinceActive = (Out-String -InputObject $UserData.ExoDaysSinceActive).Trim()
}
# Parse OneDrive for Business usage data
[string]$ODUPN = (Out-String -InputObject $UserData.ODUPN).Trim()
[string]$ODLastActive = (Out-String -InputObject $UserData.ODLastActive).Trim() # Possibility of a second OneDrive account for some users.
If (($ODLastActive -Like "*No Activity*") -or ([string]::IsNullOrEmpty($ODLastActive))) {$ODLastActive = "No Activity"} # this is a hack until I figure out a better way to handle the situation
If ($null -eq [string]::IsNullOrEmpty($ODUPN) -or $ODLastActive -eq "No Activity") {
[string]$ODDaysSinceActive = "N/A"
[string]$ODLastActive = "No Activity"
$ODFiles = 0
$ODStorage = 0
$ODQuota = 1024
} Else {
[string]$ODDaysSinceActive = (Out-String -InputObject $UserData.ODDaysSinceActive).Trim()
[string]$ODLastActive = (Out-String -InputObject $UserData.ODLastActive).Trim()
[string]$ODFiles = (Out-String -InputObject $UserData.ODFileCount).Trim()
[string]$ODStorage = (Out-String -InputObject $UserData.ODStorageUsed).Trim()
[string]$ODQuota = (Out-String -InputObject $UserData.ODQuota).Trim()
}
# Parse Yammer usage data; Yammer isn't used everywhere, so make sure that we record zero data
[string]$YUPN = (Out-String -InputObject $UserData.YUPN).Trim()
[string]$YammerLastActive = (Out-String -InputObject $UserData.YLastActive).Trim()
If (([string]::IsNullOrEmpty($YUPN) -or ($YammerLastActive -eq "No Activity"))) {
[string]$YammerLastActive = "No Activity"
[string]$YammerDaysSinceActive = "N/A"
$YammerPosts = 0
$YammerReads = 0
$YammerLikes = 0
} Else {
$YammerDaysSinceActive = (Out-String -InputObject $UserData.YDaysSinceActive).Trim()
$YammerPosts = (Out-String -InputObject $UserData.YPostedCount).Trim()
$YammerReads = (Out-String -InputObject $UserData.YReadCount).Trim()
$YammerLikes = (Out-String -InputObject $UserData.YLikedCount).Trim()
}
If ($UserData.TeamsDaysSinceActive -gt 0) {
[string]$TeamsDaysSinceActive = (Out-String -InputObject $UserData.TeamsDaysSinceActive).Trim()
[string]$TeamsLastActive = (Out-String -InputObject $UserData.TeamsLastActive).Trim()
} Else {
[string]$TeamsDaysSinceActive = "N/A"
[string]$TeamsLastActive = "No Activity"
}
If ($UserData.SPODaysSinceActive -gt 0) {
[string]$SPODaysSinceActive = (Out-String -InputObject $UserData.SPODaysSinceActive).Trim()
[string]$SPOLastActive = (Out-String -InputObject $UserData.SPOLastActive).Trim()
} Else {
[string]$SPODaysSinceActive = "N/A"
[string]$SPOLastActive = "No Activity"
}
# Fetch the sign in data if available
$LastAccountSignIn = $Null; $DaysSinceSignIn = 0
$LastAccountSignIn = $UserSignIns.Item($U)
If ($null -eq $LastAccountSignIn) {
$LastAccountSignIn = "No sign in data found"; $DaysSinceSignIn = "N/A"
} Else {
$DaysSinceSignIn = (New-TimeSpan($LastAccountSignIn)).Days
}
# Figure out if the account is used
[int]$ExoDays = 365; [int]$TeamsDays = 365; [int]$SPODays = 365; [int]$ODDays = 365; [int]$YammerDays = 365
# Base is 2 if someuse uses the five workloads because the Graph is usually 2 days behind, but we have some N/A values for days used
If ($ExoDaysSinceActive -ne "N/A") {$ExoDays = $ExoDaysSinceActive -as [int]}
If ($TeamsDaysSinceActive -eq "N/A") {$TeamsDays = 365} Else {$TeamsDays = $TeamsDaysSinceActive -as [int]}
If ($SPODaysSinceActive -eq "N/A") {$SPODays = 365} Else {$SPODays = $SPODaysSinceActive -as [int]}
If ($ODDaysSinceActive -eq "N/A") {$ODDays = 365} Else {$ODDays = $ODDaysSinceActive -as [int]}
If ($YammerDaysSinceActive -eq "N/A") {$YammerDays = 365} Else {$YammerDays = $YammerDaysSinceActive -as [int]}
# Average days per workload used...
$AverageDaysSinceUse = [Math]::Round((($ExoDays + $TeamsDays + $SPODays + $ODDays + $YammerDays)/5),2)
Switch ($AverageDaysSinceUse) { # Figure out if account is used
({$PSItem -le 8}) { $AccountStatus = "Heavy usage" }
({$PSItem -ge 9 -and $PSItem -le 50} ) { $AccountStatus = "Moderate usage" }
({$PSItem -ge 51 -and $PSItem -le 120} ) { $AccountStatus = "Poor usage" }
({$PSItem -ge 121 -and $PSItem -le 300 } ) { $AccountStatus = "Review account" }
default { $AccountStatus = "Account unused" }
} # End Switch
# And an override if someone has been active in just one workload in the last 14 days
[int]$DaysCheck = 14 # Set this to your chosen value if you want to use a different period.
If (($ExoDays -le $DaysCheck) -or ($TeamsDays -le $DaysCheck) -or ($SPODays -le $DaysCheck) -or ($ODDays -le $DaysCheck) -or ($YammerDays -le $DaysCheck)) {
$AccountStatus = "Account in use"}
If ((![string]::IsNullOrEmpty($ExoUPN))) {
# Build a line for the report file with the collected data for all workloads and write it to the list
$OutLine = [PSCustomObject] @{
UPN = $U
DisplayName = (Out-String -InputObject $UserData.ExoDisplayName).Trim()
Status = $AccountStatus
LastSignIn = $LastAccountSignIn
DaysSinceSignIn = $DaysSinceSignIn
EXOLastActive = $ExoLastActive
EXODaysSinceActive = $ExoDaysSinceActive
EXOQuotaUsed = (Out-String -InputObject $UserData.MbxQuotaUsed).Trim()
EXOItems = (Out-String -InputObject $UserData.MbxItems).Trim()
EXOSendCount = (Out-String -InputObject $UserData.ExoSendCount).Trim()
EXOReadCount = (Out-String -InputObject $UserData.ExoReadCount).Trim()
EXOReceiveCount = (Out-String -InputObject $UserData.ExoReceiveCount).Trim()
TeamsLastActive = $TeamsLastActive
TeamsDaysSinceActive = $TeamsDays
TeamsChannelChat = (Out-String -InputObject $UserData.TeamsChannelChats).Trim()
TeamsPrivateChat = (Out-String -InputObject $UserData.TeamsPrivateChats).Trim()
TeamsMeetings = (Out-String -InputObject $UserData.TeamsMeetings).Trim()
TeamsCalls = (Out-String -InputObject $UserData.TeamsCalls).Trim()
SPOLastActive = $SPOLastActive
SPODaysSinceActive = $SPODays
SPOViewedEditedFiles = (Out-String -InputObject $UserData.SPOViewedEdited).Trim()
SPOSyncedFiles = (Out-String -InputObject $UserData.SPOSyncedFileCount).Trim()
SPOSharedExtFiles = (Out-String -InputObject $UserData.SPOSharedExt).Trim()
SPOSharedIntFiles = (Out-String -InputObject $UserData.SPOSharedInt).Trim()
SPOVisitedPages = (Out-String -InputObject $UserData.SPOVisitedPages).Trim()
OneDriveLastActive = $ODLastActive
OneDriveDaysSinceActive = $ODDaysSinceActive
OneDriveFiles = $ODFiles
OneDriveStorage = $ODStorage
OneDriveQuota = $ODQuota
YammerLastActive = $YammerLastActive
YammerDaysSinceActive = $YammerDaysSinceActive
YammerPosts = $YammerPosts
YammerReads = $YammerReads
YammerLikes = $YammerLikes
License = (Out-String -InputObject $UserData.TeamsLicense).Trim()
OneDriveSite = (Out-String -InputObject $UserData.ODSite).Trim()
IsDeleted = (Out-String -InputObject $UserData.ExoIsDeleted).Trim()
EXOReportDate = (Out-String -InputObject $UserData.ExoReportDate).Trim()
TeamsReportDate = (Out-String -InputObject $UserData.TeamsReportDate).Trim()
UsageFigure = $AverageDaysSinceUse }
$OutData.Add($OutLine) }
} #End processing user data
Clear-Host
$StartTime4 = Get-Date
$GraphTime = $StartTime2 - $StartTime1
$PrepTime = $StartTime3 - $StartTime2
$ReportTime = $StartTime4 - $StartTime3
$ScriptTime = $StartTime4 - $StartTime1
$AccountsPerMinute = [math]::Round(($Outdata.count/($ScriptTime.TotalSeconds/60)),2)
$GraphElapsed = $GraphTime.Minutes.ToString() + ":" + $GraphTime.Seconds.ToString()
$PrepElapsed = $PrepTime.Minutes.ToString() + ":" + $PrepTime.Seconds.ToString()
$ReportElapsed = $ReportTime.Minutes.ToString() + ":" + $ReportTime.Seconds.ToString()
$ScriptElapsed = $ScriptTime.Minutes.ToString() + ":" + $ScriptTime.Seconds.ToString()
Write-Host " "
Write-Host "Statistics for Graph Report Script V2.0"
Write-Host "---------------------------------------"
Write-Host "Time to fetch data from Microsoft Graph:" $GraphElapsed
Write-Host "Time to prepare date for processing: " $PrepElapsed
Write-Host "Time to create report from data: " $ReportElapsed
Write-Host "Total time for script: " $ScriptElapsed
Write-Host "Total accounts processed: " $Outdata.count
Write-Host "Accounts processsed per minute: " $AccountsPerMinute
Write-Host " "
Write-Host "Output CSV file available in " $OutputCSV
$OutData | Sort-Object {$_.ExoLastActive -as [DateTime]} -Descending | Out-GridView
$OutData | Sort-Object $AccountStatus | Export-CSV $OutputCSV -NoTypeInformation
# 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.practical365.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.