Updated version of the Reporting on Teams apps and tabs script

Two years back, I published a short “proof of concept” script that helps you enumerate Teams apps and tabs across all your organization’s Teams. Due to some recent changes in the Graph API endpoints required to use the script, it’s time for an updated version.

Probably the most important change that has happened since the original script was released is around permissions. While previously it was possible to leverage “wide” permissions such as Group.Read.All, Group.ReadWrite.All, Directory.Read.All, or Directory.ReadWrite.All, these are no longer supported for the relevant Graph API endpoints. Instead, we should use “narrower” scopes such as Team.ReadBasic.All, TeamsAppInstallation.ReadForTeam.All and TeamsTab.Read.All. While this change doesn’t directly affect the script itself, you need to make sure the corresponding Azure AD application has been updated with the relevant scopes.

Still, I took the opportunity to rework the authentication part a bit, and it should be much cleaner now. I’d still recommend plugging in your preferred “get token” function instead, especially if you are working for a larger organizations with gazillion teams. At the very least, make sure to add some proper error handling and token renewal logic.

Another small change that was made is to leverage the LIST method for the /teams endpoint, which is now available in beta. So we no longer need to query Groups instead. While the current version of said method has some limitations, for the purposes of our script we only need the team ID and name, so it will do just fine.

The last change made to the script is to add some additional properties to the output, thanks to the availability of the teamsAppDefinition resource, which we can now fetch as part of the single query we run against the /installedApps endpoint, per team. Such properties include the Version of the app, the ID of the Azure AD Application used by it, if any, the Description, and available installation scopes. On the Tabs front, information about the date the tab was added will be presented in some case. Unfortunately, many of these fields will return null values for various apps, which remains an issue that Microsoft needs to resolve. As is the total lack of visibility in terms of who the Publisher (vendor) of a given app is, the permissions required, certifications and so on – all information readily available from other endpoints, but not the Graph API.

Last thing I’d want to mention is that you will likely notice an increased number of entries returned in the output. Microsoft has not been idling and a bunch more “default” apps are installed across teams now, such as the Breakout rooms one, or Share to Teams, etc. On the other side of the spectrum, many apps have been marked as “legacy”, but their entries are still returned in the output.

And that’s it, I suppose. You can find the updated version over at my GitHub repo. Let me know if you run into any issues.

5 thoughts on “Updated version of the Reporting on Teams apps and tabs script

  1. Chance says:

    Any other permissions needed as I am getting Invoke-WebRequest : The remote server returned an error: (403) Forbidden. all of the time.

    Reply
    1. Vasil Michev says:

      Whoops, well you probably need the Team.ReadBasic.All or equivalent as well, as I switched to using the /teams endpoint for getting a list of all teams. Which line is the error message referring to?

      Reply
      1. Chance says:

        I added Team.ReadBasic.All but still of no help. Getting the same error.
        Invoke-WebRequest : The remote server returned an error: (403) Forbidden.
        At ……ps1:31 char:15
        + … $result = Invoke-WebRequest -Headers $AuthHeader1 -Uri $uri -ErrorA …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc
        eption
        + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

        Reply
      2. Chance says:

        I have to correct myself. It is working with Team.ReadBasic.All – it just took some time. Thanks.

        Reply
        1. Vasil Michev says:

          Thanks for confirming, I’ll update the article/script info

Leave a Reply

Your email address will not be published. Required fields are marked *

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