MFA, Rollen, Gäste & Postfächer prüfen
Ein Klick durch die Admin Center deckt einen kompromittierten Tenant nicht auf. Stichproben im Webinterface sind fehleranfällig, liefern keine historischen Vergleichswerte und verbergen die Verschachtelungen zwischen Identitäten, Geräten und Daten.
Genau dort setzen Angreifer an: an der schwächsten Verbindung, meist an Konten mit schwacher Authentifizierung. Ein belastbares Security Audit braucht deshalb Rohdaten, keine aggregierten Portalansichten.
Erfahrungen aus Hardening-Projekten zeigen ein klares Muster: Die meisten erfolgreichen Angriffe auf Microsoft-365-Umgebungen nutzen eine Handvoll immer gleicher Schwachstellen. Fehlendes MFA-Enforcement, offene Legacy-Protokolle, unkontrollierte App-Berechtigungen, fehlende Geräte-Compliance und deaktiviertes Audit Logging. Alle fünf sind über PowerShell prüfbar, lange bevor sie im Portal auffallen.
Dieser Audit umfasst 80 Prüfpunkte und ist in drei Teile aufgeteilt.
Teil 1 nimmt sich Identität und MFA, Conditional Access, privilegierte Rollen, Gäste und die Exchange-Postfächer vor. Teil 2 widmet sich Mail-Schutz, Collaboration, Geräten und Apps, Teil 3 schließt mit Daten-Governance, Compliance und Monitoring ab.
Jeder Prüfpunkt funktioniert eigenständig und kann einzeln ausgeführt werden. Alternativ lassen sich die relevanten Bausteine für den Produktivbetrieb in einem Sammelskript oder Azure Automation Runbook bündeln.




Identität, MFA und Risiko
1. Entra ID MFA und Phishing-Resistenz
Lizenz:Entra ID Free (Basis), Entra ID P1 (detailliertere Logs)
Der reine Status "MFA-registriert" greift zu kurz. AitM-Angriffe (Adversary in the Middle) fangen Session-Cookies per Proxy ab und umgehen klassische Push-Benachrichtigungen. Was zählt, ist die konkrete Methode pro Konto, denn ein Nutzer, der nur SMS oder Sprachanruf hinterlegt hat, fällt bei SIM-Swapping und Social Engineering. In Graph laufen SMS und Voice beide unter dem Typ phoneAuthenticationMethod, deshalb genügt für die Schwach-Erkennung der Treffer auf phone. Ziel ist der Rollout von FIDO2 oder Passkeys und das harte Abschalten der Telefonverfahren.
# Modul: Microsoft.Graph.Identity.SignIns, Microsoft.Graph.Users
Connect-MgGraph -Scopes "UserAuthenticationMethod.Read.All","User.Read.All" -NoWelcome
$users = Get-MgUser -All -Property Id, UserPrincipalName
$mfaReport = foreach ($user in $users) {
$methods = Get-MgUserAuthenticationMethod -UserId $user.Id
$types = foreach ($m in $methods) { ($m.AdditionalProperties["@odata.type"] -replace "#microsoft.graph.","") }
[PSCustomObject]@{ UserPrincipalName = $user.UserPrincipalName; Methods = ($types -join ", ") }
}
$mfaReport | Where-Object { $_.Methods -match "phone" } | Format-Table # Befund: schwache Phone- oder SMS-Methode2. Globale Authentifizierungsmethoden-Richtlinie
Solange SMS oder Voice tenantweit erlaubt bleiben, ist reine Nutzer-Schulung wirkungslos, da schwache Verfahren wählbar bleiben. Die Authentication Methods Policy dient als Hebel zur sauberen technischen Abkündigung dieser Altverfahren. Steht eine Methode auf enabled, die niemand mehr nutzen soll, gehört sie auf disabled.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
(Get-MgPolicyAuthenticationMethodPolicy).AuthenticationMethodConfigurations |
Select-Object Id, State | Sort-Object Id | Format-Table # Befund: Id "Sms" oder "Voice" mit State "enabled"3. Security Defaults Status
Security Defaults sind Microsofts Basisschutz für Tenants ohne Conditional Access, beides gleichzeitig geht nicht. Der Wert ist nur im Kontext sinnvoll: Ohne CA-Policies muss IsEnabled auf True stehen, mit produktiven CA-Policies ist False korrekt. Ein Tenant ohne Security Defaults und ohne CA steht offen.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
(Get-MgPolicyIdentitySecurityDefaultEnforcementPolicy).IsEnabled4. Legacy-Authentifizierung in den Sign-In-Logs
Lizenz: Entra ID P1
Legacy-Protokolle wie IMAP, POP3 und SMTP Basic Auth authentifizieren sich außerhalb tokenbasierter Richtlinien, MFA greift dort nicht. Auch bei aktiver Blockierung zeigt die Analyse der Anmeldedaten, ob weiterhin Verbindungsversuche stattfinden, was auf fehlerhaft konfigurierte Clients oder gezielte Angriffe hindeutet. Die Gruppierung nach Legacy-Client macht Problemherde sofort sichtbar.
Connect-MgGraph -Scopes "AuditLog.Read.All" -NoWelcome
$since = (Get-Date).AddDays(-7).ToString("yyyy-MM-ddTHH:mm:ssZ")
$legacyApps = @("IMAP4","POP3","SMTP","MAPI","Other clients","Exchange ActiveSync","AutoDiscover")
$signins = Get-MgAuditLogSignIn -Filter "createdDateTime ge $since" -All
$signins | Where-Object { $_.ClientAppUsed -in $legacyApps } |
Group-Object ClientAppUsed | Select-Object Name, Count5. Inaktive Mitglieder-Konten
Lizenz: Entra ID P1
Nicht nur Gäste verwaisen. Ein internes Konto ohne Anmeldung über Monate ist entweder ein Ex-Mitarbeiter, dessen Offboarding hängt, oder ein vergessenes Service-Konto, beides Angriffsfläche ohne Geschäftsnutzen. Alles über 90 Tage ohne Login gehört auf den Prüfstand. Ohne P1 bleibt SignInActivity leer, dann ist das Ergebnis wertlos.
Connect-MgGraph -Scopes "AuditLog.Read.All","User.Read.All" -NoWelcome
$cut = (Get-Date).AddDays(-90)
$members = Get-MgUser -Filter "userType eq 'Member' and accountEnabled eq true" -Property UserPrincipalName, SignInActivity -All
$members | Where-Object { $null -ne $_.SignInActivity.LastSignInDateTime -and [datetime]$_.SignInActivity.LastSignInDateTime -lt $cut } |
Select-Object UserPrincipalName, @{N="LastSignIn";E={$_.SignInActivity.LastSignInDateTime}}6. Risiko-Benutzer aus Identity Protection
Lizenz: Entra ID P2
Identity Protection bewertet Anmelderisiko anhand von Signalen wie geleakten Credentials, IP-Reputation und atypischen Standorten. Steht ein Konto auf atRisk und greift keine automatische Remediation, läuft eine mögliche Kontenübernahme unbearbeitet weiter. Jeder Treffer gehört untersucht oder per Risk Policy zur Passwortänderung gezwungen.
Connect-MgGraph -Scopes "IdentityRiskyUser.Read.All" -NoWelcome
Get-MgRiskyUser -Filter "riskState eq 'atRisk'" -All |
Select-Object UserPrincipalName, RiskLevel, RiskState, RiskLastUpdatedDateTimeConditional Access und Sitzungen
7. Conditional Access Enforcement
Lizenz: Entra ID P1
Richtlinien für bedingten Zugriff definieren die harten Systemgrenzen des Tenants. Eine Richtlinie im Modus "Report Only" blockiert keinen einzigen Angriff, sie protokolliert nur, in Graph trägt dieser Zustand den Wert enabledForReportingButNotEnforced. Weil das Webportal Verschachtelungen und Ausschlüsse oft verdeckt, gehört der Zustand aller Policies in eine flache Übersicht.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
Get-MgIdentityConditionalAccessPolicy |
Select-Object DisplayName, State |
Sort-Object State | Out-GridView # Befund: State "enabledForReportingButNotEnforced"8. Vertrauenswürdige Named Locations
Viele Organisationen klammern Firmen-IP-Adressen von MFA aus. Wechselt das Unternehmen den Provider, bleiben diese IP-Ranges oft als "Trusted Locations" stehen, und wer diese alten IPs übernimmt, erhält direkten Bypass für Deine Authentifizierungsrichtlinien. Jeder vertrauenswürdige Standort braucht deshalb eine periodische Bestätigung durch die Netzwerkabteilung.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
Get-MgIdentityConditionalAccessNamedLocation -All |
Where-Object { $_.AdditionalProperties.isTrusted -eq $true } |
Select-Object DisplayName, ModifiedDateTime,
@{N="IPRanges";E={ ($_.AdditionalProperties.ipRanges.cidrAddress) -join ", " }}9. Sitzungssteuerung: Sign-in Frequency und Persistent Browser
Lizenz: Entra ID P1
Gestohlene Session-Tokens sind nur so lange wertvoll, wie die Sitzung gültig bleibt. Ohne Sign-in Frequency und ohne deaktivierten Persistent Browser auf nicht verwalteten Geräten bleibt ein abgegriffenes Token tagelang nutzbar. Welche Policies überhaupt Sitzungskontrollen setzen, zeigt der Blick in die SessionControls.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
Get-MgIdentityConditionalAccessPolicy |
Select-Object DisplayName,
@{N="SignInFrequency";E={$_.SessionControls.SignInFrequency.Value}},
@{N="PersistentBrowser";E={$_.SessionControls.PersistentBrowser.Mode}} |
Format-TablePrivilegierte Rollen und PIM
10. Privileged Identity Management Kontrolle
Lizenz: Entra ID P2
Permanente administrative Berechtigungen hebeln jedes Sicherheitskonzept aus. Ein kompromittierter Global Admin mit dauerhaften Rechten führt zur sofortigen Übernahme des Tenants, während PIM Just-in-Time-Zugriff erzwingt. Gesucht sind die dauerhaft zugewiesenen Rollen (Typ "Assigned" ohne Ablaufdatum), die Du anschließend in berechtigte Zuweisungen umwandelst. Ergebnisse liefert nur ein PIM-fähiger Tenant, direkte Nicht-PIM-Zuweisungen liest Du über Get-MgRoleManagementDirectoryRoleAssignment.
Connect-MgGraph -Scopes "RoleManagement.Read.Directory" -NoWelcome
$aa = Get-MgRoleManagementDirectoryRoleAssignmentSchedule -ExpandProperty "Principal,RoleDefinition" -All
$aa | Where-Object { $_.AssignmentType -eq "Assigned" -and $_.ScheduleInfo.Expiration.Type -eq "noExpiration" } |
Select-Object @{N="UPN";E={$_.Principal.AdditionalProperties.userPrincipalName}}, @{N="Role";E={$_.RoleDefinition.DisplayName}} |
Sort-Object Role | Format-Table -AutoSize11. Anzahl globaler Administratoren
Global Admin hat uneingeschränkten Zugriff auf alle Daten und Einstellungen, jedes zusätzliche Konto vergrößert den Blast Radius bei einer Kompromittierung. Microsoft empfiehlt zwei bis vier dedizierte Konten, strikt getrennt vom Alltagskonto. Liegt die Zahl darüber, gehört jedes Konto begründet oder entfernt.
Connect-MgGraph -Scopes "RoleManagement.Read.Directory" -NoWelcome
$ga = Get-MgDirectoryRole -Filter "displayName eq 'Global Administrator'"
$members = Get-MgDirectoryRoleMember -DirectoryRoleId $ga.Id -All
"Global Admins: $(@($members).Count)" # Empfehlung: 2 bis 4 dedizierte Konten
$members | ForEach-Object { $_.AdditionalProperties.userPrincipalName }12. Überwachung der Break-Glass-Accounts
Lizenz: Entra ID P1
Notfall-Administratorkonten sind bewusst von Conditional Access und MFA ausgenommen, damit eine Fehlkonfiguration den Zugriff nicht abschneidet. Diese Konten besitzen globale Admin-Rechte, jede Anmeldung bedeutet entweder einen IT-Notfall oder einen Sicherheitsvorfall. Findet sich ein Login ohne zugehöriges Notfall-Ticket, behandelst Du das als kritischen Vorfall.
Connect-MgGraph -Scopes "AuditLog.Read.All" -NoWelcome
$breakGlass = @("notfalladmin1@deinedomain.de","notfalladmin2@deinedomain.de")
$since = (Get-Date).AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")
Get-MgAuditLogSignIn -Filter "createdDateTime ge $since" -All |
Where-Object { $_.UserPrincipalName -in $breakGlass } |
Select-Object CreatedDateTime, UserPrincipalName, IpAddress, Status | Format-Table13. Lokale Administratoren auf eingebundenen Geräten
Auf Entra-ID-gejointen Windows-Clients gibt die Rolle für lokale Geräte-Administratoren lokale Admin-Rechte auf jedem Firmen-Notebook, ein kompromittiertes Konto mit dieser Rolle ermöglicht flächendeckende Ransomware-Verteilung. Eine Stolperfalle steckt im Namen: Mit dem Entra-Rebrand wurde die Rolle von "Azure AD Joined Device Local Administrator" auf "Microsoft Entra Joined Device Local Administrator" umbenannt, ein Filter auf den Anzeigenamen kommt deshalb leer zurück und meldet fälschlich null Treffer. Stabil bleibt nur die feste Rollen-Vorlagen-ID.
Connect-MgGraph -Scopes "RoleManagement.Read.Directory" -NoWelcome
# Stabil ueber die roleTemplateId, bei eingebauten Rollen entspricht sie der roleDefinition-Id
$deviceAdminRoleId = "9f06204d-73c1-4d4c-880a-6edb90606fd8"
Get-MgRoleManagementDirectoryRoleAssignment -Filter "RoleDefinitionId eq '$deviceAdminRoleId'" -ExpandProperty Principal |
Select-Object @{N="User";E={$_.Principal.AdditionalProperties.userPrincipalName}}, PrincipalId | Format-Table14. App-Registrierung durch Endnutzer
Dürfen Endanwender selbst App-Registrierungen anlegen, entstehen unkontrollierte Service Principals mit eigenen Secrets und API-Zugriffen. Das Zielbild lautet: Nur Admins registrieren Apps. Steht AllowedToCreateApps auf True, ist die Schranke offen.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
(Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions.AllowedToCreateApps # Befund, wenn TrueGäste und externe Zusammenarbeit
15. Inaktive B2B-Gastzugriffe
Lizenz: Entra ID P1
Externe Identitäten verwaisen schnell. Ein Dienstleister beendet ein Projekt, sein Konto bleibt aktiv, und wird sein Heimat-Tenant Wochen später kompromittiert, hat der Angreifer direkten B2B-Zugriff. Alles über 90 Tage ohne Anmeldung wird zur Deaktivierung markiert. Ohne P1 bleibt SignInActivity leer, dann erscheint jeder Gast fälschlich als inaktiv.
Connect-MgGraph -Scopes "AuditLog.Read.All","User.Read.All" -NoWelcome
$cut = (Get-Date).AddDays(-90)
$guests = Get-MgUser -Filter "userType eq 'Guest'" -Property Id, UserPrincipalName, SignInActivity -All
$guests | Where-Object {
$null -eq $_.SignInActivity.LastSignInDateTime -or [datetime]$_.SignInActivity.LastSignInDateTime -lt $cut
} | Select-Object UserPrincipalName, @{N="LastSignIn";E={$_.SignInActivity.LastSignInDateTime}}16. Gast-Einladungsrichtlinie
Steht AllowInvitesFrom auf everyone, darf jeder Mitarbeiter beliebige externe Konten einladen. Gastkonten leben danach in Gruppen, Teams und Sites weiter, auch wenn die Zusammenarbeit längst beendet ist. Eine Einschränkung auf Admins oder dedizierte Einlader bremst das Wachstum externer Identitäten.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
(Get-MgPolicyAuthorizationPolicy).AllowInvitesFrom # Befund, wenn "everyone"17. Cross-Tenant Access Settings
Die Cross-Tenant Access Settings steuern das Vertrauen zwischen Entra-ID-Umgebungen. Steht der Inbound-Trust zu offen, akzeptiert Dein Tenant MFA- und Compliance-Aussagen fremder Tenants ungeprüft. Liefert die Abfrage IsServiceDefault = True, gelten die Microsoft-Vorgaben unverändert, was selten zum tatsächlichen Kollaborationsmodell passt.
Connect-MgGraph -Scopes "Policy.Read.All" -NoWelcome
Get-MgPolicyCrossTenantAccessPolicyDefault |
Select-Object IsServiceDefault, InboundTrust | Format-ListExchange Online und Postfächer
18. Postfach-Delegierung (FullAccess)
Lizenz: Exchange Online Plan 1
Berechtigungen für Vollzugriff erzeugen unübersichtliche Netze für laterale Bewegung. Ein kompromittiertes Assistenz-Postfach gewährt oft Vollzugriff auf die Kommunikation der Geschäftsführung, das Feature AutoMapping verschleiert diese Zugriffe in Outlook. Gesucht sind die nicht geerbten FullAccess-Rechte abseits der Systemkonten.
Connect-ExchangeOnline -ShowBanner:$false
$mailboxes = Get-Mailbox -ResultSize Unlimited
foreach ($mb in $mailboxes) {
Get-MailboxPermission -Identity $mb.UserPrincipalName |
Where-Object { $_.User -notlike "NT AUTHORITY\*" -and $_.IsInherited -eq $false -and $_.AccessRights -match "FullAccess" } |
Select-Object Identity, User, AccessRights
}19. SendAs-Delegierung
Wer SendAs auf ein fremdes Postfach besitzt, verschickt Mails in dessen Namen, ein klassischer Hebel für internen CEO-Fraud. Diese Rechte stehen nicht im Mailbox-Permission-Objekt, sondern werden über Get-RecipientPermission gelesen. Damit schließt dieser Punkt die Lücke, die FullAccess allein offen lässt.
Connect-ExchangeOnline -ShowBanner:$false
foreach ($mb in (Get-Mailbox -ResultSize Unlimited)) {
Get-RecipientPermission -Identity $mb.UserPrincipalName |
Where-Object { $_.Trustee -notlike "NT AUTHORITY\*" -and $_.AccessRights -contains "SendAs" } |
Select-Object Identity, Trustee, AccessRights
}20. Verborgene Auto-Forwarding-Regeln auf Postfachebene
Nach einer Kontenübernahme richten Angreifer Weiterleitungen ein, eingehende Mails fließen unbemerkt an externe Adressen. Auf Postfachebene steckt das in der Eigenschaft ForwardingSmtpAddress. Das ist die eine Hälfte des Problems, die zweite liest der nächste Punkt aus.
Connect-ExchangeOnline -ShowBanner:$false
Get-Mailbox -ResultSize Unlimited |
Where-Object { $null -ne $_.ForwardingSmtpAddress } |
Select-Object UserPrincipalName, ForwardingSmtpAddress, DeliverToMailboxAndForward21. Posteingangsregeln mit externer Weiterleitung
Häufiger als die Mailbox-Weiterleitung läuft der stille Abfluss über Posteingangsregeln, die nicht im Mailbox-Objekt stehen. Du liest sie je Postfach über Get-InboxRule aus und prüfst die Aktionen ForwardTo, ForwardAsAttachmentTo und RedirectTo. Bei vielen Postfächern dauert dieser Lauf entsprechend, plane ihn außerhalb der Stoßzeiten.
Connect-ExchangeOnline -ShowBanner:$false
foreach ($mb in (Get-Mailbox -ResultSize Unlimited)) {
Get-InboxRule -Mailbox $mb.UserPrincipalName |
Where-Object { $_.ForwardTo -or $_.ForwardAsAttachmentTo -or $_.RedirectTo } |
Select-Object @{N="Mailbox";E={$mb.UserPrincipalName}}, Name, Enabled, ForwardTo, RedirectTo
}22. Outbound-Spam: Auto-Forwarding-Modus
Organisationsweit entscheidet die Outbound-Spam-Richtlinie, ob automatische externe Weiterleitung erlaubt ist. Der Wert On öffnet die Auto-Weiterleitung trotz einzelner Postfach-Regeln, während Automatic heute Off entspricht, weil Microsoft das für alle Kunden umgestellt hat. Steht eine Policy auf On, gehört das begründet oder zurückgestellt.
Connect-ExchangeOnline -ShowBanner:$false
Get-HostedOutboundSpamFilterPolicy | Select-Object Name, AutoForwardingMode # Befund, wenn "On"23. Automatische Weiterleitung an Remote-Domains
Über Remote Domains definieren Admins Ausnahmen für externe Weiterleitung. Eine Remote Domain mit AutoForwardEnabled = True ist ein genehmigtes Datenleck und gehört restriktiv dokumentiert. Jeder Treffer braucht eine geschäftliche Begründung.
Connect-ExchangeOnline -ShowBanner:$false
Get-RemoteDomain | Where-Object { $_.AutoForwardEnabled -eq $true } |
Select-Object DomainName, AutoForwardEnabled, AutoReplyEnabled | Format-Table24. Mail-Fluss-Regeln mit SCL-Bypass
Transportregeln überschreiben die Spam-Filter-Entscheidungen von Exchange Online Protection. Eine Regel, die den Spam Confidence Level für bestimmte Absender auf -1 setzt, umgeht alle Sicherheitsmechanismen, und sobald die Absender-Domain kompromittiert ist, landet Malware ungefiltert im Posteingang. Solche Whitelists gehören durch moderne Tenant-Allow/Block-Listen abgelöst.
Connect-ExchangeOnline -ShowBanner:$false
Get-TransportRule | Where-Object { $_.SetSCL -eq -1 } |
Select-Object Name, State, Description | Format-Table25. Legacy-Protokolle auf Postfachebene
Selbst wenn Conditional Access Legacy-Authentifizierung netzwerkweit blockiert, existieren POP3 und IMAP4 weiterhin auf den Postfächern, und ein fehlerhafter Ausschluss in einer CA-Policy legt sie sofort wieder offen. Tiefenverteidigung heißt hier: die Protokolle direkt am Postfach hart abschalten. Ein geschlossener Port lässt sich nicht angreifen.
Connect-ExchangeOnline -ShowBanner:$false
Get-CASMailbox -ResultSize Unlimited |
Where-Object { $_.PopEnabled -eq $true -or $_.ImapEnabled -eq $true } |
Select-Object DisplayName, PopEnabled, ImapEnabled | Format-Table26. Modern Authentication in Exchange Online
Basic Auth für die Legacy-Protokolle hat Microsoft bereits abgeschaltet, der organisationsweite Schalter für Modern Auth gehört trotzdem auf True, weil er die tokenbasierte Anmeldung für Outlook absichert. Liefert die Abfrage False, fehlt ein Baustein der modernen Authentifizierung.
Connect-ExchangeOnline -ShowBanner:$false
Get-OrganizationConfig | Select-Object OAuth2ClientProfileEnabled # Soll: True27. Mailbox-Auditing organisationsweit aktiv
Ohne Postfachüberwachung fehlt nach einem Vorfall die Spur, wer wann auf welche Mail zugegriffen hat. Mailbox-Auditing ist seit 2019 standardmäßig aktiv, lässt sich aber organisationsweit abschalten, und der globale Schalter AuditDisabled überschreibt jede Einstellung am einzelnen Postfach. False bedeutet aktiv, True ist ein Befund.
Connect-ExchangeOnline -ShowBanner:$false
Get-OrganizationConfig | Select-Object AuditDisabled # Befund, wenn True28. Connection Filter: IP Allow List
Eine IP Allow List im Connection Filter schleust ganze IP-Bereiche an der Spam-Prüfung vorbei. Gepflegt ist das legitim, eine vergessene oder zu breite Liste macht Mails aus diesen Bereichen ungeprüft zustellbar. Jeder Eintrag braucht eine aktuelle Begründung.
Connect-ExchangeOnline -ShowBanner:$false
Get-HostedConnectionFilterPolicy | Select-Object Name, IPAllowList, EnableSafeList | Format-List29. Externe E-Mails kennzeichnen
Eine sichtbare Markierung an Mails von außerhalb ist kein technischer Blocker, aber sie senkt die Erfolgsquote von Phishing und CEO-Fraud spürbar, weil der Nutzer den Kontext sofort sieht. Aktivieren lässt sich das External Tagging nur per PowerShell, im Exchange Admin Center gibt es keinen Schalter. Steht Enabled auf False, fehlt diese Awareness-Schicht.
Connect-ExchangeOnline -ShowBanner:$false
Get-ExternalInOutlook | Select-Object Identity, Enabled, AllowList # Befund, wenn Enabled = FalseVoraussetzungen & Authentifizierung
Diese Hinweise gelten für alle drei Teile der Serie. Die Fallstricke entscheiden, ob die Prüfpunkte überhaupt eine Verbindung bekommen, und sie liegen fast immer in der Umgebung, nicht im Code.
Der gemeinsame Nenner: Jedes der großen Module bringt eigene .NET-Assemblies mit, PowerShell lädt eine Assembly genau einmal pro Session und kann sie nicht wieder entladen. Treffen zwei Versionen derselben Bibliothek aufeinander, weil Submodule unterschiedlich aktuell sind oder weil zwei Module dieselbe DLL mitbringen, bricht das erste Cmdlet ab, das die andere Version braucht.
Die wichtigste Konsequenz vorweg: Ist eine Session einmal in diesem Zustand, hilft kein Reparaturbefehl, nur ein frisches Fenster. Du bereinigst den Modulstand und startest PowerShell neu.
Die Basis ist ein konsistenter Modulstand. Wichtig: Den Aufräum- und Installationsblock führst Du in einer frischen Session aus, in der noch kein Connect-MgGraph gelaufen ist. Ein geladenes Modul lässt sich nicht deinstallieren, Uninstall-Module quittiert das sonst mit "currently in use".
# In einer frischen Session, bevor ein Connect ein Modul laedt
# Altlasten entfernen (schliesst die alten Graph.Core-DLLs aus PnP-Altversionen ein)
Get-Module Microsoft.Graph* -ListAvailable | Uninstall-Module -AllVersions -Force -ErrorAction SilentlyContinue
Uninstall-Module PnP.PowerShell -AllVersions -Force -ErrorAction SilentlyContinue
# Konsistente Versionen installieren
Install-Module Microsoft.Graph -Scope CurrentUser -Force
Install-Module ExchangeOnlineManagement -Scope CurrentUser -Force # mindestens 3.7.2 wegen -DisableWAM
Install-Module MicrosoftTeams -Scope CurrentUser -Force
Install-Module PnP.PowerShell -Scope CurrentUser -Force
Install-Module Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser -Force
# Einmalig: eigene Entra-App fuer PnP registrieren, ClientId notieren
Register-PnPEntraIDAppForInteractiveLogin -ApplicationName "PhinIT-Audit" -Tenant "deintenant.onmicrosoft.com"Microsoft Graph: Versionskonflikt zwischen den Submodulen
Connect-MgGraph läuft durch, aber das erste Get-Mg*-Cmdlet meldet "Could not load file or assembly 'Microsoft.Graph.Authentication, Version=2.x.0.0' ... Assembly with same name is already loaded".
Die Ursache sind mehrere parallel installierte Versionen der Microsoft.Graph.*-Module: Connect-MgGraph lädt eine Version von Microsoft.Graph.Authentication, das Cmdlet aus Microsoft.Graph.Users erwartet eine andere, und die bereits geladene gewinnt.
Zuerst prüfst Du, ob wirklich mehrere Versionen liegen.
Get-Module Microsoft.Graph.Authentication -ListAvailable | Select-Object Name, Version
Mehr als eine Version ist der Befund. Die Bereinigung läuft in einem frischen Fenster, und zwar bevor ein Connect-MgGraph oder Get-Mg* die Assembly wieder lädt. Disconnect-MgGraph und Remove-Module entladen die DLL nicht, nur das Schließen der Konsole gibt sie frei. Deshalb: Fenster zu, neues Fenster auf, dort als Erstes deinstallieren. Das Meta-Modul allein zu entfernen reicht nicht, die Submodule bleiben sonst liegen, deshalb iterierst Du über alle.
Get-InstalledModule Microsoft.Graph* | ForEach-Object {
Uninstall-Module -Name $_.Name -AllVersions -Force -ErrorAction SilentlyContinue
}
Install-Module Microsoft.Graph -Scope CurrentUser -Force -AllowClobber
Wenn Du gerade nicht neu installieren willst, lädst Du in einer frischen Session die gewünschte Version vor dem Connect, dann gewinnt sie das Rennen. Das ist ein Pflaster, kein Ersatz für einen sauberen Modulstand.
Import-Module Microsoft.Graph.Authentication -RequiredVersion 2.35.0
Connect-MgGraph -Scopes "User.Read.All" -NoWelcomeMicrosoft Graph und PnP zusammen: geteilte Graph.Core-Assembly
Sobald Graph und PnP.PowerShell in derselben Session laufen, taucht "Could not load type AzureIdentityAccessTokenProvider" oder ein ähnlicher Microsoft.Graph.Core-Fehler auf. PnP bringt eine eigene, oft ältere Microsoft.Graph.Core.dll mit. Lädt sie zuerst, überschreibt sie die Version des Graph SDK, danach scheitern die Get-Mg*-Cmdlets. Die Lösung ist Trennung: Die Graph-Checks laufen in einer Session, die PnP- und SharePoint-Checks in einer zweiten. Wer beides in einem Sammelskript braucht, kapselt den PnP-Teil in einen eigenen Hintergrund-Job oder Runspace, damit er seine Assemblies nicht in die Hauptsession zieht.
Exchange Online: WAM-Broker und Modulversion
Beim Connect kann eine NullReferenceException im RuntimeBroker auftreten, oder -DisableWAM wird als "unsupported parameter" abgelehnt. Ab Modulversion 3.7.0 ist der Web Account Manager Standard, in Konsolen ohne Fensterkontext stört das, und den Schalter -DisableWAM gibt es erst ab 3.7.2. Du bringst das Modul auf mindestens 3.7.2, hängst -DisableWAM nur dann an und führst den Connect in einer frischen Session aus. Das v3-Modul ist REST-basiert und kollidiert kaum mit Graph, die Exchange-Checks legst Du deshalb problemlos zu den Graph-Checks in dieselbe Session.
SharePoint: zwei Module, zwei Laufzeiten
Das SPO-Modul Microsoft.Online.SharePoint.PowerShell ist auf .NET Framework gebaut und läuft nativ nur in Windows PowerShell 5.1. In PowerShell 7 startet es über die Kompatibilitätsschicht eine versteckte Windows-PowerShell-5.1-Hintergrundsession.
Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShellPnP.PowerShell dagegen verlangt PowerShell 7. Beide gehören deshalb nicht in dieselbe Session wie die Graph-Checks und idealerweise auch nicht zueinander. Dazu kommt die Authentifizierungs-Hürde: Connect-PnPOnline -Interactive braucht seit dem 09.09.2024 eine eigene Entra-App über -ClientId, weil Microsoft die Multi-Tenant-App von PnP abgeschaltet hat. Die Registrierung übernimmt einmalig Register-PnPEntraIDAppForInteractiveLogin, alternativ liest PnP die ClientId aus der Umgebungsvariable ENTRAID_APP_ID oder ENTRAID_CLIENT_ID.
Teams, Security & Compliance und die drei Grundregeln
Das Modul MicrosoftTeams ist vergleichsweise eigenständig und verträgt sich meist mit einer parallel laufenden Exchange-Session. Die Prüfungen für DLP, Aufbewahrung, Labels, Audit-Retention und Alert-Richtlinien aus Teil 3 laufen über Security & Compliance PowerShell, dafür öffnest Du mit Connect-IPPSSession eine eigene Sitzung, das Cmdlet bringt das ExchangeOnlineManagement-Modul mit. Drei Regeln halten den gesamten Audit konfliktfrei. Erstens, eine Aufgabe pro Session: Graph und Exchange zusammen, PnP und SPO getrennt davon. Zweitens, PowerShell 7 für Graph und PnP, Windows PowerShell 5.1 nur dort, wo das SPO-Modul es verlangt. Drittens, bei jedem Assembly-Fehler nicht in derselben Session weiterprobieren, sondern den Modulstand bereinigen und ein frisches Fenster öffnen. Geladene Assemblies bleiben bis zum Schließen der Konsole, jeder weitere Versuch läuft in denselben Fehler.
Fazit nach den ersten 30 Audits
Identität ist die erste und wichtigste Verteidigungslinie eines Microsoft 365 Tenants. Wer MFA-Methoden, Conditional Access, privilegierte Rollen und die Gast- und Postfach-Konfiguration als Rohdaten auswertet, sieht die Lücken, die ein Klick durch die Admin Center verdeckt. Die 29 Prüfpunkte dieses Teils decken die Angriffspfade ab, die in realen Tenant-Kompromittierungen am häufigsten ausgenutzt werden, von der schwachen SMS-Methode bis zur stillen Postfach-Weiterleitung.
Damit ist das Fundament geprüft, aber der Tenant ist mehr als Identität und Mail. In Teil 2 geht es um den E-Mail-Bedrohungsschutz mit SPF, DKIM und DMARC sowie Defender for Office 365, um die Freigabe-Einstellungen in SharePoint, OneDrive und Teams, um die Geräte-Compliance aus Intune und um die App-Berechtigungen, über die OAuth-Consent-Phishing läuft. Das sind die Prüfpunkte 30 bis 58.
Sei der Erste und starte die Diskussion mit einem hilfreichen Beitrag.
Kommentar hinterlassen
Dein Beitrag wird vor der Veröffentlichung kurz geprüft — fachlich, respektvoll und auf den Punkt ist hier genau richtig.