MSAL.PS

MSAL.PS ist ein PowerShell Modul zur Authentifizierung an Microsoft 365-Diensten. Auf dieser Seite merke ich mir die ein oder andere Einsatzszenarien und Erkenntnisse. Beachten Sie aber:

The MSAL.PS PowerShell module wraps MSAL.NET functionality into PowerShell-friendly cmdlets and is not supported by Microsoft. Microsoft support does not extend beyond the underlying MSAL.NET library. For any inquiries regarding the PowerShell module itself, you may contact the author on GitHub or PowerShell Gallery.
https://www.powershellgallery.com/packages/MSAL.PS

Vieles, was MSAL.PS macht, können sie auch per Powershell mit Invoke-WebRequest erreichen. Die MGGraph PowerShell kann alles auch selbst. Wenn Sie aber ein vom AzureAD ausgestelltes OAUTH/SAML-Token für eigene Zwecke verwenden wollen, dann kann MSAL.PS es einfacher machen.

Authentifizierung

Früher war das Leben einfach: Eine Software greift auf einen Service zu und der Service meldet, dass und wie der Anwender sich anmelden kann. Üblich war "Basic", "NTLM", "Kerberos" und bei Webseiten auch mal Formulare. Der Anwender sendet seine Credentials, der Server prüft diese selbst oder fragt einen Authentifizierungsdienst und der Anwender erhält Zugriff oder eben nicht. Nachteilig ist, dass jeder Service sich selbst um die Authentifizierung kümmern muss. Es geht ja nicht nur um Username/Kennwort sondern auch Abwehr von DoS/DDoS/PasswordSpray-Attacken und die Umsetzung von Multi Faktor-Authentication.

Das ändert sich durch die Nutzung von OAUTH/SAML und ist nicht nur bei Microsoft im Einsatz. Die verschiedenen Dienste erwarten, dass der Client mit dem Request ein "Ticket" übermittelt, wie wenn Sie in einen Zug einsteigen und die Fahrkarte vorweisen müssen. Diese besorgen Sie sich vorher an einem Schalter, am Automat oder per App, die alle die Bezahlinformationen prüfen. Das Ticket ist igital vom Aussteller signiert und damit nicht fälschbar ist. In dem Ticket stehen Informationen zur Identität und weitere Felder und Berechtigungen drin. Die ausstellende Stelle stellt sicher, dass der Benutzer korrekt authentifiziert ist, d.h. auch MFA, Conditional Access etc. regelt alles der Authentication Server. Der eigentlich Service kann Anfragen ohne gültiges Ticket in kürzester Zeit prüfen und verwerfen, was Angriffe deutlich erschwert.

Aber für den Client ist es natürlich eine Ehrenrunde, da er beim ersten Zugriff auf einen HTTP-Server mit "Authentication: Bearer" einen "Redirect" auf einen Authentication Service bekommt, sich dort über verschiedene Verfahren (Username/Kennwort, Mit/Ohne MFA, Zertifikat, Fido etc.) anmeldet und dann zum Service zurück geht. Damit dies nicht jeder Entwickler selbst umsetzen muss, gibt es fertige Bibliotheken/Libraries und MSALPS ist ein gängiges Modul für PowerShell.

  • Delegate
    Ihr Code wird durch einen Benutzer ausgeführt und kann auch Rückfragen stellen. Das Ticket bekommt der ausgeführte Code, de damit dann mit den Berechtigungen des angemeldeten Benutzers arbeitet. Verwechseln Sie "Delegate" nicht mit "Stellvertretern in Outlook" oder "Impersonation bei z.B. EWS"
  • Application
    Wenn Code automatisch ohne Mithilfe des Anwender auf Daten zugreifen solle, dann geht dies über "App-Permissions". Die Anmeldung erfolgt mit einer AppID und einem Secret (Kennwort oder Zertifikat). Mit den Zugangsdaten kann man sich nicht "interaktiv" an einem PC oder Browser anmelden.

Damit der Service die unterschiedlichen Programme und Skripte unterscheiden kann, muss jede App individuell im jeweiligen Tenant auch registriert/konfiguriert sein.

Es ist beim Delegate Access möglich, die AppID einer anderen bestehenden Applikation zu kapern. Es gibt z.B. IMAP4-Clients, die sich als "Thunderbird" ausgeben. Die AppID steht ja im verfügbaren Sourcecode.

Authenticationflow/ Delegate Application
Username/Kennwort

Ja - Wenn eine Anmeldung einfach mit Credentials erlaubt ist

Ja - Wenn eine Anmeldung einfach mit Credentials erlaubt ist

Username/Kennwort/MFA

Ja - Wenn eine Anmeldung einfach mit Credentials erlaubt ist und der Anwender interaktiv den zweiten Faktor erfüllen kein

Nein - Ein automatische Skript kann keinen zweiten Faktor ausfüllen und zudem erfolgt die Anmeldung ja als "Application" und nicht mit einem Benutzername. MFA findet also nicht statt

Zertifikat

Ja - Benutzer können sich sicher per Zertifikat anmelden

Ja - Auch Applikationen können und sollten sich sogar per Zertifikat anmelden. Wenn das Zertifikat in einem lokalen sicheren Speicher abgelegt ist, dann erfüllt es quasi 2FA-Anforderungen

Fido

Ja

Nein - meines wissens nicht möglich

DeviceLogin

Ja - Ein Anwender kann einen Code starten, der eine Device-Anmeldung erfordert, wenn er den angezeigten Code dann auf der Anmeldeseite von Microsoft verwendet

Nein - meines wissens nicht möglich

Die Applikation weist sich mit einer ClientID/AppID aus. Nun könnte natürlich jedes Skript einfach eine ClientID nutzen, die eigentlich einer bestehenden Applikation gehört. Dies passiert sogar. Es gibt z.B. IMAP4-Clients die offen kommunizieren, man möge doch die ClientID und das ClientSecret aus dem Sourcecode von Thunderbird übernehmen, damit Exchange Online nicht unterscheiden kann, dass hier doch eine fremde App zugreift. Daher bezeichnet Microsoft diese als "Public Clients". Vertrauenswürdige Apps laufen idealerweise nicht auf einem unkontrollierten System, da hier die App-Secrets exportiert werden könnten.

ADAL - veraltet

Wenn Sie nach OAUTH, AzureAD, Anmeldung, Graph suchen, dann finden sich auch noch Hinweise auf ADAL und andere Libraries. Die sind aber schon seit 2020 abgekündigt und sollten nicht mehr genutzt werden, auch wenn Microsoft diese noch lange Zeit unterstützt:


Quelle: https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps

Update: Update December 15th, 2022: ADAL end of support is now extended to June 30th, 2023. We will retire AAD Graph API any time after June 30th, 2023. Through the next six months (January 2023 – June 2023) we will continue informing customers about the upcoming end of support along with providing guidance on migration.
Quelle: Azure AD: Change Management Simplified https://techcommunity.microsoft.com/t5/microsoft-entra-blog/azure-ad-change-management-simplified/ba-p/2967456

Die Zukunft heißt aber MSAL

ClientID und Tenant ID

Bei einer Anmeldung per OAUTH an Microsoft 365 sind zwei Informationen immer erforderlich.

  • TenantID
    Das ist die eindeutige Kennzeichnung des Tenants als Name, z.B. msxfaqlab.onmicrosoft.com oder als GUID Den Namen sollten Sie schon wissen und die GUID können Sie im AzurePortal einsehen:

    Alternativ können Sie verschiedene Webseiten wie https://www.whatismytenantid.com/, https://www.whatismytenantid.cloud/ etc. nutzen, die auch nur eine Rest-API nutzen, wie ich auf Wer nutzt Office 365 und wie? beschrieben habe.
  • AppID/ClientID
    Jede Applikation muss sich beim Anmeldeserver mit einer GUID identifizieren, damit das Token dann die passenden Einträge enthält. Die App kann durch Microsoft vordefiniert, im eigenen Tenant angelegt oder von einem Dienstleister als MultiTenant App registriert worden sein.

Weder die TenantID noch die ClientID sind besonders schützenswert. Microsoft hat diese sogar dokumentiert.

Im EntraID SigninLogin-Protokoll erscheinen Sie auch. Hier eine Auswahl:

Microsoft Azure Active Directory Connect       cb1056e2-e479-49de-ae31-7812af012ed8
Azure Portal                                   c44b4083-3bb0-49c1-b47d-974e53cbdf3c
Microsoft Office Application ID                d3590ed6-52b3-4102-aeff-aad2292ab01c
Microsoft Edge Application ID                  ecd6b820-32c2-49b6-98a6-444530e5a77a
Outlook Web App Widgets Application ID         87223343-80b1-4097-be13-2332ffa1d666
Windows Sign In Application ID                 38aa3b87-a06d-4817-b275-7a316988d93b
Teams Admin Portal Service                     7f039cd1-6239-4773-8312-becdd3991400
Microsoft Teams Admin Portal Service           2ddfbe71-ed12-4123-b99b-d5fc8a062a79 (https://admin.teams.microsoft.com)

Etwas anderes ist es mit dem Client Secret, also den Zugangsdaten des Benutzers oder dem Zertifikat bzw. Kennwort bei einer Application. Ich habe mir für die weiteren Tests eine neue Applikation angelegt und sowohl TenantID als auch ClientID in je eine Variable gespeichert.

$ClientID = "39624784-6cbe-4a60-afbe-9f46d10fdb27" # Teams 
$TenantID = "463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c" #msxfaqlab

Für die weiteren Schritte muss ich natürlich MSAL.PS installieren und importieren.

Install-Module -Name MSAL.PS -Force -AcceptLicense
Import-Module MSAL.PS

In der PowerShell 7 ist das Modul bei mir auf C:\Users\<username>\OneDrive\Dokumente\PowerShell\Modules\MSAL.PS\ gelandet:

Die enthaltenen Commandlets kann man an zwei Händen abzählen.

PS C:\> Get-Command -Module msal.ps

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Add-MsalClientApplication                          4.37.0.0   msal.ps
Function        Clear-MsalTokenCache                               4.37.0.0   msal.ps
Function        Enable-MsalTokenCacheOnDisk                        4.37.0.0   msal.ps
Function        Get-MsalAccount                                    4.37.0.0   msal.ps
Function        Get-MsalClientApplication                          4.37.0.0   msal.ps
Function        Get-MsalFeatureSupport                             4.37.0.0   msal.ps
Function        Get-MsalToken                                      4.37.0.0   msal.ps
Function        New-MsalClientApplication                          4.37.0.0   msal.ps
Function        Remove-MsalClientApplication                       4.37.0.0   msal.ps
Function        Select-MsalClientApplication                       4.37.0.0   msal.ps

Die aus meiner Sicht wichtigste Funktion ist "Get-MsalToken".

Application Login mit Kennwort

Zuerst besorgen wir uns einmal ein Token für eine App-Registration. Dies ist insbesondere im Hinblick auf die Abschaltung der MSOnline/AzureAD-PowerShell im Laufe des Jahres 2024 (Siehe EOL MSOnline und AzureAD PowerShell) interessant.

Ehe ich mit MSAL.PS gearbeitet habe, habe ich mir die Tokens per PowerShell und Invoke-WebRequest selbst geholt, z.B.

  • Get-O365Usage
    Ohne den Einsatz von MSAL.PS meldet sich ein PowerShell Skript mittels Invoke-Webrequest und dem Zusammenbau der entsprechenden URLs und Payloads als Applikation an Microsoft 365 an um dann einen Bericht per Graph zu erhalten.

Das geht mit MSAL.PS und MGGraph PowerShell mittlerweile deutlich einfacher. Aber von diesem Skript gibt es in meinem Tenant noch unter https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps eine Application samt ClientCredentials, dich hier verwende:

Die Nutzung von Client Secrets ist möglich aber sie müssen schon selbst sicherstellen, das das Kennwort "sicher" ist. Eine Datei auf einem Server ist nur so sicher wie die NTFS-Rechte und Anmeldungen gesichert sind und auch ein Password Safe oder meine Überlegungen zu einem PowerShell Keyvault erfüllen nicht immer alle Anforderungen. Vor allem kann eine Datei mit einem Kennwort einfach "kopiert" werden.

$ApplicationID ="ffeebff4-5acd-4fed-b8e9-4ec075562401"
$AppSecret= "<Hier steht das App Secret im Klartext>"
$TenandID = "604d9047-44e5-443a-ad8f-98abe5748b0a"

$token = Get-MsalToken `
            -ClientId $ApplicationID `
            -ClientSecret (ConvertTo-SecureString $AppSecret -AsPlainText) `
            -TenantId $TenandID

$token

AccessToken :                  eyJ0eXAiOiJKV1QiLCJub25jZSI6IktnV1VqSTN1cGhsbjcxdXYzNzQyZDloNDVVMDJSLURoNDlVX0V4LTN0Nmci
                               LCJhbGciOiJSUzI1NiIsIng1dCI6IjVCM25SeHRRN2ppOGVORGMzRnkwNUtmOTdaRSIsImtpZCI6IjVCM25SeHRR
                               N2ppOG....................QrOsCc-xz8-YbCrc_TMyJ-EzGCOA
IsExtendedLifeTimeToken      : False
UniqueId                     :
ExpiresOn                    : 27.01.2024 17:39:00 +00:00
ExtendedExpiresOn            : 27.01.2024 17:39:00 +00:00
TenantId                     :
Account                      :
IdToken                      :
Scopes                       : {https://graph.microsoft.com/.default}
CorrelationId                : 53f44f7b-d76f-43c6-aaaa-3b6db6b6e8ba
TokenType                    : Bearer
ClaimsPrincipal              :
AuthenticationResultMetadata : Microsoft.Identity.Client.AuthenticationResultMetadata
User                         :

Wenn Sie übrigens die TenantID vergessen, dann versucht sich MSAL.PS anscheinend am Microsoft-Tenant anzumelden.

Get-MsalToken: AADSTS700016: Application with identifier 'ffeebff4-5acd-4fed-b8e9-4ec075562401' 
was not found in the directory 'Microsoft'. This can happen if the application has not been 
installed by the administrator of the tenant or consented to by any user in the tenant. 
You may have sent your authentication request to the wrong tenant. 
Trace ID: a19493f
7-1182-45db-ad05-d6b3739b1e00 Correlation ID: c591117d-24d8-4b0d-b91d-ee8181abefd3 
Timestamp: 2024-01-27 16:38:08Z

Das AccessToken ist natürlich BASE64-Codiert und das "eyJ" am Anfang ist schon ein deutlicher Hinweise auf die "{"-Klammer einer JSON-Struktur. Über https://jwt.ms/ oder https://jwt.io können Sie es einfach decodieren lassen. Aber auch in der PowerShell können Sie mit dem Community-Modul JWTDetails das Ticket anzeigen

Install-Module JWTDetails
Import-Module JWTDetails
$Token.AccessToken | Get-JWTDetails

aud                 : https://graph.microsoft.com
iss                 : https://sts.windows.net/604d9047-44e5-443a-ad8f-98abe5748b0a/
iat                 : 1706373241
nbf                 : 1706373241
exp                 : 1706377141
aio                 : E2VgYPjqKPTyt/aS7lXGp/JthXNqAA==
app_displayname     : MSXFAQ MGGraph
appid               : ffeebff4-5acd-4fed-b8e9-4ec075562401
appidacr            : 1
idp                 : https://sts.windows.net/604d9047-44e5-443a-ad8f-98abe5748b0a/
idtyp               : app
oid                 : 925a9210-f087-4509-9f01-c06865a154d3
rh                  : 0.AS8AR5BNYOVEOkStj5ir5XSLCgMAAAAAAAAAwAAAAAAAAACwAAA.
roles               : {CallRecords.Read.All, CallRecord-PstnCalls.Read.All}
sub                 : 925a9210-f087-4509-9f01-c06865a154d3
tenant_region_scope : EU
tid                 : 604d9047-44e5-443a-ad8f-98abe5748b0a
uti                 : eCzZSTYWX0yLIPmJXD0NAA
ver                 : 1.0
wids                : {0997a1d0-0d1d-4acb-b408-d5ca73121e90}
xms_tcdt            : 1631541773
xms_tdbr            : EU
sig                 : Cl1Wg1iTkHsLa0XNIQhqTkibLMcJ5Nh0ksHKdbr6KN6ET0qEfVI5nMeqkf51W4BMsfZgoAyIgQtFJ/YWWtYmWraS4VjVdtFAc
                      bvTVjzgXeTow/pbBTNSmZ9x168GIBncJIwMifDB/piIuQkY5/KiTijZmwrPrkzHj5FVz6tUBtBrNqeWpvkYUBAymaV8o/DIEF
                      QKObnRysut64uzO+A9FoHHMH41C9kYgYWBqcBdiYjLqezU530v0RKhtR/G92RnB8H0Ni+tYYpdKIoUJ1kS3Ff4Y9zCcc3vSZs
                      44h3KQt2fKsQK7EtkVAmm7pQrOsCc+xz8+YbCrc/TMyJ+EzGCOA==
expiryDateTime      : 27.01.2024 18:39:01
timeToExpiry        : 00:10:05.6000526

Achtung: Das Ticket ist im Rahmen der Gültigkeit ihr Zugangscode. Wer immer das Ticket hat, kann die Rechte ausüben! Es ist daher auch ein begehrtes Ziel für Malware

[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($token.AccessToken))

Das Token können Sie direkt mit Invoke-Webrequest verwenden.

Invoke-RestMethod `
   -Method GET `
   -Uri 'https://graph.microsoft.com/v1.0/me' `
   -Headers @{ Authorization = $Token.CreateAuthorizationHeader() }

Die Funktion "CreateAuthorizationHeader" generiert direkt den String mit dem "Bearer"-Prefix.

AppLogin mit Zertifikat

Anstelle eines "Kennworts" gibt es mit Zertifikaten eine besser Lösung. Dies erlaubt insbesondere die Ablage in einem "Sicheren Speicher", z.B. dem TPM-Chip, einer Smartcard o.ä., deren Geheimnis nicht exportiert oder kopiert werden kann. Sie laden dann das öffentliche Zertifikat einfach in die App Registration hoch und MSAL.PS registriert sich mit dem lokalen Zertifikat. Bei den Parametern ist nur der Thumbprint anzugeben:

$ApplicationID ="ffeebff4-5acd-4fed-b8e9-4ec075562401"
$TenandID = "604d9047-44e5-443a-ad8f-98abe5748b0a"

$token = Get-MsalToken `
            -ClientId $ApplicationID `
            -TenantId $TenandID `
            -CertificateThumbprint "<hier muss der Thumbprint rein>

Danach geht es wieder wie gewohnt weiter.

Delegated Login

Zuletzt bleibt noch die Anmeldung als Benutzer. Hier scheitern viele einfache PowerShell-Ansätze, da durch Multi Faktor und Conditional Access in vielen Fällen ein Dialog geöffnet werden muss, in dem der Anwender dann zusätzliche Informationen übergeben oder bestätigen muss. Ein einer Aufruf mit Username und Kennwort aus einem Skript reicht hier also nicht immer aus.

Auch hier müssen Sie natürlich wieder eine ClientID vorgeben. Das kann eine eigen ID sein aber natürlich können sie auch eine bekannte ClientID nutzen. Wenn ich z.B. ein Token für Teams haben möchte, dann könnte folgendes direkt funktionieren

$clientID = "1fec8e78-bce4-4aaf-ab1b-5451cc387264"
$token = Get-MsalToken `
            -ClientId $clientID `
            -TenantId msxfaqdev.onmicrosoft.com
$token.AccessToken

Wenn Sie im Firmennetzwerk sind und ihre Administrator sowohl z.B. anhand der IP-Adresse die MFA-Abfrage abgesichert hat und Seamless Single Sign On eine direkte Anmeldung erlaubt. In alle anderen Fälle wird MSAL.PS dann nach Anmeldedaten fragen.

Eine Übergabe von Benutzername und Kennwort ist über den Parameter "UserCredential" möglich.

DelegatedDeviceLogin

Ein Sonderfall ist die Anmeldung für ein Device, z.B. ein Teams Telefon. Dabei möchte sich der Anwender auf einem Gerät anmelden, auf dem es eigentlich keine Eingabemöglichkeit für Anmeldenamen und Kennworte gibt. In dem Fall startet das Device einen Aufruf an EntryID und bekommt einen DeviceKey, den es auf einem Display anzeigt. Der Anwender startet dann eine Anmeldung auf einem geeigneten Client unter der folgenden URL:

Hier gibt der Anwender den vom Gerät angezeigten Code ein und meldet sich an. Das Backend sendet dann das Token an das Device zur weiteren Verwendung. Das kann auch per MSAL.PS genutzt werden. Ein PowerShell-Script könnte also über diese Funktion ein Access Token bekommen ohne dass der Anwender hier die Daten eingeben muss.

$AccessToken = Get-MsalToken `
                 -DeviceCode `
                 -ClientId $clientID `
                 -TenantId $tenantID `
                 -RedirectUri "https://localhost"

Bislang habe ich diese Funktion aber noch nicht irgendwo produktiv eingesetzt.

Cache und Renewal

Am Ticket haben sie schon gesehen, dass es nur relativ kurz gültig ist und MSAL.PS auch das Feld "timeToExpiry" generiert. Wenn ein Access-Token kann ich mich natürlich erneut komplett Authentifizieren und ein neues Access-Token besorgen. Genaugenommen gibt es drei Tokens:

Tokentyp Gültigkeit Einsatzbereich

AccesToken

1h bis wenige Stunden

Das ist das meistgenutzte Token, um sich bei Diensten zu authentifizieren und auf Informationen zuzugreifen. Es enthält neben dem Namen des Benutzers auch den Scope, d.h. die Berechtigungen. Sie können es mit dem Kerberos Service Token vergleichen.

IdTocken

1h bis wenige Stunden

Damit kann der Anwender nachweisen, wer er ist, d.h. seine Identität aber das Token ist nicht mit Berechtigungen (scope) verbunden.

RefreshToken

mehrere Stunden oder Tage

Um immer wieder erneute Anmeldungen zu vermeiden, bekommt der Benutzer auch ein RefreshToken, welche ich vielleicht mit dem Kerberos TGT vergleichen würde. Es wird nur genutzt, um abgelaufene oder neue Authentcation-Tokens anzufordern oder sich selbst zu verlängern.

Zuerst müssen wir MSAL.PS die von uns genutzte Applikation mitteilen, damit er einen Cache dazu anlegen kann. Der Cache ist normalerweise im RAM aber kann auch auf eine Festplatte ausgelagert werden. Allerdings gibt es keinen Hintergrundprozess, der ein Token vor Ablauf automatisch erneuert oder verlängert. Auch im Vordergrund müssen Sie schon selbst prüfen, ob das aktuell genutzte Token noch gültig ist oder sie doch noch ein neues AccesToken mithilfe des noch nicht abgelaufenen RefreshToken anfordern müssen.

MGGraph mit Token

Im Laufe des Jahres 2024 werden die MSOnline- und AzureAD-Module für PowerShell abgeschaltet und alle Administratoren müssen ihre Skripte und Anleitungen auf die MGGraph PowerShell umschreiben. Mit der MGGraph PowerShell können Sie sich weiterhin als Application mit ClientSecret oder ClientCertificate anmelden oder interaktiv. Aber es gibt keinen Parameter mehr, mit dem Sie einen Benutzernamen oder Kennwort automatisch anmelden können.

Für die Automatisierung von Aufgaben sollten Sie mit Microsoft 365/EntraID niemand reguläre Benutzer zu "Dienstkonten" umwidmen sondern immer mit der App Registration für ihr Skript arbeiten.

Sie können aber bei "Connect-MGGraph" mit dem Parameter "-AccessToken" sehr wohl ein vorhandenes Token übergeben. Über den Weg eröffnet sich dann doch wieder die Option, sich zuerst ein Token mit MSAL.PS zu holen und diese Token dann für MGGrach einzusetzen.

$cred=Get-Credential
$Token = Get-MSALToken `
            -Scopes "Application.Read.All", "Application.ReadWrite.All" `
            -ClientId 14d82eec-204b-4c2f-b7e8-296a70dab67e `
            -UserCredential $cred `
            -TenantId msxfaqdev.onmicrosoft.com 

$AccessToken = $Token.AccessToken
Connect-MGGraph -AccessToken (ConvertTo-SecureString $AccessToken -AsPlainText)

Exchange Online PowerShell

Auf EXO PowerShell Automation habe ich z.B. beschrieben, wie eine automatische Anmeldung an den Exchange Online PowerShell als Applikation nicht nur per Zertifikat sondern auch per AccessToken generiert. Da "Connect-ExchangeOnline" aber keine Anmeldung mit Client-Secret erlaubt, muss ich mit selbst ein Token zusammenbauen. MSAL.PS hilft auch dabei:

Import-Module MSAL.PS
$msalParams = @{
        TenantID = "msxfaqdev.onmicrosoft.com"              #GUID oder onmicrosoft.com-domain
        ClientID = "9cb958d8-3f03-4f5e-b71a-8ae25a289b78"   #AppID der Application
        Scopes = 'https://outlook.office365.com/.default'   # Default Scope
        ClientSecret = (ConvertTo-SecureString "hier das Kennwort rein" -AsPlainText)
}
$msalResult = Get-MsalToken @msalParams 

Connect-ExchangeOnline `
   -Organization msxfaqdev.onmicrosoft.com `
   -AccessToken $msalResult.AccessToken

Weitere Links