Forum Discussion

Catarinagm's avatar
Catarinagm
Copper Contributor
Aug 22, 2022

See groups menbership of a list of users

Hello,

I'm trying to get a list from all groups that a user is part of, on a single file (DL, Teams groups, ...)

 

This is what I'm doing:

 

Connect-AzureAD

$Users=Get-Content -Path "C:\Temp\Test\Test.txt" #List the upn of the users i need to see what groups they are member of
 
$GroupsMembers=forEach($user in ($Users))
{Get-AzureADUser -SearchString $user | Get-AzureADUserMembership | % {Get-AzureADObjectByObjectId -ObjectId $_.ObjectId | select DisplayName,ObjectType,MailEnabled,SecurityEnabled,ObjectId,UserPrincipalName}}

$GroupsMembers | Export-CSV "C:\Temp\Test\Groupstest.CSV" -NoTypeInformation -Encoding Unicode
 
This way i can get a list of groups but i canĀ“t see the username of the users i imported ant their menbership.

 

What am i doing wrong?

Thank you.

  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    Catarinagm 

     

    Basically, you need to capture the user's details such as id, userPrincipalName, etc. in the outer loop, before proceeding to the inner loop to fetch the group/object details.

     

    I started earlier with one answer but decided to switch Azure modules (to a more "recent" one) and have a play. The example below is the result, where it pulls any kind of membership - not just groups. I've also added a flag called IsDynamicGroup since that's usually something you want to know when figuring out how someone ended up in (or out) of scope for a given group.

     

    The key additional inclusion from testing in my tenant is that it pulls Azure AD role memberships - which is quite nifty to know when working with PIM-style auditing. You can always filter this out client-side (or just take it out of the script altogether if you like.)

     

    For context, this script uses the following first-party Microsoft Azure modules:

     

    • Microsoft.Graph.Authentication
    • Microsoft.Graph.DirectoryObjects
    • Microsoft.Graph.Users

     

    It uses the Graph beta endpoint, which you can select using the following command:

     

    Select-MgProfile -Name "beta";

     

    Example script

    Get-Content -Path "D:\Data\Temp\Test.txt" |
        ForEach-Object { Get-MgUser -UserId "$_" -ExpandProperty TransitiveMemberOf -Select Id, UserPrincipalName, TransitiveMemberOf } |
            ForEach-Object {
                # We're now in your per user "outer" loop.
                $User = $_;
    
                $User.TransitiveMemberOf.Id |
                    ForEach-Object {
                        # Whereas now, we're in your per user membership inner loop. Here, we're iterating through each one of their memberships and pulling the Azure AD object details below.
    
                        Get-MgDirectoryObject -DirectoryObjectId "$_" |
                            ForEach-Object {
                                # This is yet another nested level we reach after having pulled the object for which the user is a member.
                                
                                [PSCustomObject] @{
                                    UserId = $User.Id;
                                    UserPrincipalName = $User.UserPrincipalName;
                                    ObjectId =  $_.id;
                                    ObjectType = $_.AdditionalProperties["@odata.type"].Split('.')[-1];
                                    ObjectName = $_.AdditionalProperties["displayName"];
                                    MailEnabled = $_.AdditionalProperties["mailEnabled"];
                                    SecurityEnabled = $_.AdditionalProperties["securityEnabled"];
                                    IsDynamicGroup = if ($null -ne $_.AdditionalProperties["groupTypes"]) { $_.AdditionalProperties["groupTypes"].Contains("DynamicMembership") } else { $null };
                                }
                            }
                    }
            } |
            Export-Csv -Path "D:\Data\Temp\test.csv" -NoTypeInformation -Encoding Unicode;

     

    Example output (having removed the Export-Csv in order to see this)

     

    Cheers,

    Lain

    • Catarinagm's avatar
      Catarinagm
      Copper Contributor
      Thank you so much for your answer and help.
      I used:
      Connect-Graph -Scopes User.ReadWrite.All, Organization.Read.All
      Select-MgProfile -Name "beta"

      but still getting this privileges error:

      Get-MgDirectoryObject : Insufficient privileges to complete the operation.
      At line:13 char:21
      + Get-MgDirectoryObject -DirectoryObjectId "$_" |
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : InvalidOperation: ({ DirectoryObje...ndProperty = }:<>f__AnonymousType2`3) [Get-MgDirectoryObject_Get1], RestException`1
      + FullyQualifiedErrorId : Authorization_RequestDenied,Microsoft.Graph.PowerShell.Cmdlets.GetMgDirectoryObject_Get1
      Get-MgDirectoryObject : Insufficient privileges to complete the operation.
      At line:13 char:21

      It never asked me for any tenant credentials.
      • Catarinagm's avatar
        Catarinagm
        Copper Contributor
        PS C:\WINDOWS\system32> Get-MgDirectoryObject -DirectoryObjectId xxxx

        Id DeletedDateTime
        -- ---------------
        xxx


        I have the permissions to run it individually
  • raindropsdev's avatar
    raindropsdev
    Iron Contributor

    Catarinagm

     

    Hi,

     

    The easy answer is that you're trying to get the UserPrincipalName of the Group rather than the user, which returns null because the group doesn't have a UserPrincipalName.

    As the variable $_. has already been overwritten by Get-AzureAdUsermembership you can't really reference back.

     

    I have written a Powershell script that would do the job and shared it on Github:

    https://github.com/Raindrops-dev/RAIN-TechCommunityContributions/blob/main/Get-AzureAdGroupMembership.ps1

     

    Check it out and let me know if it fits your requirements.

     

    EDIT: Apparently I was too slow and LainRobertson already came with a more modern solution!

Resources