How to get all sites from the tenant using MS Graph API?

Summary

The PnP PowerShell command Get-PnPTenantSite to get all sites from the tenant takes longer time. Additionally, it does not have asynchronous ways to get the information in the Azure Durable Function.

This article uses the MS Graph API List Sites to get the sites. To use this API the following Application API permissions required for the Azure AD app.

Sites.Read.All, Sites.ReadWrite.All

Script

$StartMs = (Get-Date).Millisecond

# You will need Azure AD app with the following API permissions.
# Application	Sites.Read.All
#
$ClientId          = "TODO"
$ClientSecret      = "TODO"
$tenantid          = "TODO"
$path2File         = 'C:\temp\test.txt' # Change this as you like.

## Get Auth Token ## 
$headersAuth = @{
    "Content-Type" = "application/x-www-form-urlencoded"
    'Accept' = '*/*'
}
$body = $("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default" -f $ClientId, $ClientSecret)
$outhTokenUrl = $("https://login.microsoftonline.com/{0}/oauth2/v2.0/token" -f $tenantid)
$response = Invoke-RestMethod $outhTokenUrl -Method 'POST' -Headers $headersAuth -Body $body
$response | ConvertTo-Json
$tokenExpiryTime = (get-date).AddSeconds($response.expires_in)
##
## Make the first call with $filer to your tenant name ##
##
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Content-Type", "application/json")
$headers.Add("SdkVersion", "postman-graph/v1.0")
$headers.Add("Prefer", "apiversion=2.1")
$headers.Add("Authorization", $("Bearer {0}" -f $response.access_token) )
$response = Invoke-RestMethod 'https://graph.microsoft.com/v1.0/sites?$filter=siteCollection/hostname eq ''{CHANGE TO YOUR TENANT NAME}.sharepoint.com''' -Method 'GET' -Headers $headers
$response | ConvertTo-Json
## Check if there are more sites to fetch...
while ( $response.'@odata.nextLink' -ne $null )
{
    ## iterate on the response and write the site url to the file.
    foreach ( $val in $response.Value )
    {
        Write-Output $("{0}" -f $val.webUrl)
        Add-Content -Path $path2File -Value $val.webUrl
    }
    # check if the token expired, if it did get a new one.
    if ( (get-date) -gt  $tokenExpiryTime )
    {
        $response = Invoke-RestMethod "https://login.microsoftonline.com/$($tenantid)/oauth2/v2.0/token" -Method 'POST' -Headers $headers -Body $body
        $response | ConvertTo-Json

        $tokenExpiryTime = (get-date).AddSeconds($response.expires_in)

        # modify header with the new token
        $headers = @{
            "Content-Type" = "application/json"
            "Authorization" = $("Bearer {0}" -f $response.access_token) 
        }
    }

    # first store the data of Web URL to the file.

    $response = Invoke-RestMethod $response.'@odata.nextLink' -Method 'GET' -Headers $headers
    $response | ConvertTo-Json 

}
$EndMs = (Get-Date).Millisecond
WriteHost "This script took $($EndMs - $StartMs) milliseconds to run."

Conclusion

Using MS Graph API you can overcome to get the list of all sites within your tenant. This can be done using the Get-PnPTenantSite but it has overheads if you just want the site urls of all sites.

About Pankaj

I am a Developer and my linked profile is https://www.linkedin.com/in/pankajsurti/
This entry was posted in MS Graph, SharePoint. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s