HybridManagment.psm1
Wenn Sie auf einem Windows Server für die Nutzung von Exchange Hybrid den Weg über "Modern Hybrid" wählen und den Hybrid Agent installieren, dann erhalten Sie nicht nur einen Dienst sondern auch ein PowerShell-Module. Diese Seite behandelt, was Sie damit anstellen können, dass einige Dinge wohl fehlerhaft sind und wie Sie dies umgehen.
Beachte dazu auch die Seite Modern Agent mit MGGraph.
Das PS1M-Modul
Das Hybrid Management kommt nicht als Standard-Modul mit der Powershell mit und kann nicht einfach mit "Import-Module" geladen werden. Die PowerShell durchsucht beim Import-Module nur einige vordefinierte Verzeichnisse und dazu gehört nicht das "Programm Files"-Verzeichnis.
Daher müssen Sie das Modul erst einmal in einer Powershell laden:
Hinweis: Anscheinend gibt es von Microsoft immer mal wieder ein Update unter der URL https://aka.ms/hybridconnectivity. Bitte laden Sie die aktuelle Version herunter.
Achtung: Das Modul lädt auch unter Powershell 7 aber davon abhängige Module funktionieren nur mit PowerShell 5. Daher bitte für das Hybrid Management die "alte" PowerShell nutzen (Stand Nov 2024). Prüfen Sie die Version einfach mit "$PSVersionTable.psversion.tostring()".
PS C:\> Import-Module "C:\Program Files\Microsoft Hybrid Service\HybridManagement.psm1"
Die im Modul enthaltenen Commandlets sind schnell aufgelistet.
PS C:\> Get-Command -Module HybridManagement CommandType Name ModuleName ----------- ---- ---------- Function GetAuthHeader HybridManagement Function GetAuthToken HybridManagement Function Get-HybridAgent HybridManagement Function Get-HybridApplication HybridManagement Function New-HybridApplication HybridManagement Function Remove-HybridApplication HybridManagement Function TestEndpoints HybridManagement Function Test-HybridConnectivity HybridManagement Function TestoneEndpoint HybridManagement Function TestProxySettings HybridManagement Function TestTLSSettings HybridManagement Function Update-HybridApplication HybridManagement
Allerdings fällt das inkonsistente Namensschema auf. Normalerweise folgen PowerShell-Commandlets dem "Verb-Noun"-Schema und oft noch mit dem Bereichsnamen. So gibt es mehrere Commandlets, die sich alle auf einen Benutzer beziehen aber produktspezifisch sind, z.B. Get-ADUser, Get-AzureADUser, Get-MSOLUser, Get-CSUser. In den Anfangszeiten der PowerShell war das aber wohl noch nicht so bekannt und Exchange 2007 hat "Get-User" für sich beansprucht und hält es bis heute bei. Nur Exchange Online hat ein "Get-EXOUser".
Das HybridManagement-Module hat aber gerade mal drei Commandlets und sieht auch sonst ziemlich zusammengestückelt aus.
Ursache ist aber, dass Microsoft interne Funktionen nicht versteckt hat. Test-HybridConnectivity ruft seinerseits nämlich "TestEndpoints" und "TestoneEndpoint" auf. Das hätte man über ein Manifest oder Export-ModuleMember schöner lösen können.
- Approved Verbs for PowerShell Commands
https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands?view=powershell-7.4 - Export-ModuleMember
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/export-modulemember?view=powershell-7.4 - PowerShell Export-ModuleMember vs Export keys in manifest
https://www.itidea.nl/index.php/powershell-export-modulemember-vs-export-keys-in-manifest/
Test-HybridConnectivity
Das erste Commandlet, welches sie einfach so nutzen können, ist Test-HybridConnectivity. Es prüft die Auflösung und Erreichbarkeit der aus Sicht von Microsoft wichtigen Gegenstellen zur Funktion des Hybrid Agent.
PS C:\> Test-HybridConnectivity Testing connection to mscrl.microsoft.com on port 80 Testing connection to crl.microsoft.com on port 80 Testing connection to ocsp.msocsp.com on port 80 Testing connection to www.microsoft.com on port 80 Testing connection to login.windows.net on port 443 Testing connection to login.microsoftonline.com on port 443 Testing connection to aadap-portcheck-seaus.connectorporttest.msappproxy.net on port 8080 WARNING: Ping to aadap-portcheck-seaus.connectorporttest.msappproxy.net failed -- Status: DestinationHostUnreachable WARNING: TCP connect to aadap-portcheck-seaus.connectorporttest.msappproxy.net:8080 failed Performing GET on https://aadap-portcheck-seaus.connectorporttest.msappproxy.net:8080 Invoke-WebRequest : Unable to connect to the remote server At C:\Program Files\Microsoft Hybrid Service\HybridManagement.psm1:196 char:19 + $result = Invoke-WebRequest -Method Get -Uri $uri + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [I nvoke-WebRequest], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.Inv okeWebRequestCommand
Die PSM1-Datei ist natürlich Klartext und so können wir direkt sehen, welche Endpunkte Microsoft hier codiert hat:
Das sind nun keine große Überraschungen enthalten. Die meisten Adressen und Ports beziehen sich auf HTTP/HTTPS und nur eine Zeile mit Port 8080 fällt aus dem Rahmen. Dieser Host und Port sind in den Requirements nicht aufgeführt und der Hybrid Agent funktioniert bei mir auch ohne diesen Port. Als wen hier jemand eine Gegenstelle für Rückmeldungen vorgesehen hat. Port 8080 ist aber meist ein alternativer Webserver-Port ohne Verschlüsselung.
- Microsoft Hybrid Agent
https://learn.microsoft.com/de-de/exchange/hybrid-deployment/hybrid-agent
Azure und SHA256Cng
Auf dem Weg zu den anderen interessanten Commandlets ist natürlich eine Anmeldung an EntraID erforderlich. Dazu bedient sich das Hybrid Management am "Azure"-Modul, welche nicht mit installiert wurde. Das sehen sie z.B. beim Aufruf von "Get-HybridAgent".
PS C:\> Get-HybridAgent -Credential (Get-Credential) cmdlet Get-Credential at command pipeline position 1 Supply values for the following parameters: Credential Import-Module : The specified module 'Azure' was not loaded because no valid module file was found in any module directory. At C:\Program Files\Microsoft Hybrid Service\HybridManagement.psm1:11 char:5 + Import-Module Azure + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceUnavailable: (Azure:String) [Import-Module], FileNotFou ndException + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModu leCommand
Hier fehlt noch das Azure-Modul, welches ich schnell nachinstallieren muss. Damit aber noch nicht genug, denn es fehlt auch noch Azure.Storage
# erforderliche Module installieren Install-Module -Name Azure, Azure.Storage -Repository PSGallery -AllowClobber -Force # Module inportieren Import-Module -Name Azure #Anmelden, damit eine Session besteht Add-AzureAccount
Aber selbst dann bekomme ich noch keine Verbindung und stattdessen einen Fehler, dass CNG256 nicht geladen werden konnte.
Add-AzureAccount : Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral...
Die Ursache dabei ist aber, dass ich eine "zu alte Powershell" genutzt habe. Wer noch nicht auf PowerShell 5.1 ist, sollte WMF 5.1 (oder neuer) aktualisieren
Windows Management Framework 5.1
https://www.microsoft.com/en-us/download/details.aspx?id=54616
- Installing the Azure PowerShell Service
Management module
https://learn.microsoft.com/en-us/powershell/azure/servicemanagement/install-azure-ps
Die PowerShell 4 oder älter kennt die neueren Encryption Verfahren noch nicht.
Anmeldung mit MFA
Nachdem auch diese Hürde übersprungen wurde, dürfte sie die MFA-Hürde erwischen. Selbst ein im November 2024 neu installierter Hybrid Agent bringt immer noch eine HybridManagement.psm1-Datei von 2019 mit, die kein MFA unterstützt. Microsoft hat aber über die Security Defaults eine MFA-Anmeldung für Administratoren erzwungen
- Security Defaults
- Security defaults in Microsoft Entra ID
https://learn.microsoft.com/en-us/entra/fundamentals/security-defaults
Entsprechend bekommen Sie dann eine Fehlermeldung:
PS C:\> Get-HybridAgent -credential $cred GetAuthToken : Exception calling "AcquireToken" with "3" argument(s): "AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access '00000003-0000-0000-c000-000000000000'. Trace ID: 210f40a5-7867-487a-9aaf-8eacc6d56a00 Correlation ID: 15a25832-beed-45e2-8a22-ceca3e19b2c7 Timestamp: 2024-11-06 10:29:36Z"
Wer eine EntraID P1/Premium-Lizenzen hat, kann mittels Conditional Access z.B. MFA für den Zugriff von diesem Server über die öffentliche IP-Adresse abschalten. Einfacher ist es aber wohl, einfach eine aktueller Version der HybridManagement.psm1 herunterzuladen. Microsoft hat dazu extra eine eigene Kurz-URL bereitgestellt:
Download der aktuellen
HybridManagement.psm1
https://aka.ms/hybridconnectivity
Fragen Sie mich bitte nicht, warum Microsoft nicht gleich diese Version mit in das MSI-Paket inkludiert, zumal Der Hybrid-Agent sogar einen eigenen Hybrid Updater Agent mitbringt. Sie müssen dann aber statt "-Credentials" den Parameter "-UserPrincipalName" nutzen
PS C:\> Get-HybridAgent -UserprincipalName admin@msxfaqlab.onmicrosoft.com | fl id : c9b35e0d-a6f8-4440-aab9-ae7530c0b120 machineName : EX01.UCLABOR.DE externalIp : 80.66.20.27 status : active
*-HybridApplication
Zu den Befehlen der HybridManagement.psm1-Modul gehört aber noch folgende Befehle:
Get-HybridApplication New-HybridApplication Remove-HybridApplication Update-HybridApplication
Diese können Sie aber nicht so einfach nutzen, denn alle Befehle erwarten eine Angabe der "AppID", d.h. der GUID zur passenden Applikation. Auch das Commandlet "Get-HybridApplication" hat keine Funktion, um alle Agenten aufzulisten. Die AppID ist einmalig und keine generische Nummer. Der Versuch mir dann aber auch die EntraID-Application zu besorgen, hat wieder nicht funktioniert. Zuerst habe ich die ID des Hybrid Agent genutzt, die aber nicht gefunden wurde.
Mit der Ausgabe von "Verbose" und einem Blick in den Code würde ich sagen, das das nie funktionieren sollte, denn sie sehen hier das "/edu/" in der URL.
Ich war mir ziemlich sicher, dass dieser Code so nicht in den regulären Umgebungen funktionieren kann. Zumal ich in den HCW-Logdateien (HCW Logging) folgende URLs gefunden habe:
2024.11.05 17:12:12.382 10386 [Client=UX, Thread=19] Previous Connector Application Name found: eb92551b-9c63-4472-a8dc-2be7fcf00313 2024.11.05 17:12:12.897 10332 [Client=UX, fn=SendAsync, Thread=19] START GET https://graph.microsoft.com/beta/463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c/applications/ eb92551b-9c63-4472-a8dc-2be7fcf00313/onPremisesPublishing 2024.11.05 17:12:13.100 10333 [Client=UX, fn=SendAsync, Thread=19] FINISH Time=203,1ms Results=OK { "@odata.context":"https://graph.microsoft.com/beta/$metadata#applications('eb92551b-9c63-4472-a8dc-2be7fcf00313')/onPremisesPublishing", "externalUrl":"https://eb92551b-9c63-4472-a8dc-2be7fcf00313.resource.mailboxmigration.his.msappproxy.net/", "internalUrl":"https://ex01.uclabor.de/", "alternateUrl":null, "externalAuthenticationType":"passthru", "isTranslateHostHeaderEnabled":false, "isTranslateLinksInBodyEnabled":false, "isOnPremPublishingEnabled":true, "isHttpOnlyCookieEnabled":false, "isSecureCookieEnabled":false, "isPersistentCookieEnabled":false, "isBackendCertificateValidationEnabled":true, "applicationServerTimeout":"Default", "useAlternateUrlForTranslationAndRedirect":false, "applicationType":"", "isStateSessionEnabled":true, "isAccessibleViaZTNAClient":false, "isDnsResolutionEnabled":false, "verifiedCustomDomainCertificatesMetadata":null, "verifiedCustomDomainKeyCredential":null, "verifiedCustomDomainPasswordCredential":null, "segmentsConfiguration":null, "singleSignOnSettings":{ "singleSignOnMode":"none", "kerberosSignOnSettings":null }, "onPremisesApplicationSegments":[] }
HCW nutzt aber nicht die ConnectorID als GUID sondern eine andere Nummer, die bislang noch nicht aufgetaucht ist. Ich habe sie nur beim Migration Endpoint gefunden und im HCWLog sehe ich auch, dass der HCW genau diesen Befehl auch aufruft.
2024.11.05 17:16:44.724 10276 [Client=UX, Session=Tenant, Cmdlet=Get-MigrationEndpoint, Thread=7] START 2024.11.05 17:16:45.159 10277 [Client=UX, Session=Tenant, Cmdlet=Get-MigrationEndpoint, Thread=7] FINISH Time=434,6ms Results=1 { AcceptUntrustedCertificates=False EndpointType=ExchangeRemoteMove Guid=1b2ab337-614c-443a-b5d9-8ab57596e95d Identity=Hybrid Migration Endpoint - EWS (Default Web Site) Identity(ObjectId)=Hybrid Migration Endpoint - EWS (Default Web Site) IsPublicFolderMailboxesMigrationSource=False IsRemote=True IsValid=True MailboxPermission=Admin MaxConcurrentIncrementalSyncs=10 MaxConcurrentMigrations=20 RemoteServer=eb92551b-9c63-4472-a8dc-2be7fcf00313.resource.mailboxmigration.his.msappproxy.net Username=UCLABOR\admfc}
Ich kann nur vermuten, dass der HCW hier im Hintergrund über die Exchange Online PowerShell sich den "Remoteserver" und daraus die AppID besorgt. Mit dieser GUID gelingt dann auch die Abfrage mit Get-HybridApplication. Anscheinend hat "Graph" hier einen Alias, denn auch der Zugriff über den "/edu/"-Pfad funktioniert:
Wenn Sie nun glauben, dass ihre Werte hier falsch sind, dann können Sie diese mit einem "Update-HybridApplication" natürlich korrigieren. Die "HybridManagement.psm1" enthält den passenden Code und sie haben auch die Berechtigungen. Allerdings erlaubt das Commandlet nur das Setzen der TargetURL.
Das kann mal erforderlich sein, wenn Sie mitten in der Migration sich entschließen, eine neue lokale URL zu verwenden. Das ist aber eher unüblich.
Eigene Abfragen
Dieser Abschnitt ist entstanden, ehe ich mit MGGraph einen besseren Weg gefunden und auf HCW Modern Agent mit MGGraph beschrieben habe. Aber vielleicht interessiert jemand auch der Zugriff ohne MGGraph PowerShell
Das ganze geht natürlich auch ohne MGGraph mit direkten PowerShell-aufrufen. Das Microsoft Modul gibt sich als "AzureAD PowerShell" aus und das kann ich genauso. Damit erspare ich mir weitere Consent-Abfragen und bin sicher, dass ich genau die gleichen Berechtigungen habe.
$ClientID = "1950a258-227b-4e31-a9cf-717495945fc2" $TenantDomain = "msxfaqlab.onmicrosoft.com" $Token = Get-MsalToken -TenantId $TenantDomain -ClientId $ClientID $TenantID = $Token.TenantID
Mit "Get-MSALToken" kommt dann auch der klassische Anmeldedialog, der auch MFA unterstützt und am Ende enthält die Variable "$token" ein AccessToken und einige andere Informationen. Das AccessToken ist wieder ca. 75 Minuten gültig. Hier nur ein Auszug:
{ "aud": "https://graph.microsoft.com", "iat": 1730893988, "nbf": 1730893988, "exp": 1730898197, "amr": [ "pwd", "mfa" ], "app_displayname": "Microsoft Azure PowerShell", "appid": "1950a258-227b-4e31-a9cf-717495945fc2", "idtyp": "user", "name": "fcadm msxfaqlab", "scp": "AuditLog.Read.All Directory.AccessAsUser.All email openid profile", "tenant_region_scope": "EU", "tid": "463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c", "unique_name": "fcadm@msxfaqlab.onmicrosoft.com", "upn": "fcadm@msxfaqlab.onmicrosoft.com", }
Diese Token setzen wir dann in einen HTTP-Header und starten den Graph-Abruf:
$authHeader = @{ 'Content-Type'='application\json' 'Authorization'=$token.CreateAuthorizationHeader() } $uri = "https://graph.microsoft.com/beta/onPremisesPublishingProfiles/applicationProxy/connectorGroups?$expand=members" $ConnectorGroups = Invoke-RestMethod ` -URI $uri ` –Headers $authHeader ` –Method GET
Die Variable $ConnectorGroups enthält dann die JSON-Payload im Property "value". In meinem LAB-Tenant finde ich da drei Einträge:
Es ist also nicht nur der Hybrid Connector, welcher hier aufgeführt wird, sondern auch mein EntraID Connect Sync und vermutlich auch GroupWriteback. Darauf gehe ich aber nicht weiter ein und mir reicht die ID meines Exchange Hybrid Sync.
# Die ConnectorID hole ich mir wie folgt: $Connectorid = ($ConnectorGroups.value | where-object {$_.connectorgroupType -eq "exchangeOnline"}).id
ConnectorApplicationName
Ich möchte aber noch mehr über die Konfiguration des AppProxy erfahren, den ich nicht im AzureAD meines Tenants sehe. Im HCW Logging finde ich dazu folgende URL:
https://graph.microsoft.com/beta/463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c/applications/eb92551b-9c63-4472-a8dc-2be7fcf00313/onPremisesPublishing
Der Wert "eb92551b-9c63-4472-a8dc-2be7fcf00313" finde ich im HCW-Logging als "ConnectorApplicationName" aber keine weitere Information, woher die ID ausgelesen wird. Google liefert dazu nicht und auch eine Suche im AzureAD zeigt nichts an.
Auch im lokalen Active Directory konnte ich keinen Treffer auf die GUID landen. Im HCW-Logging sehe ich aber einen Aufruf auf folgende URL:
Den Tenant mit seiner ID kenne ich aber die AppID scheint sogar eine Zufallszahl zu sein. Im Code von "Hybridmanagement.psm1" steht sogar die Generierung wie folgt drin:
Das passt aber nicht mit meinen Betrachtungen, dass ich die App komplett löschen und neu anlegen lassen kann und die GUID doch wieder die gleiche ist. Der Prozess ist etwas undurchsichtig. Zumal die Application auch nicht aufgeführt wird. Wenn ich die URL etwas anpasse, dann bekomme ich schon ein Antwort, aber nicht die gewünschte Applikation.
# $uri = "https://graph.microsoft.com/beta/$($token.tenantID)/applications/$ClientID/onPremisesPublishing" $url="https://graph.microsoft.com/beta/463e98ae-b7d4-4af2-8ef8-3eda0b4d8a7c/applications/eb92551b-9c63-4472-a8dc-2be7fcf00313/onPremisesPublishing" $application = Invoke-RestMethod -Uri $uri –Headers $authHeader –Method GET $application.value
Das ist nun unerwartet, denn ich hätte entweder einen Fehler oder leere Rückgabe erwartet, aber keine Liste aller von mir selbst definierten Apps. Aber auch der Versuch mit "/edu/" liefert genau die gleichen Informationen zurück. Ich habe mir dann noch einmal den aktuellen Code von "HybridManagement.psm1" angeschaut und noch eine Unstimmigkeit gefunden.
Die Variable "$foundApplications" kommt sonst nirgends vor und liefert dann wohl ein "$null". Eine Rückgabe liefert das Commandlet wohl nur aufgrund von "$applications" in Zeile 103. Ich kann aber keinen Unterschied zwischen dem REST-Aufruf in dem Microsoft Module und meiner interaktiven Aufrufe erkennen aber die Ergebnisse unterscheiden sich.
Die GUID der Application habe ich indirekt über die Exchange Online PowerShell ermitteln können, weil es natürlich einen Migration Endpoint gibt.
Install-Module ExchangeOnlineManagement Connect-ExchangeOnline Get-MigrationEndpoint | fl identity,remoteserver Identity : Hybrid Migration Endpoint - EWS (Default Web Site) RemoteServer : eb92551b-9c63-4472-a8dc-2be7fcf00313.resource.mailboxmigration.his.msappproxy.n et
Das ist aber keine verlässliche Quelle.
Einschätzung
Ich hoffe, dass Sie möglichst wenig mit dem Modul "HybridManagement" und dem "Modern Hybrid Agent" zu tun haben. Es ist eine Möglichkeit etwas hinter die Kulissen zu schauen und mögliche Fehler bei der Installation durch den HCW zu erkennen. Die Korrekturmöglichkeiten sind aber doch stark eingeschränkt und die Handhabung ist nicht gerade einfach. Andere Managementmodule kennen ein "Connect-*" Befehl, um einmal die Authentifizierung zu erledigen. Hier müssen entweder jedes Mal die Credentials oder den UPN mitgeben. Auch dass eigentlich "interne" Funktionen "Exportiert" werden, ist unschön. Die Namen könnten mit bestehenden Commandlets oder Skripten kollidieren.
Dennoch wird es wohl die ein oder andere Notwendigkeit geben, damit zu arbeiten. Dann wissen sie nun aber um die Fallstricke und notwendige Voraussetzungen wie z.B. die Notwendigkeit der Powershell 5, die Erfordernis weiterer Azure-Module und dass der MFA-Support nur mit der aktuellsten Version enthalten ist. Das kann man es fast verschmerzen, dass das Skript die AppID der "Azure AD Powershell" zur Anmeldung kapert. Wenn Sie aber schon immer mal ein kleines Skript analysieren wollten, wie es sich ein AuthToken besorgt und damit Graph-Aufrufe durchführt, dann können Sie einmal spicken.
Weitere Links
- Modern Agent mit MGGraph
- Hybrid Agent
- HCW Logging
- HCW - Hybrid Configuration Wizard
- Hybrid Agent, Extended Protection und Port 9821
- MGGraph PowerShell
- Microsoft Hybrid Agent
https://learn.microsoft.com/en-us/exchange/hybrid-deployment/hybrid-agent - Modern HCW (Hybrid Agent):
troubleshooting like a pro
https://techcommunity.microsoft.com/blog/exchange/modern-hcw-hybrid-agent-troubleshooting-like-a-pro/1558725 - The Microsoft Hybrid Agent Public
Preview
https://techcommunity.microsoft.com/blog/exchange/the-microsoft-hybrid-agent-public-preview/608939 - Testing a New Exchange Hybrid Configuration with Office 365
https://practical365.com/testing-new-exchange-hybrid-configuration-office-365/ - Modern HCW (Hybrid Agent): troubleshooting like a pro
https://techcommunity.microsoft.com/blog/exchange/modern-hcw-hybrid-agent-troubleshooting-like-a-pro/1558725 - Troubleshooting Hybrid Migration Endpoints in Classic and Modern Hybrid
https://techcommunity.microsoft.com/blog/exchange/troubleshooting-hybrid-migration-endpoints-in-classic-and-modern-hybrid/953006 - Installing the Azure PowerShell Service Management module
https://learn.microsoft.com/en-us/powershell/azure/servicemanagement/install-azure-ps - Troubleshoot Office 365 Hybrid Configuration and Hybrid Agent
https://blog.icewolf.ch/archive/2020/04/29/troubleshoot-office-365-hybrid-configuration-and-hybrid-agent/