EXO PowerShell Automation
Für die Verwaltung von Exchange Online per PowerShell starten Sie ein "Connect-ExchangeOnline" und geben ihre Anmeldedaten ein. Da MFA heute quasi Pflicht ist, funktioniert das mit hinterlegten Kennworten nur noch eingeschränkt, z.B. wenn der "Conditional Access" z.B. über die IP-Adresse geregelt ist. Eine automatische Anmeldung per Programm kann ja kaum die Authenticator-App auf einem Smartphone bedienen. Aber die Exchange Online PowerShell V2 erlaubt auch die Verwendung als App mittels Zertifikat.
Nutzen Sie bitte die Exchange PowerShell V3. V2 ist zum Sommer 2023 abgekündigt.
Apps, Graph und Exchange
Viele Jahrzehnte haben wir Administratoren für automatische Prozesse entsprechende Dienstkonten angelegt oder Computerkonten genutzt Exchange 4.0-5-5 hatte noch einen Domain Benutzer zum Betreiben der Dienste und erst mit Exchange 2000 liefen die Exchange Dienste dann als "LocalSystem" und mittlerweile noch weniger Rechten. Auch in der Cloud gibt es die RoleGroup "Exchange Administratoren" und ein AzureAD-Benutzer kann die Berechtigungen bekommen. Allerdings ist eine automatische Anmeldung mit einem regulären Benutzerkonto und Kennwort recht unsicher und eignet sich wenig für eine Automatisierung. Zum einen sollten Sie privilegierte Konten mit MFA ausstatten, dass eine Automatisierung erschwert. Kritischer ist aber die Offenheit, dass sich jemand auch regulär als "Azure AD Benutzer" anmelden kann.
Graph und andere APIs kennen aber die Möglichkeit von App-Berechtigungen, d.h. der Code authentifiziert sich mit einer GUID als Benutzername und einem Kennwort oder Zertifikat. Die Applikation bekommt dann genau die Berechtigungen, die diese benötigt aber kann sich nicht interaktiv anmelden. Dieser Weg ist auch mit der Exchange PowerShell V2.0.3 oder neuer möglich. Allerdings muss ich dazu zwingend ein Zertifikat nutzen.
- App-only authentication for unattended
scripts in the EXO V2 module
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#set-up-app-only-authentication
Die Einrichtung ist dann relativ schnell erfolgt:
- Zertifikat generieren
Das kann auch ein Self Signed Certificate sein. Es kann als PFX-Datei vorliegen oder im Zertifikatsspeicher des PCs abgelegt sein. PFX-Dateien sind "portabel" aber natürlich unsicherer als - App konfigurieren
Hier müssen das Zertifikat und die Berechtigungen konfiguriert werden. Die erforderlichen Berechtigungen sind leider nicht per Browser direkt auswählbar, sondern müssen über ein Manifest eingerichtet werden. - Skript umstellen
In ihrer Automatisierungslösung müssen Sie dann nur den Connect-Exchange Online mit den passenden Parametern anlegen
Dieser Weg kann durchaus auch für die tägliche Administration per Exchange Online PowerShell interessant sein, wenn ich kein eigenes "Admin-Konto" o.ä. brauche, sondern einfach nur eine Exchange Online PowerShell. Ich kann die PFX-Datei ja mit einem Kennwort sichern und damit sicher und ohne MFA-Einrichtung nutzen. Mein Anwendungsfall ist aber tatsächlich die Automatisierung von Exchange Online-Aufgaben wie z.B. die Verwaltung von MailContacts in einem Exchange Online-Tenant zur besseren Zusammenarbeit zwischen zwei Tenants. Microsoft beschreibt die Schritte in einer anderen Reihenfolge. Ich lege aber zuerst das Zertifikat an.
Zertifikat anlegen
Die Exchange Online PowerShell V2 erlaubt keine Anmeldung mit einer AppID und einen Kennwort sondern erfordert ein Zertifikat. Mit den folgenden PowerShell-Befehlen lege ich ein Zertifikat an.
Das Zertifikat ist per Default 1 Jahr gültig. Überlegen Sie sich daher, wie Sie jede Jahr das Zertifikat verlängern oder tauschen. Das nahe Ende wird auch im Azure Portal angezeigt.
Sie können die Gültigkeit auch auf z.B. 5 Jahre oder mehr setzen. Da es aber ein "SelfSigned"-Cert ist, gibt es keine IssuingCA, die ein Zertifikat zurückziehen kann. Bei einer Kompromittierung müssen Sie in der App Registration das Zertifikat entfernen.
Microsoft empfiehlt die Ausführung als Administrator aber bei mir haben die folgenden Schritte auch als normaler Benutzer funktioniert.
# Zertifikat generieren $mycert = New-SelfSignedCertificate ` -DnsName "msxfaqdev1Jahr" ` -CertStoreLocation "cert:\CurrentUser\My" ` -NotAfter (Get-Date).AddYears(1) ` -KeySpec KeyExchange # Export certificate in .pfx Datei mit private Key $mycert | Export-PfxCertificate ` -FilePath msxfaqdev1jahr.pfx ` -Password $(ConvertTo-SecureString -String "CertPassWord!" -AsPlainText -Force) # Export certificate als .cer datei zum Upload in Azure $mycert | Export-Certificate ` -FilePath msxfaqdev1jahr.cer # Thumbprint ausgeben Write-host $mycert.Thumbprint
Das Zertifikat finden Sie auch im Zertifikatsspeicher ihres Benutzers.
Wenn ein Skript immer genau auf einem System mit einem bekannten Konto ausgeführt wird, dann ist die Ablage des Zertifikat in sicheren Zertifikatsspeicher mein Favorit. Damit erspare ich mir die Hinterlegung eines Kennworts an einer weniger sicheren Stelle zum Entsperren der PFX-Datei.
- Step 3: Generate a self-signed certificate
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#step-3-generate-a-self-signed-certificate
App konfigurieren
Der nächst Schritt ist etwas umfangreicher aber von Microsoft sehr gut mit Bildern dokumentiert. Daher beschreibe ich hier nur eine Kurzfassung:
- Neue App Registration anlegen
Über die Adresse https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps sehe ich alle bereits registrierten Apps und Starte mit "New Registration".
Ich gebe der App einen sprechenden Namen "MSXFAQDEV EXOPS2 CBA" und lasse anderen Werte auf Default - AppID kopieren
Nach der Registrierung bin ich auf der Übersichtsseite und kopiere mir hier schon mal die "Application (Client) ID", denn das ist der spätere Benutzername - Zertifikat hochladen
Dann nutze ich die im ersten Schritt exportierte CER-Datei, um den "Public Key" des später genutzten Zertifikats in der App zu hinterlegen. - App Berechtigungen
Laut Microsoft muss ich das über eine MANIFEST-Datei machen. Aber ich habe einen Weg über die Webseite gefunden:
Im nächsten Dialog wähle ich dann die passende "Application Permission: Exchange.ManageAsApp" aus.
Zuletzt muss ich noch "Admin Consent" gewähren.
- Exchange Admin Rolle vergeben
Zuletzt muss ich der App auch noch die entsprechende AzureAD-Rolle vergeben. Dazu muss ich im Azure-Portal auf https://portal.azure.com/#blade/Microsoft_AAD_IAM/RolesManagementMenuBlade/AllRoles/ gehen und die Rolle "Exchange Administrator" suche und dann die App addiere. Erinnern sie sich noch an den Namen, den sie am Anfang vergeben haben?
Damit ist die Einrichtung im Azure AD abgeschlossen.
Wenn Sie als Dienstleister für viele Kunden arbeiten wollen, dann könnten Sie die App sogar als "Multi Tenant"-App bereitstellen, so dass Sie viele Exchange Online Tenants "as a Service" verwalten können.
- Step 1: Register the application in
Azure AD
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#step-1-register-the-application-in-azure-ad - Step 4: Attach the certificate to the Azure AD application
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#step-4-attach-the-certificate-to-the-azure-ad-application - Step 2: Assign API permissions to the application
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#step-2-assign-api-permissions-to-the-application - Step 5: Assign Azure AD roles to the application
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#step-5-assign-azure-ad-roles-to-the-application
RBAC Rollen zuweisen (Optional)
Wenn Sie die soeben konfigurierte App direkt nutzen, dann haben Sie alle Rechte auf die Exchange Konfiguration. Sie sind quasi "Global Admin" hinsichtlich Exchange. Das ist für eine App, die vielleicht nur einen kleinen Teilaspekte der Exchange Konfiguration verwalten soll, viel zu viel. Seit Exchange 2010 kennen wir "OnPremises" die Funktion RBAC - Role Based Access Control. Diese gibt es in vergleichbarer Form auch bei Exchange Online und kann nicht nur auf Anwender, sondern auch auf App-Registrations angewendet werden. Genau genommen können wir in Exchange damit steuern, welche App, welches Rechte auf welchen Scope anwenden darf. Eine Rollenzuweisung kombiniert diese drei Bausteine.
Damit Exchange aber die App als kennt, brauchen wir die AppID und legen damit ein "Service Principal" an. Technisch legen wir im Echange Online Forest ein Objekt an, damit wir diesem dann die Berechtigungen zuweisen können.
New-ServicePrincipal ` -AppId <CApplicationID> ` -ObjectId <objectID> ` -DisplayName <name>
Die Werte für die ApplicationID und ObjectID übernehmen Sie einfach aus der App Registration im AzureAD-Portal
Sie können in Exchange Online auch noch einen "Management Scope" anlegen. Hier ein Beispiel basierend auf dem Land:
New-ManagementScope ` -Name "Mitarbeiter in Deutschland" ` -RecipientRestrictionFilter ""CountryOrRegion -eq 'Germany'"
Denkbar sind natürlich auch CustomAttribute, Gruppenmitgliedschaften etc.
- New-ManagementScope
https://learn.microsoft.com/en-us/powershell/module/exchange/new-managementscope?view=exchange-ps
recipientrestrictionfilter
https://learn.microsoft.com/en-us/powershell/module/exchange/new-managementscope?view=exchange-ps#-recipientrestrictionfilter - Filterable properties for the RecipientFilter parameter on Exchange cmdlets
https://learn.microsoft.com/en-us/powershell/exchange/recipientfilter-properties?view=exchange-ps
Mit dem ServicePrincipal und dem optionalen ManagementScope kann ich dann die Rechte verknüpfen,
New-ManagementRoleAssignment ` -Name "Rollenbezeichnung" ` -Role <RoleIdParameter> ` -App <AppID> ` -CustomResourceScope <Management Scope> (oder -RecipientAdministrativeUnitScope)
Damit beschränke ich die weiter oben angelegte App auf die entsprechenden Empfänger und gewünschte Funktion
- Role Based Access Control for Applications in Exchange Online
https://learn.microsoft.com/en-us/exchange/permissions-exo/application-rbac
Exchange Online PowerShell verbinden
Mit der AppID der gerade angelegten Application (bei mir 9cb958d8-3f03-4f5e-b71a-8ae25a289b78) und dem Zertifikat kann ich direkt die Exchange Online PowerShell V2 verbinden.
Wichtig ist, dass Sie mit dem Parameter "-Organization" den Tenant spezifizieren, denn die PowerShell hat ja "nur" das Zertifikat und keinen UPN eines Benutzers, anhand dessen er den richtigen Tenant ermitteln kann.
# Verbinden mit PFX-Datei und Zertifikat Connect-ExchangeOnline ` -CertificateFilePath ".\automation-cert.pfx" ` -CertificatePassword (ConvertTo-SecureString -String "<MyPassword>" -AsPlainText -Force) ` -AppID "36ee4c6c-0812-40a2-b820-b22ebd02bce3" ` -Organization "msxfaqdev.onmicrosoft.com"
Wenn ich das Zertifikat im Computerstore habe, dann brauche ich kein Kennwort.
Connect-ExchangeOnline ` -CertificateThumbPrint "815E2AD820B297DF4ED8D278CCE2D06EDAE35267" ` -AppID "9cb958d8-3f03-4f5e-b71a-8ae25a289b78" ` -Organization "msxfaqdev.onmicrosoft.com"
Die Verbindung ist erstaunlich robust. Auch ein Wechsel der IP-Adresse, ein "Schlafmode" des Notebook über 8 Stunden etc. hat die PowerShell nicht gestört. Die Verbindung wurde automatisch wieder erneuert.
Alternativ kann ich mich auch mit einem "Client Secret" verbinden, wobei ich mir dazu erst ein Access-Token generieren muss. Das geht klassisch manuell mit einem Invoke-WebRequest:
$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 = "Kennwort der App" $token = Invoke-RestMethod ` -Method POST ` -ContentType 'application/x-www-form-urlencoded' ` -Uri "https://login.microsoftonline.com/$($tenantid)/oauth2/v2.0/token" ` -Body @{ client_id = $clientid client_secret = $clientsecret scope = Scopes' grant_type = 'client_credentials' }
Alternative können Sie auch MSAL.PS dazu verwenden.
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
Achtung: Hinterlegen Sie nie Kennworte in einem Skript. Zu oft wurde solcher Source Code dann auf Github oder anderen Plattformen irrtümlich veröffentlicht oder durch Angreifer "gefunden"
- MSAL.PS
- Connecting to Exchange Online PowerShell
via client secret
https://www.michev.info/blog/post/2997/connecting-to-exchange-online-powershell-via-client-secret-flow
Fehlerbilder
Mögliche Fehler, auf die ich gestoßen bin:
- Admin Consent nicht gewährt:
Exception: Connecting to remote server outlook.office365.com failed with the following error message : Zugriff verweigert For more information, see the about_Remote_Troubleshooting Help topic.
- Fehlende Exchange Admin Rolle:
Exception: Processing data from remote server outlook.office365.com failed with the following error message: [AuthZRequestId=654e14bf-819d-49cc-ae3d-c993b1ff56b6][FailureCategory=AuthZ-CmdletAccessDeniedException] Die Rolle, die der Anwendung 9cb958d8-3f03-4f5e-b71a-8ae25a289b78 zugewiesen ist, wird in diesem Szenario nicht unterstützt. Bitte beachten Sie die Onlinedokumentation, um der Azure AD-Anwendung die richtigen Verzeichnisrollen für die EXO Nur-App-Authentifizierung zuzuweisen. For more information, see the about_Remote_Troubleshooting Help topic.
Missbrauch
Auch wenn Sie eine Application entsprechend eingerichtet haben, so können Sie unter "Permission" auch andere Berechtigungen sehen. Ich habe daher einfach die gleichen Anmeldedaten mal genutzt, um eine Graph PowerShell zu starten. Das hat natürlich funktioniert.
PS C:\> Connect-MgGraph ` -ClientID "9cb958d8-3f03-4f5e-b71a-8ae25a289b78" ` -TenantId "msxfaqdev.onmicrosoft.com" ` -CertificateThumbprint "815E2AD820B297DF4ED8D278CCE2D06EDAE35267" PS C:\> Get-MgContext ClientId : 9cb958d8-3f03-4f5e-b71a-8ae25a289b78 TenantId : 604d9047-44e5-443a-ad8f-98abe5748b0a CertificateThumbprint : 815E2AD820B297DF4ED8D278CCE2D06EDAE35267 Scopes : AuthType : AppOnly AuthProviderType : ClientCredentialProvider CertificateName : Account : AppName : MSXFAQDEV EXOPS2 CBA ContextScope : Process Certificate : PSHostVersion : 7.2.5 ClientTimeout : 00:05:00
Obwohl ich keine Scope oder Rechte mit angefordert habe, konnte ich einige Commandlets nutzen z.B.: Get-MGUser, Get-MGGroup etc. ein Code, der Zugriff auf AppID, Tenantname und das Zertifikat hat, kann also durchaus einige "Default Rechte" ausüben. Achten Sie daher auf ihre Zugangsdaten.
Einschätzung
Auslöser für diese Seite war die Suche nach einem Weg, Exchange-Kontakte in einem anderen Tenant automatisiert zu pflegen. Per Graph ist es nicht möglich und mit MFA kann ich nicht mit einem Dienstkonto arbeiten. Die Nutzung der Exchange Online PowerShell V2 mittels Zertifikat und registrierter Application finde ich mehr als nur interessant, denn es ist eine effektive Lösung für die Aufgabenstellung "automatisches Provisioning". Meine Anforderungen einer Automatisierung von Exchange Online-Einstellungen kann ich damit problemlos umsetzen.
Weitere Links
- Exchange PowerShell V3
- Conditional Access
- MFA und Dienstkonten
- App Password
- Exchange Online PowerShell V2
-
App-only authentication for unattended
scripts in Exchange Online PowerShell and
Security & Compliance PowerShell
https://learn.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2 - App-only authentication for unattended
scripts in the EXO V2 module
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#set-up-app-only-authentication - Moving from the Exchange PowerShell v1
Module to the v2 Preview
https://techcommunity.microsoft.com/t5/exchange-team-blog/moving-from-the-exchange-powershell-v1-module-to-the-v2-preview/ba-p/3450679 - Use app-only authentication with the
Microsoft Graph PowerShell SDK
https://docs.microsoft.com/en-us/powershell/microsoftgraph/app-only - Hacking your way around Modern
authentication and the PowerShell modules
for Office 365
https://www.michev.info/Blog/Post/1771/hacking-your-way-around-modern-authentication-and-the-powershell-modules-for-office-365 - Exchange Online to Stop Support for
Remote PowerShell Connections in June 2023
https://office365itpros.com/2022/12/19/remote-powershell-deprecation/ - Avoid Windows Task Scheduler When
Running Microsoft 365 PowerShell Scripts
https://practical365.com/dump-task-scheduler/ - Modern Auth and Unattended Scripts in
Exchange Online PowerShell V2
https://o365reports.com/2020/07/04/modern-auth-and-unattended-scripts-in-exchange-online-powershell-v2/ - Connect to Exchange Online using App
Registration and Certificate
https://techlabs.blog/categories/automation/connect-to-exchange-online-using-app-registration-and-certificate