Microsoft Updates Teams PowerShell Module to 2.0

Useful Update With Some Authentication Challenges

Teams PowerShell Module 2.0

Without any fanfare, Microsoft released Version 2.0 of the Teams PowerShell module on March 4. You can download and install the new module from the PowerShell gallery. Here are the commands I used:

Uninstall-Module -Name MicrosoftTeams -AllVersions
Install-Module -Name MicrosoftTeams -Force -Scope AllUsers

The previous production version for the Teams PowerShell module was 1.1.6. The major enhancements in this release are:

  • Support for cmdlets to manage Teams templates policies.
  • The need to run the New-CsOnlineSession cmdlet to connect to the policy management endpoint (old Skype for Business Online endpoint) and download the policy management cmdlets into a session no longer exists. All the cmdlets are now in the Microsoft Teams module. You’ll experience a slight delay when a cmdlet needs to connect to the policy management endpoint for the first time in a session and later if a connection must be re-established.
  • The module now uses the Microsoft Authentication Library (MSAL) rather than the Active Directory Authentication Library (ADAL) for authentication and authorization.
  • Support for group policy assignment to users. According to MC243733 (9 March), Microsoft is rolling this feature out to be complete in mid-March.
  • The Get-Team cmdlet is much faster at retrieving teams than it was in the past, and it comes with a progress bar (Figure 1)
Get-Team does its stuff and reports progress
Figure 1: Get-Team does its stuff and reports progress

Good as these enhancements seem at first reading, issues lurk, and some might ask why Microsoft could issue a new module with such evident challenges.

You can use a script as described in this article to keep your PowerShell modules updated. I usually run the script once monthly to make sure that I pick up any updates I haven’t gone looking for.

Authentication Problems

Moving to MSAL has some downsides. For instance, connecting to Teams using the AccountId parameter to pass a user principal name for an MFA-enabled account generates an error.

Connect-MicrosoftTeams -AccountId $O365Cred.UserName 
Connect-MicrosoftTeams : One or more errors occurred.
At line:1 char:1
+ Connect-MicrosoftTeams -AccountId $O365Cred.UserName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : AuthenticationError: (:) [Connect-MicrosoftTeams], AggregateException
    + FullyQualifiedErrorId : Connect-MicrosoftTeams,Microsoft.TeamsCmdlets.Powershell.Connect.ConnectMicrosoftTeams

Connect-MicrosoftTeams : Integrated Windows Auth is not supported for managed users. See https://aka.ms/msal-net-iwa for details.

Basic authentication works as expected but the only reliable way I have found to sign into Teams with an MFA-enabled account (and all administrative accounts should be MFA-enabled) is to run Connect-MicrosoftTeams without a parameter and choose the account name from the login dialog. This isn’t suitable for batch processing, so if you need to run batch jobs to access Teams with PowerShell, use the older 1.1.6 release, scripts with other cmdlets if possible (for example, Get-UnifiedGroup), or the Graph API.

Update: Microsoft has released a preview version (2.1.0) of the Teams PowerShell module which works properly with modern authentication. It’s likely that this version will be pushed through to general availability quite quickly.

Microsoft is aware of the problems with authentication. We’ll update this post when further news appears.

Using the Teams Template Management Cmdlets is Not Easy

Microsoft added template policy management to the Teams admin center in late February 2021. The cmdlets to manage teams templates are in V2.0. However, their syntax is very much like Graph API commands rather than following normal PowerShell conventions. In addition, the cmdlets to create and update templates don’t accept PowerShell objects as input. Output is odd too, with JSON the favorite output format. The way the new cmdlets behave creates a learning barrier to surmount, which isn’t helped by some odd text in the documentation. For instance:

Within the universe of templates the admin’s tenant has access to, returns a template definition object (displayed as a JSON by default) for every custom and every Microsoft en-US template which names include ‘test’.

To begin, the Get-CsTeamsTemplateList cmdlet returns the set of teams templates in the tenant:

Get-CsTeamTemplateList

OdataId
-------
/api/teamtemplates/v1.0/d84de63f-26bb-4c8e-a438-fa5b99ac5c5a/Tenant/en-US
/api/teamtemplates/v1.0/9f90e23d-a361-4caf-ba79-9886adc93c68/Tenant/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.ManageAProject/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.ManageAnEvent/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.OnboardEmployees/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.AdoptOffice365/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.OrganizeHelpDesk/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.CoordinateIncidentResponse/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.CollaborateOnAGlobalCrisisOrEvent/Public/en-US
/api/teamtemplates/v1.0/retailStore/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.CollaborateWithinABankBranch/Public/en-US
/api/teamtemplates/v1.0/healthcareWard/Public/en-US
/api/teamtemplates/v1.0/healthcareHospital/Public/en-US
/api/teamtemplates/v1.0/com.microsoft.teams.template.QualitySafety/Public/en-US
/api/teamtemplates/v1.0/retailManagerCollaboration/Public/en-US

The first two templates listed are custom tenant templates. The others are the default set maintained by Microsoft. To make things easier to deal with, I extract the data for each template and put it into a PowerShell list:

$Templates = Get-CsTeamTemplateList
$Report = [System.Collections.Generic.List[Object]]::new() 
ForEach ($Template in $Templates) {
    $ModifiedBy = $Null
    If ([string]::IsNullOrWhiteSpace($Template.ModifiedBy)) {
       $ModifiedBy = "Microsoft" }
    Else {
       $ModifiedBy = (Get-AzureADUser -ObjectId $Template.ModifiedBy).DisplayName }
    $ReportLine = [PSCustomObject]@{
         Name           = $Template.Name
         Apps           = $Template.AppCount
         Channels       = $Template.ChannelCount
         Description    = $Template.ShortDescription
         Modified       = $ModifiedBy
         "Last Updated" = Get-Date($Template.ModifiedOn) -format g
         Id             = $Template.ODataId
         Scope          = $Template.Scope
         Visibility     = $Template.Visibility }
    $Report.Add($ReportLine) }

The extracted properties for a template object now looks like:

Name         : R&A Events
Apps         : 5
Channels     : 6
Description  : Improve your event management and collaboration.
Modified     : Tony Redmond
Last Updated : 26/02/2021 14:33
Id           : /api/teamtemplates/v1.0/d84de63f-26bb-4c8e-a438-fa5b99ac5c5a/Tenant/en-US
Scope        : Tenant
Visibility   : Private

To retrieve full information about a template, use the Get-CsTeamTemplate cmdlet. This takes the Odata.Id as its identity. Taking the id stored in our list we can do this:

$TemplateData = Get-CsTeamTemplate -ODataId $Report[0].id

The result is a bunch of JSON formatted information about the apps, channels, and settings configured for the template. Here’s a snippet:

{
  "templateId": "d84de63f-26bb-4c8e-a438-fa5b99ac5c5a",
  "displayName": "R\u0026A Events",
  "description": "Manage tasks, documents and collaborate on everything you need to deliver a compelling event.
Invite guests users to have secure collaboration inside and outside of your company.",
  "visibility": "Private",
  "channels": [
    {
      "id": "General",
      "displayName": "General",
      "description": "",
      "isFavoriteByDefault": true,
      "tabs": [
        {
          "id": "General.tab0",
          "teamsAppId": "0d820ecd-def2-4297-adad-78056cde7c78",
          "name": "Team Information",
          "key": "General.tab0"
        },
        {
          "id": "General.tab1",
          "teamsAppId": "com.microsoft.teamspace.tab.planner",
          "name": "Event Plan",
          "key": "General.tab1"
        },
        {
          "id": "General.tab2",
          "teamsAppId": "0d820ecd-def2-4297-adad-78056cde7c78",
          "name": "Meeting Notes",
          "key": "General.tab2"
        }
      ]
    },

Unfortunately, if you try to convert the JSON, it fails due to an invalid primitive.

$TemplateData = Get-CsTeamTemplate -OdataId $Report[0].id | ConvertFrom-Json
ConvertFrom-Json : Invalid JSON primitive: Microsoft.Teams.ConfigAPI.Cmdlets.Generated.Models.TeamTemplate.

The other cmdlets are:

If you’re used to PowerShell, the syntax created for these cmdlets is not the norm. I think this is due to the familiarity the designers have with the Graph API. This makes the cmdlets harder to use, but it’s unlikely that you will use them often as it is easier to maintain templates policies through the Teams admin center.

Creating a New Teams Template

As an example of where you might want to use these cmdlets, consider the situation of a multinational tenant who wants to create the same policy in different languages. To do this, you:

Extract the properties of the source template policy to a text file.

Get-CsTeamTemplate -OdataId "/api/teamtemplates/v1.0/d84de63f-26bb-4c8e-a438-fa5b99ac5c5a/Tenant/en-US" > Template.json

Update the text strings in the file with translated strings and save the file. Then use it as input to the New-CsTeamTemplate cmdlet. The output after the command is the response from Teams:

New-CsTeamTemplate -Locale fr-FR -Body (Get-Content 'template-fr.json' | Out-String )

{
  "id": "b8e908a8-af13-42e6-86b9-eb33b8874fa5",
  "name": "Événements d\u0027entreprise",
  "scope": "Tenant",
  "description": "Gérez les tâches, les documents et collaborez sur tout ce dont vous avez besoin pour organiser
un événement convaincant.\r\nInvitez les utilisateurs invités à avoir une collaboration sécurisée à
l\u0027intérieur et à l\u0027extérieur de votre entreprise.",
  "shortDescription": "Améliorez la gestion et la collaboration de vos événements.",
  "iconUri": "https://statics.teams.cdn.office.net/evergreen-assets/teamtemplates/icons/default_tenant.svg",
  "channelCount": 6,
  "appCount": 5,
  "modifiedOn": "2021-03-10T08:56:55.1668488Z",
  "modifiedBy": "53f08764-07d4-418c-8403-a737a8fac7b3",
  "locale": "fr-FR",
  "@odata.id": "/api/teamtemplates/v1.0/b8e908a8-af13-42e6-86b9-eb33b8874fa5/Tenant/fr-FR"
}

Voila! We now have a French version of the template policy. This won’t be something you do often, but when you need to do it, the cmdlets might offer an alternative to creating the templates in the Teams admin center.


Normally we like including news of updated PowerShell modules in the Office 365 for IT Pros eBook. I’m not so sure about this update, but even so we will adjust our text.

15 Replies to “Microsoft Updates Teams PowerShell Module to 2.0”

  1. I realise that templates for Teams are not the same thing as templtes for Team Sites, but is it possible that these new cmdlets are intended to be used also to create, and generally manage, tempates for Team Sites?

    1. No. They are very different. One deals with the creation of teams, the other with the creation of SharePoint team sites.

Leave a Reply

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