How to Connect to Teams Powershell Module (TPM) using App-Based Authentication

As of Release 4.9.1 of the Teams Powershell Module (TPM), Microsoft supports Application-based authentication. This tutorial provides the necessary steps to authenticate to TPM using a Service Principal.

How to Connect to Teams Powershell Module (TPM) using App-Based Authentication

As of Release 4.9.1 of the Teams Powershell Module (TPM), Microsoft supports Application-based authentication in Teams PowerShell Module for commercial environments. (Versions above 5 or later also support app based auth for GCC High & DoD environments).

Below we will go over how to set up your tenant and connect to the Teams Powershell Module unattended using App-Based authentication.

In short, using a modern and secure token-based authentication with no password prompts and no browser pop-ups.

Why it matters — Attended vs Unattended Authentication

Folks who manually use Powershell using the Connect-MicrosoftTeamscommand will see their browser pop up, asking them to authenticate.

But what happens if you want to run some Teams Powershell Module cmdlets unattended? For example:

  • Running a script on a schedule.
  • Running a script from an upstream API call.

This is where Connecting to Teams Powershell using Application-Based Auth is required!

How to Setup Your Tenant

First, we will need to set up an Application Registration in Azure which we will then use to authenticate to TPM.

Register an Application in Azure

Those who use the Graph API will find these steps familiar.

Navigate to portal.azure.com and go to App registrations

Click “New Registration” to register a new app:

📝 Take note of:

  • Application (client) ID
  • Directory (tenant) ID

from the overview section:

Create a Client Secret

Navigate to Certificates & secrets and click “New Client Secret

📝 Take note of the:

  • Secret Value

Note - BE CAREFUL to not confuse Secret Value with Secret ID, what you will need is the Value.

Congrats! 🎉 You now have a new app registration with the 3 important pieces you’ll need (📝 Tenant ID, App ID, Secret Value). Next step, assign your app the necessary roles.

Assign your App the Teams Administrator Role

Navigate to PIM — Privileged Identity Management

Find the Role you’d like to assign to the App. (In our case, we will assign the Teams Administrator Role) to ensure our script can run and run any Teams Powershell Module Cmdlet.

Similar to how you can assign roles to users, search for your app registration and assign it the Teams Administrator Role.

You should now see the role assigned correctly by looking at the “Assignments” section.

Or see them added to your count of Teams Administrators via the “Roles”:

Connect to the Teams Powershell Module

We’re now ready to Connect to Teams using our Application Registration using the 3 values you 📝 noted above:

  • Application ID
  • Tenant ID
  • Client Secret

by running the commands below:

//  
$ClientSecret   = "…" 
$ApplicationID = "00000000-0000-0000-0000-000000000000" 
$TenantID = "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY" 
 
$graphtokenBody = @{    
   Grant_Type    = "client_credentials"    
   Scope         = "https://graph.microsoft.com/.default"    
   Client_Id     = $ApplicationID    
   Client_Secret = $ClientSecret    
}   
 
$graphToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $graphtokenBody | Select-Object -ExpandProperty Access_Token  
 
$teamstokenBody = @{    
   Grant_Type    = "client_credentials"    
   Scope         = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"    
   Client_Id     = $ApplicationID    
   Client_Secret = $ClientSecret  
}  
 
$teamsToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $teamstokenBody | Select-Object -ExpandProperty Access_Token  
 
Connect-MicrosoftTeams -AccessTokens @("$graphToken", "$teamsToken")

What does this code do?

The first 3 lines define the 3 variables we noted. These 3 variables are used to create two Oauth2 access tokens via web requests:

  • Graph API Token
  • Teams API Token

These tokens are finally passed on the last line to the Connect-MicrosoftTeams Command via the -AccessTokens param.

What does it tell us? What’s next for TPM?

Moving towards a REST API?

This tells me that the Teams Powershell Module is quickly being modernized to utilize a web-based RESTful API under the hood and moving away from WinRM. There’s a really interesting deep-dive by Vasil Michev that goes over this theory here:

https://www.michev.info/blog/post/3870/teams-remote-powershell-updates-and-new-api-endpoints

Although this gives me hope that there will come a day when these web APIs will be publically available/published. It’s also important to note that this work isn’t done. There are still cmdlets that do not yet support application based auth:

  • New-Team
  • [Get|Set|New|Sync]-CsOnlineApplicationInstance
  • *-CsUserCallingSettings
  • *-CsUserCallingDelegate
  • *PolicyPackage*
  • *-CsTeamsShiftsConnection*
  • *-CsBatchTeamsDeployment*

Maybe Mac/Linux Support in Future?

I am also excited for the day when these operations would be supported from Mac/Linux. Moving to a web-based API certainly moves the needle forward in that regard because anything over HTTPS implies that the OS won’t matter.

For now, when attempting to use the application-based authentication on my Mac, I get the following error Connect-MicrosoftTeams: Object reference not set to an instance of an object.

Connect-MicrosoftTeams -AccessTokens @("$graphToken", "$teamsToken"); 
Connect-MicrosoftTeams: Object reference not set to an instance of an object. 
Connect-MicrosoftTeams: Object reference not set to an instance of an object.

On the flip side, TPM does seem to work with basic auth or browser-based auth on Linux or Mac, but we are in “unsupported” land.

Overall, Microsoft seems to be moving fast with modernizing their Authentication in TPM, but I hope to one day see a fully web-based API or even a consolidation of all Teams administration into the Graph API. Until then, we’ll continue to use Powershell!

Happy coding/scripting! 👨‍💻