The struggle with the MicrosoftTeams PowerShell Modules

Hallo zusammen,

In den letzten Wochen habe ein bisschen mit dem MicrosoftTeams Modul herumgespielt. Andauernd kommen neue Versionen heraus und immer wieder geht etwas anderes nicht mehr.

MicrosoftTeams Modul 2.3.2

Aktuell habe ich das MicrosoftTeams Modul 2.3.2 installiert

Wie bereits beim MicrosoftTeams Module 2.3.1 funktionieren die *CS* Befehle nicht beim Anmelden mit einer ApplicationID und einem Zertifikat. Das habe ich bereits hier gebloggt https://blog.icewolf.ch/archive/2021/05/10/microsoftteams-powershell-module-2-3-1-still-problems-with-certificate.aspx

$TenantId = "icewolfch.onmicrosoft.com"
$AppID = "546f064a-baa2-4eb9-8b68-70c79b91942b" #TeamsPS
$CertificateThumbprint = "3B42F63204F0F54F6E4CB9CF96E365513C913C2B"
Connect-MicrosoftTeams -ApplicationId $AppID -CertificateThumbprint $CertificateThumbprint -TenantId $TenantId
Get-Team
Get-CsOnlineUser -Identity a.bohren@icewolf.ch | fl *Ent*,*host*,*voice*, *um*

Ich kann mich zwar mit Teams verbinden, habe jedoch immer noch die *CS* Fehler - einfach mit ein bisschen anderer Fehlermeldung

Ich habe die API Permissions fast so gesetzt wie in der Dokumentation zu Connect-MicrosoftTeams

Connect-MicrosoftTeams
https://docs.microsoft.com/de-de/powershell/module/teams/connect-microsoftteams?view=teams-ps

Die Skype and Teams Tenant Admin API auswählen. Man merke sich die Application ID: 48ac35b8-9aa8-4d74-927d-1f4a14a0b239

Unter Application Permissions "application_access" auswählen

Graph API
- "Group.ReadWrite.All"
- "User.Read.All"
Skype and Teams Tenant Admin API
- "application_access"

Ich versuche noch was anderes und installiere mir die MSAL.PS

Install-Module MSAL.PS
Get-Module MSAL.PS -ListAvailable

Import-Module MSAL.PS
$TenantId = "icewolfch.onmicrosoft.com"
$AppID = "546f064a-baa2-4eb9-8b68-70c79b91942b" #TeamsPS
$CertificateThumbprint = "3B42F63204F0F54F6E4CB9CF96E365513C913C2B"

$ClientCertificate = Get-Item Cert:\CurrentUser\My\$CertificateThumbprint
$Scope = "https://graph.microsoft.com/.default"
$Token = Get-MsalToken -clientID $AppID -ClientCertificate $ClientCertificate -tenantID $tenantID -Scope $Scope
$GraphAccessToken = $Token.AccessToken
$GraphAccessToken

Der Access Token ist ein JSON Web Token (JWT) https://de.wikipedia.org/wiki/JSON_Web_Token

Den kann man mit folgender PowerShell Funktion decodieren, dann sieht man die Roles

###############################################################################
# Parse JWT Token
# https://www.michev.info/Blog/Post/2140/decode-jwt-access-and-id-tokens-via-powershell
###############################################################################
function Parse-JWTtoken {
 
    [cmdletbinding()]
    param([Parameter(Mandatory=$true)][string]$token)
 
    #Validate as per https://tools.ietf.org/html/rfc7519
    #Access and ID tokens are fine, Refresh tokens will not work
    if (!$token.Contains(".") -or !$token.StartsWith("eyJ")) { Write-Error "Invalid token" -ErrorAction Stop }
 
    #Header
    $tokenheader = $token.Split(".")[0].Replace('-', '+').Replace('_', '/')
    #Fix padding as needed, keep adding "=" until string length modulus 4 reaches 0
    while ($tokenheader.Length % 4) { Write-Verbose "Invalid length for a Base-64 char array or string, adding ="; $tokenheader += "=" }
    Write-Verbose "Base64 encoded (padded) header:"
    Write-Verbose $tokenheader
    #Convert from Base64 encoded string to PSObject all at once
    Write-Verbose "Decoded header:"
    [System.Text.Encoding]::ASCII.GetString([system.convert]::FromBase64String($tokenheader)) | ConvertFrom-Json | fl | Out-Default
 
    #Payload
    $tokenPayload = $token.Split(".")[1].Replace('-', '+').Replace('_', '/')
    #Fix padding as needed, keep adding "=" until string length modulus 4 reaches 0
    while ($tokenPayload.Length % 4) { Write-Verbose "Invalid length for a Base-64 char array or string, adding ="; $tokenPayload += "=" }
    Write-Verbose "Base64 encoded (padded) payoad:"
    Write-Verbose $tokenPayload
    #Convert to Byte array
    $tokenByteArray = [System.Convert]::FromBase64String($tokenPayload)
    #Convert to string array
    $tokenArray = [System.Text.Encoding]::ASCII.GetString($tokenByteArray)
    Write-Verbose "Decoded array in JSON format:"
    Write-Verbose $tokenArray
    #Convert from JSON to PSObject
    $tokobj = $tokenArray | ConvertFrom-Json
    Write-Verbose "Decoded Payload:"
   
    return $tokobj
}

Parse-JWTtoken $GraphAccessToken

Oder man macht das über den Browser mit der folgenden Website https://jwt.ms/

Nun braucht es noch den Teams Access Token

$Scope = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"
$Token = Get-MsalToken -clientID $AppID -ClientCertificate $ClientCertificate -tenantID $tenantID -Scope $Scope
$TeamsAccessToken = $Token.AccessToken
$TeamsAccessToken

Parse-JWTtoken $TeamsAccessToken

Nun werden die beiden AccessTokens in ein Array gespeichert und ein Connect-MicrosoftTeams ausgeführt. Unklar ist, weshalb man hier einen AccountID Parameter mitgeben muss, aber ohne geht es nicht

$AccessTokens = @($GraphAccessToken,$TeamsAccessToken)
Connect-MicrosoftTeams -AccessTokens $AccessTokens -AccountId a.bohren@icewolf.ch

Resultat: Teams kann verbunden werden, aber die *CS* Befehle funktionieren nicht.

MicrosoftTeams Modul 2.4.0-Preview

Nun habe ich mir das MicrosoftTeams Modul 2.4.0-Preview installiert

Get-Module MicrosoftTeams -ListAvailable
Uninstall-Module MicrosoftTeams
Find-Module MicrosoftTeams
Find-Module MicrosoftTeams -AllowPreview
Install-Module MicrosoftTeams -AllowPreview
Get-Module MicrosoftTeams -ListAvailable

Der selbe Code von oben

Import-Module MSAL.PS
$TenantId = "icewolfch.onmicrosoft.com"
$AppID = "546f064a-baa2-4eb9-8b68-70c79b91942b" #TeamsPS
$CertificateThumbprint = "3B42F63204F0F54F6E4CB9CF96E365513C913C2B"

$ClientCertificate = Get-Item Cert:\CurrentUser\My\$CertificateThumbprint
$Scope = "https://graph.microsoft.com/.default"
$Token = Get-MsalToken -clientID $AppID -ClientCertificate $ClientCertificate -tenantID $tenantID -Scope $Scope
$GraphAccessToken = $Token.AccessToken

$Scope = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"
$Token = Get-MsalToken -clientID $AppID -ClientCertificate $ClientCertificate -tenantID $tenantID -Scope $Scope
$TeamsAccessToken = $Token.AccessToken
$AccessTokens = @($GraphAccessToken,$TeamsAccessToken)

Parse-JWTtoken $GraphAccessToken
Parse-JWTtoken $TeamsAccessToken

Nur leider funktioniert der jetzt nicht mehr

Connect-MicrosoftTeams -AccessTokens $AccessTokens -AccountId a.bohren@icewolf.ch
Connect-MicrosoftTeams -AccessTokens $AccessTokens

Und der Code ganz vom Anfang mit dem Parameter "ApplicationID" funktioniert auch nicht mehr, weil es den Parameter nicht mehr gibt.

Fazit:

Die Situation mit dem MicrosoftTeams PowerShell Modul ist seit Monaten extrem mühsam. Bei jeder neuen Version geht etwas anderes nicht mehr. Einmal fehlen plötzlich die Befehle für die Teams Hierarchie, dann sind die wieder da, dafür geht was anderes nicht mehr. Und die Anmeldung über ein Zertifikat mit den Teams Befehlen hat noch nie funktioniert. Hoffentlich wird das ganze etwas stabiler, wenn erstmal Skype for Business Online am 31.07.2021 abgeschaltet ist.

Grüsse
Andres Bohren