Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Use this method when your report contains site IDs and you need human-readable URLs for analysis.
Before you begin
You must have the following items and permissions to do the tasks in thie article:
- A Microsoft 365 admin account
- Access to Microsoft Entra admin center
- Permission to register an application and grant admin consent
- The exported CSV files from:
If you need help downloading the reports or turning off privacy settings for user details, see Microsoft 365 admin center activity reports.
How it works
Microsoft Graph API provides an API that you can use to list all the sites within an organization. To use this API, you need an application with the Sites.Read.All permission.
The script calls this API endpoint to get the mapping between site IDs and site URLs. Then, it adds the site URLs into the exported CSV reports.
Why not use delegated permissions?
The
/sites/getAllSitesAPI only accepts application permissions.The
/sites?search=*API accepts delegated permissions, but it doesn't return all the sites, even when you use an admin account.
Use PowerShell to display site URLs
Step 1. Create a Microsoft Entra ID application
- Go to Microsoft Entra admin center > Applications > App registrations.
- On the App registrations page, select New registrations.
- Pick a name for this application, and use the default configuration to register the app.
The app's Essentials section displays the client id and tenant id.
Step 2. Add Graph API permission to the app
On the new application's Request API permissions page, add the Sites.Read.All permission.
Then, grant admin consent.
Step 3. Create a client secret
In the new application's Certificates & secrets section, create a new client secret. Then, store the secret's value in a safe and secure place.
Step 4. Download the reports in Microsoft 365 admin center
Download the site details report on the two report pages and put the CSV report files in a local folder.
Before downloading the reports, turn off the privacy setting for user details. For more information, see Microsoft 365 admin center activity reports.
For SharePoint site usage, go to the SharePoint site usage page in the Microsoft 365 admin center.
For OneDrive site usage, go to the OneDrive site usage page in the Microsoft 365 admin center.
Step 5. Update the reports with site URLs
To update the reports with site URLs, run the following PowerShell script.
.\Update-Report.ps1 -**tenantId** {tenant id above} -**clientId** {client id above} -**reportPaths** @("file path for report \#1", "file path for report \#2")
To view the full Update-Report PowerShell script, see Update-Report PowerShell.
The script asks you to enter the secret's value created in Step 3. Create a client secret.
After you run the script, it creates new versions of the reports with site URLs added.
Step 6. Clean up the environment
To clean up the environment, go back to the application's Certificates & secrets page and delete the secret that you created earlier.
Tip
Use an SSD (solid-state drive) to improve the I/O performance. Run the script on a machine with enough free or unused memory. The cache uses roughly 2 GB for the 15 million sites.
Update-Report PowerShell script
The following script is the PowerShell script for Update-Report.
param(
[Parameter(Mandatory=$true)]
[string]$tenantId,
[Parameter(Mandatory=$true)]
[string]$clientId,
[Parameter(Mandatory=$false)]
[string[]]$reportPaths
)
function Get-AccessToken {
param(
[Parameter(Mandatory=$true)]
[string]$tenantId,
[Parameter(Mandatory=$true)]
[string]$clientId,
[Parameter(Mandatory=$true)]
[System.Security.SecureString]$clientSecret,
[Parameter(Mandatory=$false)]
[string]$scope = "https://graph.microsoft.com/.default"
)
$tokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$tokenRequest = @{
client_id = $clientId
scope = $scope
client_secret = ConvertFrom-SecureString $clientSecret -AsPlainText
grant_type = "client_credentials"
}
$tokenResponse = Invoke-RestMethod -Uri $tokenEndpoint -Method Post -Body $tokenRequest
return $tokenResponse.access_token
}
Prepare the cache and client secret
if ($reportPaths.Count -eq 0) {
Write-Host "Please provide at least one report path" -ForegroundColor Red
exit
}
$cache = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
$clientSecret = Read-Host "Please enter client secret" -AsSecureString
Fetch site info from Graph API
Write-Host
Write-Host "Getting information for all the sites..." -ForegroundColor Cyan
$uri = "https://graph.microsoft.com/v1.0/sites/getAllSites?`$select=sharepointIds&`$top=10000"
while ($uri -ne $null) {
Write-Host $uri
$isSuccess = $false
while (-not $isSuccess) {
try {
$accessToken = Get-AccessToken -tenantId $tenantId -clientId $clientId -clientSecret $clientSecret
$restParams = @{Headers=@{Authorization="Bearer $accessToken"}}
}
catch {
Write-Host "Retrying... $($_.Exception.Message)" -ForegroundColor Yellow
continue
}
try {
$sites = Invoke-RestMethod $uri @restParams
$isSuccess = $true
}
catch {
if ($_.Exception.Response -and $_.Exception.Response.Headers['Retry-After']) {
$retryAfter = [int]$_.Exception.Response.Headers['Retry-After']
Write-Output "Waiting for $retryAfter seconds before retrying..." -ForegroundColor Yellow
Start-Sleep -Seconds $retryAfter
}
Write-Host "Retrying... $($_.Exception.Message)" -ForegroundColor Yellow
continue
}
}
$sites.value | ForEach-Object {
$cache[$_.sharepointIds.siteId] = $_.sharepointIds.siteUrl
}
$uri = $sites."@odata.nextLink"
Write-Host "Total sites received: $($cache.Count)"
}
Update the report using cached site info
foreach ($reportPath in $reportPaths) {
Write-Host
Write-Host "Updating report $($reportPath) ..." -ForegroundColor Cyan
$outputPath = "$($reportPath)_$([Math]::Floor((Get-Date -UFormat %s))).csv"
$writer = [System.IO.StreamWriter]::new($outputPath)
$reader = [System.IO.StreamReader]::new($reportPath)
$rowCount = 0
while ($null -ne ($line = $reader.ReadLine())) {
$rowCount++
$columns = $line.Split(",")
$siteId = $columns[1]
$_guid = New-Object System.Guid
if ([System.Guid]::TryParse($siteId, [ref]$_guid)) {
$siteUrl = $cache[$siteId]
$columns[2] = $siteUrl
$line = $columns -join ","
}
$writer.WriteLine($line)
if ($rowCount%1000 -eq 0) {
Write-Host "Processed $($rowCount) rows"
}
}
$writer.Close()
$reader.Close()
Write-Host "Processed $($rowCount) rows"
Write-Host "Report updated: $($outputPath)" -ForegroundColor Cyan
}
Finalize
Write-Host
Read-Host "Press any key to exit..."
Next steps
- Need help downloading or configuring usage reports? See Microsoft 365 admin center activity reports.
- Need API details for SharePoint sites? See site resource type.
- Need API details for OneDrive drives? See drive resource type.
- Working with only a few sites instead of full reports? See Extra option for small-scale scenarios.
Extra option for small-scale scenarios
For smaller scale scenarios, admins with appropriate access can use the SharePoint REST API or Microsoft Graph API to retrieve information about site IDs referenced in affected reports.