What’s the Best Way to Find SharePoint Online Sites with Graph PowerShell?

Considering the Use of the Get-MgSite and Get-MgAllSite Cmdlets

SharePoint Online retrieving sites with PowerShell.

Get-MgAllSite.

A reader asked if the the getAllSites Graph API is the best way to retrieve details of SharePoint Online sites with PowerShell. On the surface, the API seems like a good way for apps to fetch details of SharePoint Online sites for processing, especially in multi-geo scenarios, which is why the API exists. The API can also fetch sites for a single-geo tenant. It is implemented as the Get-MgAllSite cmdlet in the Microsoft Graph PowerShell SDK.

The Get Site API also fetches information about sites (implemented as the Get-MgSite cmdlet). The two APIs return sites ordered by creation date, with the most recent sites returned first. Two major differences exist. First, the API only supports the retrieval of sites for single-geo tenants. Second, the Get Site API supports both delegated (for access to the sites is a signed-in member of) and application permissions whereas the getAllSites API only supports application permissions.

The permissions gap means that a SharePoint administrator can sign into an interactive Microsoft Graph PowerShell SDK session and list sites with Get-MgSite, but they cannot use Get-MgAllSite because it doesn’t support delegated permissions.

The problem is easily solved by creating an Entra ID registered app and assigning the Sites.Read.All application permission to the app. You can then use an X.509 certificate (recommended) or app secret (for testing only) to authenticate in app-only mode and use the Get-MgAllSite cmdlet.

In terms of performance, Get-MgAllSite seems to be slightly faster than Get-MgSite. Both cmdlets retrieve the same set of site properties, so there’s no obvious reason why one might be better than the other. In any case, from a practical perspective, there’s nothing to choose in terms of speed when retrieving all sites. Let’s see hopw to find sites with the two cmdlets.

Filtering to Find Sites

To find all sites in a tenant, sign into an app-only session, and run the Get-MgSite cmdlet with the All parameter:

[array]$Sites = Get-MgSite -All

Get-MgAllSite doesn’t have an All parameter and although I have tested it to find > 600 sites without a hitch, I don’t know how it will cope with larger tenants. However, the cmdlet can use filtering to avoid the need to fetch all sites. For example, here’s how to find the set of personal (OneDrive for Business) sites in a tenant. Once again, we’re using app-only mode:

[array]$Sites = Get-MgAllSite -filter "isPersonalSite eq true"

Filtering against a site display name is also supported:

Get-MgAllSite -Filter "displayname eq 'Ultimate Guide to Office 365'"

Another example is using the startsWith operator to find sites:

$Site = Get-MgAllSite -filter "startsWith(displayName,'Ultimate Guide')"

You can also filter to find sites based on the creation date. This example shows how to retrieve sites created in the last month.

$FirstDayOfMonth = (Get-Date -Day 1).ToString('yyyy-MM-ddT00:00:00Z')
Get-MgAllSite -Filter "createdDateTime ge $FirstDayOfMonth"

Get-MgSite can’t filter using the isPersonalSite, DisplayName, or CreationDateTime properties and responds with “Get-MgSite_List: Cannot enumerate sites.”

The closest the Get-MgSite cmdlet gets to filtering is via the Search parameter (which isn’t supported by the Get-MgAllSite cmdlet):

Get-MgSite -Search "Ultimate Guide"

Why Filter Sites with One Cmdlet and Not the Other?

I don’t know why the Get Site API doesn’t support filtering in the same way as the getAllSites API does. Given the apparent similarities between the two APIs in terms of performance and output, there doesn’t appear to be a good reason why the developers chose not to implement filtering for the Get Site API.

Even though the Get-MgSite cmdlet can retrieve all sites, perhaps the reason for the different behavior across the two APIs is because the purpose of the Get Site API is to retrieve details of individual sites. By comparison, the getAllSites API exists to retrieve sets of sites when filtering obviously becomes more important and is therefore implemented. If so, the documentation could clarify the situation better than it does.

Avoid the Top Parameter

Although Get-MgAllSite supports filtering, it currently has a problem when combining filters with the Top parameter. Two issues exist. First, performance (both cmdlet and API request) is much slower when the Top parameter is used. Second, the API ignores the Top parameter and returns all sites that match the filter instead of the number of hits specified in the parameter. For instance, this command returns all the sites created in the last month:

Get-MgAllSite -Filter "createdDateTime ge $FirstDayOfMonth" -Top 1

The problem is reported as issue #3405 for V2.30 of the Microsoft Graph PowerShell SDK.

Mix and Match as the Need Arises

My advice is to use Get-MgSite whenever an app needs to retrieve details of a single site and Get-MgAllSite to fetch details of multiple sites (but only in app-only mode). Both cmdlets include the site identifier in the properties they return, and that’s the critical piece of information for further interaction with sites through Microsoft Graph PowerShell SDK cmdlets or API requests (like this example of accessing site pages or this one of creating a list in a site).


Need some assistance to write and manage PowerShell scripts for Microsoft 365, including Azure Automation runbooks? Get a copy of the Automating Microsoft 365 with PowerShell eBook, available standalone or as part of the Office 365 for IT Pros eBook bundle.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.