Working with hash of arrays

Welcome Forums General PowerShell Q&A Working with hash of arrays

This topic contains 5 replies, has 2 voices, and was last updated by

 
Participant
1 month ago.

  • Author
    Posts
  • #171190

    Participant
    Topics: 1
    Replies: 3
    Points: 18
    Rank: Member

    Hi,

    I'm new to powershell, and having a bit of trouble with my first script. I'm pulling group memberships from AzureAD users (as a list of groups per each member) and wish to format as a list of members per each group. So my method was to create a hash of arrays, with groups as a key, and its members as an array value. Here's what I have:

    
    # list of users by userPrincipalName
    $upns = @('moe@stooge.com', 'larry@stooge.com', 'curly@stooge.com')
    
    $users = New-Object System.Collections.ArrayList
    $groupMemberships = @{}
    
    # Convert userPrincipalName to User Object
    ForEach ($upn in $upns) {
    if ( $user = Get-AzureADUser -Filter "userPrincipalName eq '$upn'" ) {
    $users += $user
    }
    }
    
    # Collect membership for each seen group
    ForEach ( $user in $users ) {
    ForEach ( $seenGroup in Get-AzureADUserMembership -All $true -ObjectID $user.ObjectId ) {
    if ( $groupMemberships.ContainsKey( $seenGroup ) ) {
    $groupMemberships[ $seenGroup ] += $user
    } else {
    $groupMemberships[ $seenGroup ] = @();
    $groupMemberships[ $seenGroup ] += $user
    }
    }
    }
    
    

    My problem is in pushing users into the hash of arrays. If the hash key doesn't exist, I create a new empty array as the hash value, then add the user to it. Problem is that all of the resulting hashes only contains a single user in the array – I'm not able to detect the  resulting hash key "if ( $groupMemberships.ContainsKey( $seenGroup )",  so with each iteration (over groups), a new array is created, deleting the previous array.

    I suspect I am having issues with scope, but not sure how to fix it.

     

    Thanks for your help,

    Rick

  • #171205

    Participant
    Topics: 9
    Replies: 423
    Points: 675
    Helping Hand
    Rank: Major Contributor

    If the purpose of the script is to get "list of members per each group" you can use something like:

    $UPNList = @(
        'moe@stooge.com'
        'larry@stooge.com'
        'curly@stooge.com'
    )
    
    $myOutput = foreach ($UPN in $UPNList) {
        if ($AzureADUser = Get-AzureADUser -Filter "UserPrincipalName eq '$UPN'") {
            if ($GroupList = Get-AzureADUserMembership -All $true -ObjectID $AzureADUser.ObjectId) {
                [PSCustomObject]@{
                    UPN = $UPN
                    GroupList = $GroupList.DisplayName
                }
            }
        }
    }
    
    $myOutput
    

    I don't think a hash table of arrays is the data structure you need here.
    I recommend that you format your output as a PS Object as shown above.

  • #171220

    Participant
    Topics: 1
    Replies: 3
    Points: 18
    Rank: Member

    Hi Sam,

    Thanks for your reply, much appreciated. However I am looking for the opposite output:

    
    group1  {user1, user...}
    
    group... {user1, user...}
    
    

    Which is what I meant by "list of users in each group".

    The hash structure is useful because the same directory can appear multiple times across the users. Placing each directory as a hash key naturally combines each unique directory data into a single instance (because keys have to be unique).

    Why won't my test for a key (my line 18) find an occurence generated (my line 22) in a previous loop?

    Rick

  • #171259

    Participant
    Topics: 1
    Replies: 3
    Points: 18
    Rank: Member

    Working script below. Returns a hash, with group display names as keys, and an array of group members (user principal names) as values.

    
    $UPNList = @(
        'moe@stooge.com'
        'larry@stooge.com'
        'curly@stooge.com'
    )
    
    $users = New-Object System.Collections.ArrayList
    $groupMemberships = @{}
    
    # Convert userPrincipalName to User Object
    ForEach ($UPN in $UPNList) {
        if ( $user = Get-AzureADUser -Filter "userPrincipalName eq '$UPN'" ) {
            $users += $user
        }
    }
    
    # Collect membership for each seen group
    ForEach ( $user in $users ) {
        ForEach ( $seenGroup in Get-AzureADUserMembership -All $true -ObjectID $user.ObjectId ) {
            $displayName = $seenGroup.DisplayName
            $userPrincipalName = $user.UserPrincipalName
            if ( $groupMemberships[ $displayname ] ) {
                $groupMemberships[ $displayName ] += $userPrincipalName
            } else {
                $groupMemberships[ $displayName ] = @( $userPrincipalName )
            }
        }
    }
    
    $groupMemberships | Format-List
    
  • #171286

    Participant
    Topics: 9
    Replies: 423
    Points: 675
    Helping Hand
    Rank: Major Contributor
    $UPNList = @(
        'moe@stooge.com'
        'larry@stooge.com'
        'curly@stooge.com'
    )
    
    $UserGroupMembership = foreach ($UPN in $UPNList) {
        if ($AzADUser = Get-AzureADUser -Filter "UserPrincipalName eq '$UPN'") {
            if ($GroupList = Get-AzureADUserMembership -All $true -ObjectId $azAdUser.ObjectId) {
                [PSCustomObject]@{
                    UPN       = $UPN
                    GroupList = $GroupList.DisplayName
                }
            }
        }
    }
    
    $GroupUserMembership = foreach ($GroupName in ($UserGroupMembership.GroupList | select -Unique)) {
        [PSCustomObject]@{
            GroupName  = $GroupName
            MemberList = ($UserGroupMembership | where GroupList -Contains $GroupName).UPN
        }
    }
    
    $UserGroupMembership | FT -a 
    $GroupUserMembership | FT -a
    
  • #171301

    Participant
    Topics: 1
    Replies: 3
    Points: 18
    Rank: Member

    Hs Sam,

    Very elegant. Looks like I should  learn more about PSCustomObject and how it's used in PowerShell scripting.

    Thanks!

    Rick

You must be logged in to reply to this topic.