Quinze vérifications ciblées, avec des résultats à interpréter
Un compte trop privilégié, un consentement OAuth oublié ou un transfert externe peut rester invisible dans une revue rapide du portail. PowerShell aide à rendre ces configurations lisibles et à conserver une preuve reproductible.
Les 15 contrôles suivants lisent la configuration. Les commandes de préparation, de connexion et de fermeture sont séparées du décompte. Il ne s’agit pas d’un audit complet automatisé : absence de résultat, accès refusé et contrôle réellement réussi doivent rester trois états distincts.
Les exemples ciblent Microsoft Graph v1.0 et Exchange Online, avec des identifiants fictifs. Aucun contrôle ne retire de licence, ne révoque un consentement et ne change une stratégie.
Préparer les modules et une session autorisée
Utilisez une version prise en charge de PowerShell et des modules Microsoft.Graph.Authentication, Identity.Governance, Identity.SignIns, Applications et ExchangeOnlineManagement. Pour les versions EXO 3.5.0 à 3.9.2 sous PowerShell 7, Microsoft documente PowerShell 7.4.x; confirmez la matrice de votre version plutôt que d’installer aveuglément la dernière combinaison.
Installez ou mettez à jour les modules dans votre procédure de changement, pas au milieu d’une collecte. Consignez leurs versions. Les cmdlets Graph ci-dessous utilisent les modules stables, sans préfixe Beta. Adaptez aussi l’environnement de connexion si vous utilisez un cloud national.
Connectez-vous avec une identité nominative protégée par MFA. Un consentement de portée Graph peut créer une autorisation persistante : utilisez une application de collecte approuvée et faites autoriser uniquement les permissions nécessaires. ContextScope Process limite le contexte local de connexion; il ne révoque pas les consentements du locataire.
L’exemple de connexion ci-dessous suffit aux contrôles 4 et 5 seulement. Pour les autres blocs, demandez la portée indiquée dans le tableau. Une permission OAuth ne remplace pas le rôle Entra ou le RBAC Exchange du compte.
# Preparation, outside the 15 checks. Use approved installed versions.
$ErrorActionPreference = 'Stop'
Get-Module -ListAvailable Microsoft.Graph*,ExchangeOnlineManagement |
Select-Object Name,Version
# Example for checks 4 and 5 only: request scopes by diagnostic block.
Connect-MgGraph -TenantId '00000000-0000-0000-0000-000000000000' -Scopes 'Policy.Read.All' -ContextScope Process
Get-MgContext | Select-Object TenantId,Account,Scopes
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
# All addresses and IDs in this guide are fictional.Permissions : choisir le bloc utile
Les portées sont présentées par opération. Si une session approuvée possède déjà une portée plus large en lecture, ne rajoutez pas des permissions d’écriture. Le rôle Global Reader peut servir à plusieurs lectures Entra, mais n’est pas une solution universelle pour Exchange. Le contrôle 12 présente une exception importante.
Pour Exchange, faites identifier les entrées de rôle et les paramètres nécessaires par l’administrateur RBAC, puis déléguez la portée utile. Une commande absente ou une erreur 403 doit être notée « non évalué », jamais « conforme ».
| Contrôles | Portée Graph minimale pour l’opération | Autre condition |
|---|---|---|
| 1–2 | RoleManagement.Read.Directory | Rôle de lecture Entra pris en charge |
| 3 | RoleEligibilitySchedule.Read.Directory | Rôle pris en charge; PIM et licences applicables |
| 4–5 | Policy.Read.All | Rôle pris en charge pour lire les stratégies |
| 6 | Policy.Read.AuthenticationMethod | Par exemple Global Reader selon l’API |
| 7 et 9 | Application.Read.All | Lecture des principaux de service |
| 8 | Directory.Read.All | Lecture du répertoire étendue, à justifier |
| 10–15 | — | RBAC Exchange, cmdlets et portée de destinataires |
1. Nommer les rôles avant de compter les administrateurs
Permission de collecte : RoleManagement.Read.Directory.
Conservez cette table pour résoudre RoleDefinitionId à l’étape 2. Un rôle défini n’est pas nécessairement attribué; examinez aussi les rôles personnalisés.
$roles = @(Get-MgRoleManagementDirectoryRoleDefinition -All -ErrorAction Stop)
$roles | Select-Object Id,DisplayName,IsBuiltIn,IsEnabled2. Lister les attributions de rôles actives
Permission de collecte : RoleManagement.Read.Directory.
Reliez les identifiants aux rôles du contrôle 1 et aux principaux dans Entra. Un principal peut être un utilisateur, un groupe ou une application. Développez les groupes attribuables aux rôles avant de compter les personnes. Cette liste ne couvre pas les éligibilités non activées.
Get-MgRoleManagementDirectoryRoleAssignment -All -ErrorAction Stop |
Select-Object Id,PrincipalId,RoleDefinitionId,DirectoryScopeId,AppScopeId3. Relever les éligibilités PIM séparément
Permission de collecte : RoleEligibilitySchedule.Read.Directory.
Une éligibilité n’est pas une activation. Comparez durée, portée et besoin du propriétaire. PIM exige les licences Entra ID P2 ou ID Governance appropriées. Un accès refusé ne signifie pas qu’il n’y a aucune éligibilité.
Get-MgRoleManagementDirectoryRoleEligibilityScheduleInstance -All -ErrorAction Stop |
Select-Object Id,PrincipalId,RoleDefinitionId,DirectoryScopeId,StartDateTime,EndDateTime4. Lire les stratégies Conditional Access
Permission de collecte : Policy.Read.All.
Inspectez exclusions, ressources, plateformes et contrôles. Report-only observe sans appliquer les décisions de cette stratégie. Un nom « MFA partout » ne prouve aucune couverture. Conditional Access exige Entra ID P1; les conditions de risque exigent P2. Validez ensuite avec What If et journaux.
Get-MgIdentityConditionalAccessPolicy -All -ErrorAction Stop |
Select-Object Id,DisplayName,State,Conditions,GrantControls,SessionControls |
ConvertTo-Json -Depth 205. Vérifier les paramètres de sécurité par défaut
Permission de collecte : Policy.Read.All.
IsEnabled décrit ce mécanisme, pas la sécurité globale. False peut être cohérent avec une architecture Conditional Access. True ne prouve pas qu’une connexion précise a été protégée. Les paramètres de sécurité par défaut sont disponibles avec Entra ID Free.
Get-MgPolicyIdentitySecurityDefaultEnforcementPolicy -ErrorAction Stop |
Select-Object Id,DisplayName,IsEnabled6. Inspecter la stratégie des méthodes d’authentification
Permission de collecte : Policy.Read.AuthenticationMethod.
Examinez méthodes activées, groupes inclus et exclusions. Une méthode autorisée ne signifie pas que les utilisateurs l’ont enregistrée, ni qu’une force d’authentification l’impose. Complétez avec les rapports d’inscription et les stratégies applicables.
Get-MgPolicyAuthenticationMethodPolicy -ExpandProperty AuthenticationMethodConfigurations -ErrorAction Stop |
ConvertTo-Json -Depth 207. Inventorier les applications d’entreprise
Permission de collecte : Application.Read.All.
Ce sont des principaux de service du locataire, pas uniquement les inscriptions d’applications dont vous êtes propriétaire. Conservez $apps pour le contrôle 9. Un nom familier ou une application désactivée ne remplace pas la vérification des permissions et du propriétaire.
$apps = @(Get-MgServicePrincipal -All -Property Id,AppId,DisplayName,AccountEnabled,AppRoles -ErrorAction Stop)
$apps | Select-Object Id,AppId,DisplayName,AccountEnabled8. Lire les consentements délégués OAuth
Permission de collecte : Directory.Read.All.
Scope contient des permissions déléguées. ClientId et ResourceId sont ici des identifiants d’objets servicePrincipal, pas l’AppId public. AllPrincipals désigne un consentement pour tous; Principal désigne un utilisateur. Vérifiez justification et besoin avant toute révocation.
Get-MgOauth2PermissionGrant -All -ErrorAction Stop |
Select-Object Id,ClientId,ResourceId,ConsentType,PrincipalId,Scope9. Lire les permissions applicatives d’une application pilote
Permission de collecte : Application.Read.All.
Ces attributions sont distinctes des consentements délégués. Elles peuvent permettre un accès sans utilisateur connecté. Si Permission est vide, conservez l’identifiant et résolvez-le dans l’API cible; ne concluez pas à une absence de droit. Le script couvre une seule application choisie.
# Use check 7 to select the exact service principal OBJECT ID.
$clientObjectId = '11111111-1111-1111-1111-111111111111'
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $clientObjectId -All -ErrorAction Stop |
ForEach-Object {
$grant = $_
$resource = $apps | Where-Object Id -eq $grant.ResourceId
$role = $resource.AppRoles | Where-Object Id -eq $grant.AppRoleId
[pscustomobject]@{
ClientObjectId=$clientObjectId; ResourceId=$grant.ResourceId
Resource=$resource.DisplayName; AppRoleId=$grant.AppRoleId
Permission=$role.Value
}
}10. Lire l’état d’audit de l’organisation Exchange
Permission de collecte : Exchange RBAC.
AuditDisabled doit se lire dans le bon sens : True désactive l’audit de boîte au niveau organisationnel. False ne garantit ni les événements attendus, ni leur rétention, ni l’absence d’exclusions. Confirmez la recherche d’un événement test et les licences Purview pertinentes.
Get-OrganizationConfig -ErrorAction Stop |
Select-Object Name,AuditDisabled11. Rechercher les transferts configurés sur les boîtes
Permission de collecte : Exchange RBAC.
Une destination d’annuaire peut être un contact à adresse externe : résolvez-la avant de classer le transfert. Cette collecte ne voit pas les règles de boîte ou de transport. Elle identifie une configuration, pas une exfiltration prouvée.
Get-EXOMailbox -ResultSize Unlimited -Properties ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward -ErrorAction Stop |
Where-Object { $_.ForwardingAddress -or $_.ForwardingSmtpAddress } |
Select-Object DisplayName,PrimarySmtpAddress,ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward12. Examiner les règles d’une boîte pilote, y compris cachées
Permission de collecte : Exchange RBAC spécifique.
Microsoft indique que cette cmdlet ne fonctionne pas avec View-Only Organization Management ni avec le rôle Entra Global Reader. Faites déléguer les entrées Get-InboxRule et la portée de destinataires nécessaires; n’accordez pas un rôle global d’écriture pour contourner cette limite. Préservez les détails complets des règles suspectes avant remédiation.
Get-InboxRule -Mailbox 'alex@contoso.com' -IncludeHidden -ResultSize Unlimited -ErrorAction Stop |
Select-Object Identity,Name,Enabled,Priority,ForwardTo,RedirectTo,ForwardAsAttachmentTo,DeleteMessage,StopProcessingRules13. Lire les politiques de transfert sortant
Permission de collecte : Exchange RBAC.
La présence d’une politique restrictive ne prouve pas qu’elle cible tous les destinataires. Vérifiez séparément les règles d’affectation, priorités et exceptions. Comparez AutoForwardingMode à la documentation du service; évitez de supposer que Automatic signifie autorisé.
Get-HostedOutboundSpamFilterPolicy -ErrorAction Stop |
Select-Object Name,IsDefault,AutoForwardingMode14. Lire le paramètre SMTP AUTH du locataire
Permission de collecte : Exchange RBAC.
True décrit la désactivation au niveau organisationnel. Les paramètres de boîte, les stratégies d’authentification et les contrôles Entra peuvent modifier le résultat effectif. SMTP AUTH et Basic Authentication ne sont pas synonymes : ce booléen ne prouve pas l’usage d’OAuth ni l’absence de connexions héritées.
Get-TransportConfig -ErrorAction Stop |
Select-Object SmtpClientAuthenticationDisabled15. Repérer les règles de transport à examiner
Permission de collecte : Exchange RBAC.
Examinez redirections, copies cachées, exceptions et réglages antispam inhabituels. Une règle de test n’agit pas comme une règle appliquée. L’extrait n’expose pas toutes les actions : ouvrez le détail complet de toute règle retenue et validez avec son propriétaire.
Get-TransportRule -ResultSize Unlimited -ErrorAction Stop |
Sort-Object Priority |
Select-Object Identity,Name,State,Mode,Priority,Description,RedirectMessageTo,BlindCopyTo,SetSCLConserver des preuves sans transformer une revue en balayage aveugle
Commencez par une application et une boîte pilote. Les contrôles Graph utilisent -All pour parcourir les pages; les commandes Exchange utilisent ResultSize Unlimited lorsque pertinent. Cela ne supprime ni restrictions de portée ni limitation de débit. Évitez la parallélisation massive; conservez les erreurs et les nouvelles tentatives dans le dossier de collecte.
Notez locataire, compte collecteur, date et heure UTC, version des modules, commande et périmètre. Les tableaux Format-Table ne doivent pas servir de source d’export; conservez les objets avant formatage. Utilisez JSON à profondeur adaptée ou CliXML pour les valeurs imbriquées; un CSV peut aplatir ou perdre les groupes, conditions et actions.
Les résultats contiennent adresses, identifiants et détails sensibles de sécurité. Définissez emplacement, accès et rétention. Un instantané décrit un état à un moment donné; il ne montre pas à lui seul l’historique des changements ou l’utilisation réelle des permissions.
Passer des constats aux changements, avec validation et retour arrière
Classez les résultats selon exposition et impact : rôle administratif injustifié, accès applicatif très large ou transfert externe inconnu méritent une validation rapide. Associez chaque constat à un propriétaire et à une preuve; ne révoquez pas une application simplement parce que son nom est inconnu.
Les changements restent un travail distinct : export de l’état initial, confirmation du besoin métier, périmètre pilote, tests, fenêtre et procédure de retour arrière. Pour Conditional Access, passez par Report-only et les comptes d’urgence; pour Exchange, validez les flux légitimes. Une suppression de consentement ou d’attribution peut nécessiter un nouvel accord pour être restaurée.
Après remédiation, relancez le contrôle ciblé et un test fonctionnel. Déconnectez les sessions de collecte. Disconnect-MgGraph ferme la session locale, sans supprimer les autorisations accordées à l’application. Faites réviser les consentements de collecte devenus inutiles.
Ce point de départ peut préparer un audit de sécurité Microsoft 365 et Entra ID. L’analyse professionnelle relie les résultats aux journaux, aux dépendances, aux licences et aux risques réels; elle ne se résume pas à quinze sorties PowerShell.
Disconnect-MgGraph
Disconnect-ExchangeOnline -Confirm:$false