Skip to content

Instantly share code, notes, and snippets.

@AlexanderHolmeset
Last active August 3, 2022 20:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexanderHolmeset/5d9d9180a1aa8ff4eb2474b8e859ad95 to your computer and use it in GitHub Desktop.
Save AlexanderHolmeset/5d9d9180a1aa8ff4eb2474b8e859ad95 to your computer and use it in GitHub Desktop.
TeamsFiletypesStatistics
### Teams Filetype Statistics ###
### Version 1.1 ###
### Author: Alexander Holmeset ###
### Email: alexander.holmeset@gmail.com ###
### Twitter: twitter.com/alexholmeset ###
### Blog: alexholmeset.blog ###
#Need Azure App registration with Groupd.Read.All and Site.Read.All permissions.
$TenantId = "xxxxxxxx"
$ClientID = "xxxxxxxx"
$ClientSecret = "xxxxxxxx"
$TeamsStatsTotal = [PSCustomObject]@()
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
function Get-MSGraphAppToken{
<# .SYNOPSIS
Get an app based authentication token required for interacting with Microsoft Graph API
.PARAMETER TenantID
A tenant ID should be provided.
.PARAMETER ClientID
Application ID for an Azure AD application. Uses by default the Microsoft Intune PowerShell application ID.
.PARAMETER ClientSecret
Web application client secret.
.EXAMPLE
# Manually specify username and password to acquire an authentication token:
Get-MSGraphAppToken -TenantID $TenantID -ClientID $ClientID -ClientSecert = $ClientSecret
.NOTES
Author: Jan Ketil Skanke
Contact: @JankeSkanke
Created: 2020-15-03
Updated: 2020-15-03
Version history:
1.0.0 - (2020-03-15) Function created
#>
[CmdletBinding()]
param (
[parameter(Mandatory = $true, HelpMessage = "Your Azure AD Directory ID should be provided")]
[ValidateNotNullOrEmpty()]
[string]$TenantID,
[parameter(Mandatory = $true, HelpMessage = "Application ID for an Azure AD application")]
[ValidateNotNullOrEmpty()]
[string]$ClientID,
[parameter(Mandatory = $true, HelpMessage = "Azure AD Application Client Secret.")]
[ValidateNotNullOrEmpty()]
[string]$ClientSecret
)
Process {
$ErrorActionPreference = "Stop"
# Construct URI
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
# Construct Body
$body = @{
client_id = $clientId
scope = "https://graph.microsoft.com/.default"
client_secret = $clientSecret
grant_type = "client_credentials"
}
try {
$MyTokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
$MyToken =($MyTokenRequest.Content | ConvertFrom-Json).access_token
If(!$MyToken){
Write-Warning "Failed to get Graph API access token!"
Exit 1
}
$MyHeader = @{"Authorization" = "Bearer $MyToken" }
}
catch [System.Exception] {
Write-Warning "Failed to get Access Token, Error message: $($_.Exception.Message)"; break
}
return $MyHeader
}
}
#Generate Graph API Token
$global:Header = Get-MSGraphAppToken -TenantID $TenantId -ClientID $ClientID -ClientSecret $ClientSecret
#URL to SharePoint list with expand fields.
$currentUri = "https://graph.microsoft.com/v1.0/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')"
#Gets entrys in SharePoint list.
$Teams = while (-not [string]::IsNullOrEmpty($currentUri)) {
# API Call
# Write-Host "`r`nQuerying $currentUri..." -ForegroundColor Yellow
$apiCall = Invoke-WebRequest -Method "GET" -Uri $currentUri -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing
$nextLink = $null
$currentUri = $null
if ($apiCall.Content) {
# Check if any data is left
$nextLink = $apiCall.Content | ConvertFrom-Json | Select-Object '@odata.nextLink'
$currentUri = $nextLink.'@odata.nextLink'
$apiCall.Content | ConvertFrom-Json
}
}
$Teams = $Teams.value
$count = 0
foreach($team in $teams){
If($stopwatch.Elapsed.minutes -gt 40) {
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
#Generate Graph API Token
$global:Header = Get-MSGraphAppToken -TenantID $TenantId -ClientID $ClientID -ClientSecret $ClientSecret
}
$count++
$count
$filetypes = @()
$teamschannelsURL = "https://graph.microsoft.com/v1.0/teams/$($team.id)/channels"
$teamchannels = (Invoke-RestMethod -Method "GET" -Uri $teamschannelsURL -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing).value
foreach($channel in $teamchannels){
if($channel.membershiptype -eq "private"){
$channelURL = $teamschannelsURL+"/$($channel.id)/filesfolder"
$channelinfo = (Invoke-RestMethod -Method "GET" -Uri $channelURL -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing).parentReference.driveid
$driveurl = "https://graph.microsoft.com/v1.0/drives/$channelinfo/list"
$PrivateList = Invoke-RestMethod -Method "GET" -Uri $driveurl -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing
$PrivateListID = $PrivateList.id
$PrivateSiteID = ((($PrivateList.parentReference).siteid).split(".com,")[1]).split(",")[0]
$PrivateSharePointDocumentsURL = "https://graph.microsoft.com/v1.0/sites/$privatesiteid/lists/$privatelistid/items"
$currentUri = $PrivateSharePointDocumentsURL
#Gets entrys in SharePoint list.
$Documents = @()
$Documents = while (-not [string]::IsNullOrEmpty($currentUri)) {
# API Call
# Write-Host "`r`nQuerying $currentUri..." -ForegroundColor Yellow
$apiCall = Invoke-WebRequest -Method "GET" -Uri $currentUri -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing
$nextLink = $null
$currentUri = $null
if ($apiCall.Content) {
# Check if any data is left
$nextLink = $apiCall.Content | ConvertFrom-Json | Select-Object '@odata.nextLink'
$currentUri = $nextLink.'@odata.nextLink'
$apiCall.Content | ConvertFrom-Json
}
}
$Documents = $Documents.value | Where-Object{($_.contenttype).name -eq "Document"}
$filetypes += $Documents.weburl -replace '.*\.' | select-string -Pattern '^[^\s]{3,4}$'
}
}
$TeamSharePointID = @()
$TeamSharePointID = $team.proxyAddresses | Where-Object { $_ -like 'SPO:*' }
$TeamSharePointID = ($TeamSharePointID.split("SPO:SPO_")[1]).split("@SPO_")[0]
$SharePointListsURL = "https://graph.microsoft.com/v1.0/sites/$TeamSharePointID/lists/"
$SharePointList = (Invoke-RestMethod -Method "GET" -Uri $SharePointListsURL -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing).value | where-object { $_.name -eq 'Shared Documents' }
$SharePointDocumentsURL = @()
$SharePointDocumentsURL = $SharePointListsURL+$SharePointList.id+"/items"
#URL to SharePoint list with expand fields.
$currentUri = $SharePointDocumentsURL
#Gets entrys in SharePoint list.
$Documents = @()
$Documents = while (-not [string]::IsNullOrEmpty($currentUri)) {
# API Call
# Write-Host "`r`nQuerying $currentUri..." -ForegroundColor Yellow
$apiCall = try{Invoke-WebRequest -Method "GET" -Uri $currentUri -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing} Catch{Start-Sleep -Seconds 10;Invoke-WebRequest -Method "GET" -Uri $currentUri -ContentType "application/json" -Headers $global:Header -ErrorAction Stop -UseBasicParsing }
$nextLink = $null
$currentUri = $null
if ($apiCall.Content) {
# Check if any data is left
$nextLink = $apiCall.Content | ConvertFrom-Json | Select-Object '@odata.nextLink'
$currentUri = $nextLink.'@odata.nextLink'
$apiCall.Content | ConvertFrom-Json
}
}
$Documents = $Documents.value | Where-Object{($_.contenttype).name -eq "Document"}
$filetypes += $Documents.weburl -replace '.*\.' | select-string -Pattern '^[^\s]{3,4}$'
$filetypesUnique = $filetypes | Sort-Object -Unique
write-output "FileTypes Unique: $($filetypesUnique.count)"
foreach($filetype in $filetypesUnique){
$datemodified = @()
$datemodified = (($datemodified = $Documents | Where-Object { $_.weburl -like "*$filetype" } ).lastModifiedDateTime | Sort-Object -descending)[0]
If(!$datemodified){$datemodified = 0}
$TeamStatsObject = @()
$TeamStatsObject = [PSCustomObject]@{
Displayname = $team.displayName
ObjectID = $team.id
Type = $filetype
Count = ($filetypes | Where-Object { $_ -eq $filetype }).count
LastModified = $datemodified
}
$TeamsStatsTotal += $TeamStatsObject
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment