Graph API: Query Teams Provisioned SPO Sites


Usage of Microsoft Teams boomed under COVID-19 shelter in place orders. For organizations with Office 365 licenses, Teams facilitated remote collaboration, but each newly created team provisions a [SharePoint Online] site collection.

Post-quarantine, organizations may want to audit their Teams’ provisioned SPO sites. And if end-users aren’t restricted from creating teams, then there will be plenty of sites mistakenly created by curious individuals. Though these teams can be queried using PowerShell and the Graph API…

Note:

Microsoft currently supports 2 million site collections per tenant.


Create request header:

  • Provide {clientID}
  • Provide [clientSecret}
function Get-GraphAPIHeader {
    [System.String] $TenantName = "{tenantName}.onmicrosoft.com"
    [System.String] $Url = "https://login.microsoftonline.com/$($TenantName)/oauth2/v2.0/token"

    $PostSplat = @{
        ContentType = "application/x-www-form-urlencoded"
        Method = "POST"
        Body = @{
            client_id = "{clientID}"
	    client_secret = "{clientSecret}"
	    scope = "https://graph.microsoft.com/.default"
	    grant_type = "client_credentials"
        }
        Uri = "$Url"
    }
    $Request = Invoke-RestMethod @PostSplat
    return @{
        Authorization = "$($Request.token_type) $($Request.access_token)"
    }
}

Batch Requests:

This function accepts an array of batch APIs, then creates the JSON object for the batch request…

function Get-GraphApiBatchResponse {
    param(
        [System.String] $GraphAPI = "https://graph.microsoft.com/v1.0",
        [Parameter(Mandatory)] [System.Array] $ArrayOfBatchRequests
    )

    $JSON = @{
        "requests" = $ArrayOfBatchRequests
    } | ConvertTo-Json -Depth 5
    $JSON | Out-Host

    return Invoke-RestMethod `
        -Uri "$($GraphAPI)/`$batch" `
        -Headers (Get-GraphAPIHeader) `
        -Body $JSON `
        -Method POST `
        -ContentType "application/json" `
        -UseBasicParsing
}

Query Office Groups:

Office 365 groups differ from AD Security Groups. Both are used to manage user permissions, but Office groups are user-managed rather than IT-managed. Additionally, Office groups are created and used by:

  • Microsoft Stream
  • Microsoft Teams
  • Microsoft Planner
  • etc.

The following function queries the tenant Office groups and iterates only the mail-enabled groups. With this smaller subset, the Teams provisioned groups are added to the hash table, $listOf:

function Get-GraphAPIGroups {
    $requests = @()
    $requests += @{
        "url" = "/groups"
        "method" = "GET"
        "id" = "1"
    }
    
    $listOf = @{}
    $response = Get-GraphApiBatchResponse -ArrayOfBatchRequests $requests
    $response.responses.body.value | ?{$_.mailEnabled -eq $true} | % {

        if ($_.creationOptions.Contains("Team")) {
            $listOf["$($_.mailNickname)"] = ""
        }
    }
    return $listOf
}

ex., PowerShell Output


Search SPO Sites:

For the list of Office groups, each entry is queried for a respective SPO site:

function Get-GraphAPISPOSiteIDs {
    param(
        [System.String] $GraphAPI = "https://graph.microsoft.com/v1.0",
        [Parameter(Mandatory)] [System.Collections.Hashtable] $HashOfSPOSites
    )

    $index = 1
    $requests = @()
    $HashOfSPOSites.GetEnumerator() | Sort-Object Key | % {

        $requests += @{
            "url" = "/sites?search=$($_.Key)"
            "method" = "GET"
            "id" = "$index"
        }
        $index++
    }

    $response = Get-GraphApiBatchResponse -ArrayOfBatchRequests $requests
    $response.responses | % {
        $temp = $_.body.value
        $HashOfSPOSites[$temp.name] = $temp.webUrl
    }
    return $HashOfSPOSites
}

ex., PowerShell Output


Output SPO Site URLs:

Pass the output of the first function as a parameter to the section function.

Get-GraphAPISPOSiteIDs -HashOfSPOSites (Get-GraphAPIGroups)

ex., PowerShell Output


Conclusion:
Post-pandemic audits should be interesting if the organization cares how many SPO sites currently exist. But determining which sites were provisioned from Microsoft Teams is simple enough…

“Mistakes are a fact of life. It is the response to the error that counts.”

Nikki Giovanni

2 thoughts on “Graph API: Query Teams Provisioned SPO Sites

    • Hi, Vas. Currently, the Graph API can only query active sites. You’ll need to use the “Get-SPODeletedSite” commandlet of the SharePointOnlinePowerShell module to search the recycle bin…

      Like

Leave a reply to vas Cancel reply