Upgrading the Teams and Groups Activity Report to 6.0

Updating Old Code to Use the Microsoft Graph PowerShell SDK

Teams and Groups activity report

The Teams and Groups Activity Report is a reasonably popular script which attempts to measure whether teams and groups are in active use based on criteria like the number of messages sent in a team. Processes like this are important because it’s all too easy for a Microsoft 365 tenant to fall into a state of digital rot where unused teams and groups mask where useful work is done.

But like many scripts, the code has evolved over years (since 2016 in this case). The current version uses many Graph API calls and some Exchange Online cmdlets to fetch and analyze statistics. Microsoft recently released the Entra PowerShell module, which is built on top of the Microsoft Graph PowerShell SDK. I think this is a mistake because there are many issues that Microsoft should address in the PowerShell SDK. Dividing their engineering resources and focus across two modules seems like a recipe for inadequacy instead of excellence.

To prove the usefulness of the Microsoft Graph PowerShell SDK, it seemed like a good idea to rewrite the Teams and Groups activity report and replace Graph API requests with PowerShell SDK cmdlets wherever possible. The new Entra PowerShell module is incapable of the task because it deals exclusively with Entra objects, and the script needs to access elements like usage reports to determine if a group or team is active.

Microsoft Graph PowerShell SDK Advantages

By converting to the Microsoft Graph PowerShell SDK, I wanted to take advantages of two specific features offered by the SDK cmdlets. First, you don’t need to worry about pagination. Second, you don’t need to deal with access token acquisition and renewal. Many SDK cmdlets like Get-MgGroup have an All parameter, which instructs a cmdlet to perform automatic pagination to fetch all available items. Token acquisition and renewal is handled automatically for Graph SDK interactive or app-only sessions.

The old version of the script handles pagination and token renewal, but scripts require code to handle these tasks. Extra code means extra places where things can go wrong, and that’s always a concern.

The value passed to the PageSize parameter is another important factor for performance. Cranking its value up to 999 (or whatever the maximum supported value is for a resource like groups) reduces the number of Graph requests required to fetch data, a factor that can be very important when dealing with thousands of groups and teams.

Upgrading Script Code

Like all PowerShell scripts that use Graph API requests, the previous version uses an Entra ID application (or rather, the application’s service principal) to hold the Graph permissions used by the script.

The same technique can be used with the Microsoft Graph PowerShell SDK. In fact, it’s the right way to confine apps to the limited set of permissions necessary to do whatever processing they perform. Using an Entra ID registered app to connect to the Graph means that application permissions are used rather than delegated permissions and therefore the script has access to all data consented through permissions rather than just the data available to the signed-in account, which is the case with an interactive Graph session.

Here’s the code to connect a Graph session in app-only mode. The code specifies the tenant identifier, application identifier, and a certificate thumbprint. After connection, the script can use any permission consented to for the application.

$TenantId = "a662313f-14fc-43a2-9a7a-d2e27f4f3478"
$AppId = "a28e1143-88e3-492b-bf82-24c4a47ada63"
$CertificateThumbprint = "F79286DB88C21491110109A0222348FACF694CBD"
# Connect to the Microsoft Graph
Connect-MgGraph -NoWelcome -AppId $AppId -CertificateThumbprint $CertificateThumbprint -TenantId $TenantId

In the case of the script, the application must hold consent for the Group.Read.All, Reports.Read.All, User.Read.All, GroupMember.Read.All, Sites.Read.All, Organization.Read.All, and Teams.ReadBasic.All application permissions.

Some Hiccups

Like all coding projects, some hiccups occurred.

First, the cmdlets to fetch usage report data don’t seem to be capable of saving the data to a PSObject. Instead, the data must be saved to a temporary CSV file and then imported into an array. Also in this area, the annoying bug that prevents SharePoint usage data returning site URLs persists. It’s only been present since September 2023!

Second, the Get-MgSite cmdlet returned a 423 “site locked” error for some sites when retrieving site information. As it turned out, the sites were archived by Microsoft 365 Archive. Unfortunately, the Get-MgSite cmdlet doesn’t have an IsArchived property to filter against.

Third, it’s always better for performance to have the Graph return sorted information instead of fetching data and then sorting it with the Sort-Object cmdlet. When fetching groups, the original script used Sort-Object to sort the objects by display name. I converted this code to:

[array]$Groups = Get-MgGroup -Filter "groupTypes/any(a:a eq 'unified')" -PageSize 999 -All `
-Property id, displayname, visibility, assignedlabels, description, createdDateTime, renewedDateTime, drive -Sort "displayname DESC"

Get-MgGroup_List: Sorting not supported for current query.

The command didn’t work and the error isn’t as helpful as it could be. The reason for the failure is that adding a sort converts the query from a standard to an advanced query, which means that you need to add the ConsistencyLevel and CountVar parameters. Here’s a working version of the command:

[array]$Groups = Get-MgGroup -Filter "groupTypes/any(a:a eq 'unified')" -PageSize 999 -All `
-Property id, displayname, visibility, assignedlabels, description, createdDateTime, renewedDateTime, drive -Sort "displayname DESC" -ConsistencyLevel eventual -CountVar GroupCount

Oddly, the Get-MgTeam cmdlet doesn’t support the ConsistencyLevel parameter so you cannot sort a list of teams except by sorting the objects fetched by Get-MgTeam with the Sort-Object cmdlet.

A Successful Conversion

I am happy with the migration. There are about 10% fewer lines of code in the Graph SDK version of the script, and everything works as expected. Or so I think. If you want to see the converted script, you can download it from GitHub.


Learn more about how the Office 365 applications really work on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.

One Reply to “Upgrading the Teams and Groups Activity Report to 6.0”

Leave a Reply

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