Back to script library
Entra / Microsoft 365 · Teams

Audit Teams meeting recording uploads

Uses Office 365 audit log records to track uploads of Teams meeting recordings to SharePoint or OneDrive.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShell
# Make sure that you use the right URL for your tenant here
Connect-SPOService -Url https://office365itpros-admin.sharepoint.com

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

param(
[int] $LookbackDays = 180,
[string] $StartDate = (Get-Date).AddDays(-$LookbackDays),
[string] $EndDate = "Get-Date"
)
Write-Host "Connecting to SharePoint Online to fetch details of OneDrive for Business sites..."
# This part is to generate a hash table of OneDrive sites that we can use to look up for audit records
Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShell
# Make sure that you use the right URL for your tenant here
Connect-SPOService -Url https://office365itpros-admin.sharepoint.com
[array]$OneDriveSites = Get-SPOSite -IncludePersonalSite $true -Limit All `
-Filter "Url -like '-my.sharepoint.com/personal/'" | Select-Object URL, Owner
# Build the hash table
$OneDriveHashTable = @{}
ForEach ($Site in $OneDriveSites) {
[string]$SiteKey = $Site.URL + "/"
$OneDriveHashTable.Add($SiteKey, $Site.Owner)
}
# Connect to Exchange Online, if we're not already connected
$Modules = Get-Module | Select-Object -ExpandProperty Name
If ("ExchangeOnlineManagement" -notin $Modules) {
Write-Host "Connecting to Exchange Online..."
Connect-ExchangeOnline -SkipLoadingCmdletHelp
}
Write-Host "Searching for Teams recordings upload audit records..."
[array]$Records = Search-UnifiedAuditLog -Operations FileUploaded, FileModified `
-StartDate $StartDate -EndDate $EndDate -Formatted -ResultSize 5000 -SessionCommand ReturnLargeSet `
-UserIds "app@sharepoint" -RecordType SharePointFileOperation
If (!($Records)) {
Write-Host "No audit records found - exiting!"; break
}
# Remove duplicates and make sure that we have a set sorted by date
$Records = $Records | Sort-Object Identity -Unique | Sort-Object {$_.CreationDate -as [datetime]} -Descending
$TaggedRecordings = [System.Collections.Generic.List[Object]]::new()
ForEach ($Rec in $Records) {
$AuditData = $Rec.AuditData | ConvertFrom-Json
If (($AuditData.SourceFileExtension -eq "mp4") -and ($AuditData.SourceRelativeUrl -like "*/Recordings") `
-and $AuditData.SourceFileName.Substring(0,4) -ne "~tmp") {
$RecordingFileName = $AuditData.SourceFileName
$DateLoc = $RecordingFileName.IndexOf("-202")
If ($DateLoc -eq -1) {
$Topic = $RecordingFileName
} Else {
$Topic = $RecordingFileName.SubString(0,$DateLoc)
}
# All uploads are performed by the app@sharepoint account, so we try to use the hash table
# to figure out the owner of the target OneDrive for Business account
$User = $OneDriveHashTable[$AuditData.SiteURL]
If ($null -eq $User) {
$User = "SharePoint app"
}
$CreationDate = Get-Date $Rec.CreationDate -format 'dd-MMM-yyyy HH:mm:ss'
$DataLine = [PSCustomObject] @{
Workload = $AuditData.Workload
Operation = $Rec.Operations
Date = $CreationDate
User = $User
Recording = $RecordingFileName
"Meeting title" = $Topic
Site = $AuditData.SiteURL
FullURL = $AuditData.ObjectId
Folder = $AuditData.SourceRelativeURL
}
$TaggedRecordings.Add($DataLine)
} #End If
} #End For
$TaggedRecordings = $TaggedRecordings | Sort-Object {$_.Date -as [datetime]} -Descending
$CSVOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\TeamsRecordings.csv"
$TaggedRecordings | Out-GridView -Title 'Teams Recordings Uploads'
$TaggedRecordings | Export-CSV -NoTypeInformation $CSVOutputFile -Encoding utf8

Parameters

ParameterDefaultNotes
-LookbackDays180How many days back to search for newly created mailboxes or recent activity.
-StartDate(Get-Date).AddDays(-180)Start of the reporting window.
-EndDateGet-DateEnd of the reporting window.
Attribution