Working with hash of arrays

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

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.

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

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
$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

Hs Sam,

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

Thanks!

Rick