Sur un poste Azure AD Join ou Hybrid Join sans accès à l’AD local, whoami /groups
n’affiche pas les groupes Azure AD. Voici des méthodes éprouvées, avec scripts réutilisables, pour récupérer rapidement et précisément toutes les appartenances (directes et imbriquées) d’un utilisateur.
Obtenir la liste des groupes d’un utilisateur Azure AD
Problématique
Dans un environnement Active Directory « on‑prem », la commande whoami /groups
renvoie la liste complète des groupes (SID résolus) associés au jeton de l’utilisateur connecté. En revanche, lorsque le poste est uniquement attaché au cloud Azure AD (Azure AD Join, ou Hybrid Join sans ligne de vue vers le contrôleur de domaine), whoami /groups
ne remonte pas les groupes Azure AD : l’OS n’interroge pas Microsoft Graph pour compléter ce jeton. D’où la question : quel équivalent utiliser pour récupérer ces appartenances ?
Pourquoi whoami /groups
ne reflète pas Azure AD
- Jeton local Windows : il contient des SIDs issus de la machine et, le cas échéant, de l’AD DS. Les groupes Azure AD n’y sont pas nativement injectés.
- Group claims dans les tokens Azure : côté cloud, les groupes se propagent dans les access tokens/ID tokens (claims
groups
/roles
). Cette information n’est pas exposée parwhoami
. - Azure AD vs Azure AD DS : si vous utilisez Azure AD Domain Services (AAD DS), les groupes répliqués peuvent apparaître via des SIDs AD DS. Mais sur un simple Azure AD Join, ce n’est pas le cas.
Ce que proposait le fil d’origine
Dans le fil mentionné, aucune solution technique n’a été fournie ; l’utilisateur a été redirigé vers Microsoft Q&A. Ci‑dessous, vous trouverez des méthodes concrètes et immédiatement utilisables.
Méthodes recommandées pour récupérer les groupes Azure AD
Méthode | Outil / Module | Exemple de commande | Points clés |
---|---|---|---|
Portail Azure | Azure Portal | Azure Active Directory → Utilisateurs → [Nom d’utilisateur] → Groupes | Interface graphique. Rapide pour un cas ponctuel. |
PowerShell Microsoft Graph (recommandé) | Microsoft.Graph | Connect-MgGraph -Scopes "Directory.Read.All" Get-MgUser -UserId alice@contoso.com | Get-MgUserTransitiveMemberOf -All | Where-Object {$_.OdataType -eq "#microsoft.graph.group"} | Select-Object DisplayName, Id | Inclut l’appartenance transitive (groupes imbriqués). |
PowerShell AzureAD (hérité) | AzureAD | Connect-AzureAD Get-AzureADUser -ObjectId alice@contoso.com | Get-AzureADUserMembership | Module déprécié mais encore utilisable. |
Azure CLI | az | az ad user get-member-groups \ --id alice@contoso.com \ --security-enabled-only \ --output table | Idéal en environnement multi‑plateformes & CI/CD. |
Microsoft Graph API (REST) | HTTPS | GET /v1.0/users/{user-id}/transitiveMemberOf/microsoft.graph.group?$select=displayName,id,securityEnabled,groupTypes | Intégration directe dans vos applis et outils. |
Prérequis & autorisations
- Rôle : au minimum Directory Reader (ou équivalent en privilèges).
- Scopes (délégués) : souvent
Directory.Read.All
est le plus simple. Selon vos besoins, une combinaisonUser.Read.All
+Group.Read.All
peut suffire. - App‑only (application) :
Application.Read.All
/Group.Read.All
en permissions applicatives, avec consentement administrateur.
Étape par étape : PowerShell Microsoft Graph (option privilégiée)
Installation & connexion
# 1) Installer le SDK Microsoft Graph (une fois)
Install-Module Microsoft.Graph -Scope CurrentUser -Repository PSGallery
# 2) Se connecter avec les scopes nécessaires
Connect-MgGraph -Scopes "Directory.Read.All"
Select-MgProfile -Name "v1.0" # Profil stable
Vérifiez votre contexte courant :
Get-MgContext | Format-List
Lister les groupes d’un utilisateur donné
$upn = "alice@contoso.com"
# Récupère l'utilisateur puis ses appartenances transitives
$user = Get-MgUser -UserId $upn -Property Id,UserPrincipalName,DisplayName
$groups = Get-MgUserTransitiveMemberOf -UserId $user.Id -All |
Where-Object {$*.OdataType -eq "#microsoft.graph.group"} |
Select-Object @{
Name="UserUPN"; Expression={$user.UserPrincipalName}
}, @{
Name="GroupName"; Expression={$*.AdditionalProperties.displayName}
}, @{
Name="GroupId"; Expression={$*.Id}
}, @{
Name="Security"; Expression={$*.AdditionalProperties.securityEnabled}
}, @{
Name="GroupTypes"; Expression={$_.AdditionalProperties.groupTypes -join ","}
}
$groups | Sort-Object GroupName | Format-Table -AutoSize
Astuce : pour filtrer par type :
- Groupes Microsoft 365 (Unified) :
Where-Object { $_.GroupTypes -match "Unified" }
- Groupes de sécurité :
Where-Object { $_.Security -eq $true }
Version « boîte à outils » (fonction réutilisable)
function Get-AadUserGroups {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$UserPrincipalName,
[switch]$Transitive = $true
)
```
$u = Get-MgUser -UserId $UserPrincipalName -Property Id,UserPrincipalName,DisplayName -ErrorAction Stop
$cmd = if ($Transitive) { 'Get-MgUserTransitiveMemberOf' } else { 'Get-MgUserMemberOf' }
& $cmd -UserId $u.Id -All -ErrorAction Stop |
Where-Object { $_.OdataType -eq "#microsoft.graph.group" } |
Select-Object @{
N='UserUPN'; E={$u.UserPrincipalName}
}, @{
N='DisplayName'; E={$_.AdditionalProperties.displayName}
}, @{
N='Id'; E={$_.Id}
}, @{
N='SecurityEnabled'; E={$_.AdditionalProperties.securityEnabled}
}, @{
N='GroupTypes'; E={$_.AdditionalProperties.groupTypes -join ","}
}
```
}
Utilisation :
Get-AadUserGroups -UserPrincipalName "alice@contoso.com" | Out-GridView
Exporter pour un audit massif
$output = "GroupsByUser.csv"
Remove-Item $output -ErrorAction SilentlyContinue
$allUsers = Get-MgUser -All -Property Id,UserPrincipalName
foreach ($u in $allUsers) {
Write-Host "Traitement $($u.UserPrincipalName)..." -ForegroundColor Cyan
Get-MgUserTransitiveMemberOf -UserId $u.Id -All |
Where-Object { $*.OdataType -eq "#microsoft.graph.group" } |
Select-Object @{N='UserUPN';E={$u.UserPrincipalName}},
@{N='GroupName';E={$*.AdditionalProperties.displayName}},
@{N='GroupId';E={$_.Id}} |
Export-Csv -Path $output -Append -NoTypeInformation -Encoding UTF8
}
Write-Host "Export terminé → $output" -ForegroundColor Green
Bonnes pratiques Graph PowerShell
- Utilisez
-All
pour paginer automatiquement. - Gérez les erreurs et éventuels throttlings (Try/Catch, backoff exponentiel).
- Limiter les champs avec
-Property
/$select
pour améliorer les performances.
Alternative (héritée) : module AzureAD
Bien que déprécié, il reste présent dans de nombreux environnements.
Install-Module AzureAD -Scope CurrentUser
Connect-AzureAD
Get-AzureADUser -ObjectId "[alice@contoso.com](mailto:alice@contoso.com)" |
Get-AzureADUserMembership |
Where-Object { $_.ObjectType -eq "Group" } |
Select-Object DisplayName, ObjectId
Limites : surface API plus restreinte, évolution stoppée, et compatibilité future non garantie. Privilégiez le SDK Microsoft Graph.
Azure CLI : listing scriptable multi‑plateformes
# Connexion (interactif, device code possible)
az login
# Lister les groupes (GUID)
az ad user get-member-groups
--id [alice@contoso.com](mailto:alice@contoso.com)
--security-enabled-only
--output tsv
La commande ci‑dessus renvoie des IDs de groupes. Pour obtenir les noms :
az ad user get-member-groups --id alice@contoso.com --security-enabled-only -o tsv \
| while read gid; do
name=$(az ad group show --id "$gid" --query displayName -o tsv)
echo -e "$name\t$gid"
done
Astuce : supprimez --security-enabled-only
pour inclure aussi les groupes Microsoft 365 (Unified).
Microsoft Graph (REST) : pour l’intégration applicative
Endpoint recommandé
GET https://graph.microsoft.com/v1.0/users/{user-id}/transitiveMemberOf/microsoft.graph.group?$select=id,displayName,securityEnabled,groupTypes
Le cast /microsoft.graph.group
filtre nativement les objets d’annuaire non pertinents (ex. roles, unités d’administration).
Exemple de réponse (tronquée)
{
"value": [
{
"id": "1f3508c8-1c3a-4f3a-9b9d-8c1a0a2f0a11",
"displayName": "Sec-App-ERP-Readers",
"securityEnabled": true,
"groupTypes": []
},
{
"id": "8a8b7b42-95e2-4c21-87fa-50a6307f5f6b",
"displayName": "Marketing (M365)",
"securityEnabled": false,
"groupTypes": ["Unified"]
}
]
}
Permissions minimales (rappels)
- Déléguées :
Directory.Read.All
(ou combinaison équivalente couvrant utilisateurs et groupes). - Applicatives :
Group.Read.All
(app‑only) + consentement admin.
Cas du poste Azure AD Join : récupérer les groupes de l’utilisateur connecté
Pour l’utilisateur courant, vous pouvez éviter de fournir un UPN explicite :
# Après Connect-MgGraph
$me = (Get-MgContext).Account
Get-MgUser -UserId $me |
Get-MgUserTransitiveMemberOf -All |
Where-Object {$_.OdataType -eq "#microsoft.graph.group"} |
Select-Object @{N='UserUPN';E={$me}},
@{N='GroupName';E={$_.AdditionalProperties.displayName}},
Id
Diagnostic d’appartenance du poste :
dsregcmd /status
Vous verrez notamment AzureAdJoined : YES
si la machine est bien jointe à Azure AD.
Séparer les groupes de sécurité des groupes Microsoft 365
Dans Microsoft Graph, deux champs aident à classifier :
securityEnabled
:true
pour un groupe de sécurité.groupTypes
: contientUnified
pour un groupe Microsoft 365.
Exemple :
$groups = Get-AadUserGroups -UserPrincipalName "alice@contoso.com"
$securityOnly = $groups | Where-Object { $*.SecurityEnabled -eq $true }
$m365Only = $groups | Where-Object { $*.GroupTypes -match "Unified" }
"Groupes de sécurité : $($securityOnly.Count)"
"Groupes Microsoft 365 : $($m365Only.Count)"
Automatiser sans interaction (identité applicative)
- Créer une application (inscription) et lui attribuer un certificat (recommandé) ou un secret.
- Accorder les permissions applicatives (ex.
Group.Read.All
) puis réaliser le consentement administrateur. - Script :
$tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$appId = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
$thumb = "AA BB CC DD EE FF 11 22 33 44 55 66 77 88 99 00"
Connect-MgGraph -TenantId $tenantId -ClientId $appId -CertificateThumbprint $thumb
Get-MgUserTransitiveMemberOf -UserId "[alice@contoso.com](mailto:alice@contoso.com)" -All |
Where-Object {$*.OdataType -eq "#microsoft.graph.group"} |
Select-Object Id, @{N='DisplayName';E={$*.AdditionalProperties.displayName}}
Important : en app‑only, l’API n’agit pas « au nom d’un utilisateur », mais en tant qu’application. Veillez à limiter la portée (principe du moindre privilège) et à contrôler l’accès aux exports générés.
Erreurs fréquentes & résolutions
Symptôme | Cause probable | Correction |
---|---|---|
Insufficient privileges to complete the operation | Scopes ou rôles insuffisants | Ajouter Directory.Read.All (délégué) ou Group.Read.All (app‑only) et redemander le consentement |
Résultats incomplets | Pagination non gérée | Ajouter -All (SDK) ou itérer @odata.nextLink (REST) |
Groupes en double | Combinaison de membre direct + imbriqué | Dédupliquer sur Id (Select-Object -Unique Id ) |
Nom de groupe manquant en CLI | az ad user get-member-groups renvoie des IDs | Enchaîner avec az ad group show --id <guid> pour résoudre le nom |
Timeouts / throttling | Quota Graph franchi | Implémenter des backoffs, réduire le $select , parallélisme raisonnable |
Comparatif rapide des approches
Approche | Transitive | Multi‑OS | Automatisation | Simplicité | Cas d’usage type |
---|---|---|---|---|---|
Portail Azure | Oui | — | Faible | Très simple | Vérification ponctuelle |
PowerShell Microsoft Graph | Oui | Windows/Linux/macOS (PowerShell 7) | Élevée | Moyenne | Audit, remédiation, reporting |
Azure CLI | Oui | Oui | Élevée | Moyenne | DevOps, CI/CD multi‑plateformes |
Microsoft Graph (REST) | Oui | Oui | Très élevée | Technique | Intégration applicative |
Module AzureAD (hérité) | Partiel | Windows | Moyenne | Simple | Environnements existants |
Aller plus loin : cas particuliers & conseils
- Groupes imbriqués : préférez toujours la vue « transitive ».
Get-MgUserTransitiveMemberOf
agrège les appartenances indirectes (groupe A membre de B, etc.). - Rôles Azure AD : les rôles (ex. Global Reader) sont des directory roles, pas des groupes. D’où l’intérêt du cast
/microsoft.graph.group
. - Confidentialité : limitez les exports à ce qui est nécessaire (principe du moindre privilège) et sécurisez les fichiers générés.
- Performance : quand vous bouclez sur des milliers d’utilisateurs, récupérez d’abord tous les
Id
/UserPrincipalName
, puis parallélisez avec un throttle maîtrisé. - Terminologie : Azure AD est désormais appelé Microsoft Entra ID. Les commandes et APIs restent identiques côté Graph.
Exemples pratiques prêts à l’emploi
Exporter les groupes (sécurité vs Microsoft 365) pour tous les utilisateurs
Connect-MgGraph -Scopes "Directory.Read.All"
Select-MgProfile v1.0
$output = "GroupsByUser-typed.csv"
Remove-Item $output -ErrorAction SilentlyContinue
$users = Get-MgUser -All -Property Id,UserPrincipalName
foreach ($u in $users) {
$groups = Get-MgUserTransitiveMemberOf -UserId $u.Id -All |
Where-Object { $_.OdataType -eq "#microsoft.graph.group" }
foreach ($g in $groups) {
$name = $g.AdditionalProperties.displayName
$id = $g.Id
$isSec = [bool]$g.AdditionalProperties.securityEnabled
$types = ($g.AdditionalProperties.groupTypes) -join ","
$kind = if ($types -match "Unified") { "M365" } elseif ($isSec) { "Security" } else { "Other" }
```
[pscustomobject]@{
UserUPN = $u.UserPrincipalName
GroupName = $name
GroupId = $id
Category = $kind
} | Export-Csv $output -Append -NoTypeInformation -Encoding UTF8
```
}
}
Write-Host "Export → $output" -ForegroundColor Green
Afficher uniquement les groupes liés à une appli (pattern)
$pattern = "ERP"
Get-AadUserGroups -UserPrincipalName "alice@contoso.com" |
Where-Object { $_.DisplayName -like "*$pattern*" } |
Sort-Object DisplayName |
Format-Table DisplayName, GroupId -AutoSize
FAQ courte
Q : Puis‑je obtenir l’équivalent exact de whoami /groups
sur un Azure AD Join ?
R : Non. whoami
interroge le jeton local Windows. Utilisez Microsoft Graph (PowerShell/CLI/REST) pour une vision fiable côté Azure.
Q : La vue « transitive » est‑elle toujours préférable ?
R : Oui pour l’audit/contrôles d’accès, car elle inclut les appartenances via des groupes imbriqués. Pour des scénarios strictement « directs », utilisez Get-MgUserMemberOf
.
Q : Quels droits minimums accorder à un analyste ?
R : Le rôle Directory Reader et le scope Directory.Read.All
(ou équivalents ciblés) suffisent dans la majorité des cas de lecture.
Conclusion
Même si whoami /groups
ne reflète rien d’utile dans un contexte Azure AD pur, vous avez à votre disposition plusieurs méthodes entièrement supportées pour lister les groupes d’un utilisateur : Portail Azure (cas ponctuels), PowerShell Microsoft Graph (préféré pour l’IT), Azure CLI (DevOps multi‑plateformes) et Graph REST (intégration applicative). En combinant l’appartenance transitive, un filtrage par type et un export CSV, vous disposerez d’un inventaire exploitable pour les audits et la remédiation.
Cheat‑sheet (récapitulatif)
# PowerShell (SDK Graph) – utilisateur unique (transitif)
Connect-MgGraph -Scopes "Directory.Read.All"
Get-MgUser -UserId alice@contoso.com |
Get-MgUserTransitiveMemberOf -All |
Where-Object {$_.OdataType -eq "#microsoft.graph.group"} |
Select-Object DisplayName, Id
# Azure CLI – IDs des groupes de sécurité
az ad user get-member-groups --id [alice@contoso.com](mailto:alice@contoso.com) --security-enabled-only -o table
# REST – uniquement des objets de type groupe
GET /v1.0/users/{user-id}/transitiveMemberOf/microsoft.graph.group?$select=id,displayName,securityEnabled,groupTypes
Choisissez la méthode la mieux adaptée à votre flux de travail (GUI, script IT, pipeline DevOps, ou code).