Quickly list all Groups and Teams a user is member of in Microsoft 365

In one of my most popular articles, I discussed several tips and tricks on how to quickly fetch group membership for a given user. As the article was written almost 5 years ago, some of the examples therein are now outdated, and some might even stop working due to upcoming deprecations. So in this article, I will provide you with updated examples, using the latest and greatest available methods at the time of writing.

The Exchange Online cmdlets remain the easiest method to fetch group membership across any and all group types supported by Exchange. Thanks to the use of server-side filtering, the output is trimmed down to just the objects we care about, and is usually fast enough to warrant the use of the “old-style” Get-Recipient cmdlet:

Get-Recipient -Filter "Members -eq 'CN=user,OU=tenant.onmicrosoft.com,OU=Microsoft Exchange Hosted Organizations,DC=EURPR03A001,DC=prod,DC=outlook,DC=com'"

where you need to provide the DistinguishedName value for the user you want to fetch groups for. An easier example combines the output of the Get-Mailbox cmdlet to fetch the DN value first, and then uses it for the server-side filter:

$dn = (Get-Mailbox user@domain.com).DistinguishedName

Get-Recipient -Filter "Members -eq '$dn'"

And just in case you have some immensely overcrowded environment, here’s how you can perform the same action by leveraging the REST-based Exchange Online cmdlets, part of the V2 module:

Get-EXORecipient -Filter "Members -eq 'CN=user,OU=domain.onmicrosoft.com,OU=Microsoft Exchange Hosted Organizations,DC=EURPR03A001,DC=prod,DC=outlook,DC=com'"

or by fetching the DN first:

$dn = (Get-EXOMailbox user@domain.com).DistinguishedName

Get-EXORecipient -Filter "Members -eq '$dn'"

We no longer need to use the –RecipientTypeDetails parameter to specifically request Office 365/Microsoft 365 Groups, as those are now included in the output by default. Thus the cmdlets above will cover all Distribution groups, Mail-enabled security groups and Microsoft 365 Groups the user is member of. No Azure AD security groups are included though!

To cover any Dynamic distribution groups, which are not included in any of the above examples, we can leverage the recently introduced Get-DynamicDistributionGroupMember cmdlet. Unfortunately, the cmdlet does not support server-side filters, so we need to do things the stupid way. The example below should return any Dynamic distribution groups a given user is a member of:

$dn = (Get-Mailbox user@domain.com).DistinguishedName

Get-DynamicDistributionGroup | ? {(Get-DynamicDistributionGroupMember -Identity $_.PrimarySMTPAddress | ? {$_.DistinguishedName -eq $dn})}

In the old article, we also covered some examples on how to perform similar operations via the Azure AD PowerShell module. As said module is going to be deprecated soon, we can instead use the Microsoft Graph SDK (PowerShell module), or if you prefer, call the Graph API endpoints it leverages directly. Here are few examples on that.

First, to query all group objects a given user is a member of, we can use the /memberOf endpoint. Since the output will also include admin roles the user has been assigned to, we can further narrow it down by adding an additional filter. Lastly, we can also request the count of objects to be added to the output, although this will also require a special header to be added to the request (“consistencyLevel”=”eventual”):

GET https://graph.microsoft.com/beta/users/user@domain.com/memberOf

GET https://graph.microsoft.com/beta/users/user@domain.com/memberOf/microsoft.graph.group

GET https://graph.microsoft.com/beta/users/user@domain.com/memberOf/microsoft.graph.group?$count=true

To perform the same queries via the Microsoft Graph SDK, use the following cmdlets:

Get-MgUserMemberOf -UserId user@domain.com

Get-MgUserMemberOf -UserId user@domain.com | ? {$_.AdditionalProperties['@odata.type'] -ne '#microsoft.graph.directoryRole'}

You will of course notice that the output of the MG PowerShell cmdlets is not as easy to work as the one from the Exchange cmdlets we used above, but that’s what we get with auto-generated modules…

The Graph API, and to an extent the MG PowerShell cmdlets also allow us to query “transitive” group membership, as detailed for example here. This in turn allows us to easily include any “nested” groups a given user is a member of in the output. Or to put it another way, we can “flatten” the membership list. Here are some examples:

GET https://graph.microsoft.com/beta/users/user@domain.com/transitivememberOf

GET https://graph.microsoft.com/beta/users/user@domain.com/transitivememberOf/microsoft.graph.group

GET https://graph.microsoft.com/beta/users/user@domain.com/transitivememberOf/microsoft.graph.group?$count=true

And the same via the Microsoft Graph SDK:

Get-MgUserTransitiveMemberOf -UserId user@domain.com

Get-MgUserTransitiveMemberOf -UserId user@domain.com | ? {$_.AdditionalProperties['@odata.type'] -ne '#microsoft.graph.directoryRole'} 

Last, let’s also examine some methods to directly fetch a list of all Teams a given user is a member of. The methods outlined above all include this data, so technically we can filter the output to just Teams object, but that’s not always a straightforward task. Instead, we can leverage the unified Group cmdlets, Get-UnifiedGroup and Get-UnifiedGroupLinks:

Get-UnifiedGroup -Filter {ResourceProvisioningOptions -eq "Team"} | ? {(Get-UnifiedGroupLinks $_.Guid.Guid -LinkType member | ? {$_.PrimarySmtpAddress -eq "user@domain.com"})}

Here’s how to do the same via the MicrosoftTeams module:

Get-Team | ? {Get-TeamUser -GroupId $_.GroupId | ? {$_.User -eq "user@domain.com"}}

The Graph API allows us to use the /joinedTeams endpoint:

GET https://graph.microsoft.com/beta/users/user@domain.com/joinedTeams

Finally, via the Get-MgUserJoinedTeam cmdlet:

Get-MgUserJoinedTeam -UserId user@domain.com

1 thought on “Quickly list all Groups and Teams a user is member of in Microsoft 365

  1. JM says:

    For Get-Recipient and Get-EXORecipient I had to use the “like” operator instead of the “eq” operator to get this to work.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.