Home > database >  Possible to pull info from AdditionalProperties dictionary with Microsoft Graph PowerShell cmdlets?
Possible to pull info from AdditionalProperties dictionary with Microsoft Graph PowerShell cmdlets?

Time:05-26

I am trying to use PowerShell Graph cmdlets instead of the Azure AD module cmdlets. With the Azure AD module, I can do this:

# This is what I want:
get-azureadgroupmember -objectid $GroupID | select-object -property displayname, `
    mail, userprincipalname, objectid

DisplayName     Mail                        UserPrincipalName  ObjectId
-----------     ----                        -----------------  --------
John Smith      [email protected]      [email protected] 4bae8291-6ec3-192b-32ce-dd21869ef784
(...)


# All of these properties are directly accessible in the returned objects:
$res = get-azureadgroupmember -objectid $GroupID
$res[0] | fl -prop *
# Shows long list of directly accessible properties

I'm trying to figure out the equivalent with PowerShell Graph:

$res = get-mggroupmember -groupid $GroupID
$res[0] | fl -prop *
# Only properties are DeletedDateTime, Id, and AdditionalProperties

# Want to do something like this, but it doesn't work:
get-mggroupmember -groupid $GroupID | select-object -property id, `
    additionalproperties['displayName'], additionalproperties['mail'], `
    additionalproperties['userPrincipalName']

# This works, but is there a better option???
get-mggroupmember -groupid $GroupID | foreach-object { `
        "{0},{1},{2},{3}" -f $_.id, $_.additionalproperties['displayName'], `
        $_.additionalproperties['mail'], $_.additionalproperties['userPrincipalName']
    }

AdditionalProperties is a dictionary (IDictionary) which contains displayname, mail, and userprincipalname. My thought is there is probably a better way to do this or to get at the information.

There are a few interesting parameters in get-mggroupmember that I'm not clear on including "-expandproperty" and "-property". I've tried playing around with these but haven't had any luck. I'm wondering if there's a way to use these to do what I want.

Suggestions?

CodePudding user response:

Given the following $object, 3 properties and one of them AdditionalProperties is a Dictionary<TKey,TValue>:

$dict = [Collections.Generic.Dictionary[object, object]]::new()
$dict.Add('displayName', 'placeholder')
$dict.Add('mail', 'placeholder')
$dict.Add('userPrincipalName', 'placeholder')

$object = [pscustomobject]@{
    DeletedDateTime = 'placeholder'
    Id = 'placeholder'
    AdditionalProperties = $dict
}

Supposing from this object you're interested in Id, displayName and mail, you could use Select-Object with calculated properties:

$object | Select-Object @(
    'Id'
    @{
        N = 'displayName'
        E = { $_.additionalProperties['displayName'] }
    }
    @{
        N = 'mail'
        E = { $_.additionalProperties['mail'] }
    }
)

However this gets messy as soon as you need to pick more property values from the objects, PSCustomObject with a loop comes in handy in this case:

$object | ForEach-Object {
    [pscustomobject]@{
        Id          = $_.Id
        displayName = $_.additionalProperties['displayName']
        mail        = $_.additionalProperties['mail']
    }
}

Both alternatives would output the same "flattened" object that can be converted to Csv without any issue:

  • As Object
Id          displayName mail
--          ----------- ----
placeholder placeholder placeholder
  • As Csv
"Id","displayName","mail"
"placeholder","placeholder","placeholder"

In that sense, you could construct an array of objects using one of the above techniques, for example:

Get-MgGroupMember -GroupId $GroupID | ForEach-Object {
    [pscustomobject]@{
        Id                = $_.id
        displayName       = $_.additionalproperties['displayName']
        mail              = $_.additionalproperties['mail']
        userPrincipalName = $_.additionalproperties['userPrincipalName']
    }
}

If you're looking for a programmatical way to flatten the object, you can start by using this example, however it's important to note that this can only handle an object which's property is nested only once, in other words, it can't handle recursion:

$newObject = [ordered]@{}
foreach($property in $object.PSObject.Properties) {
    if($property.Value -is [Collections.IDictionary]) {
        foreach($addproperty in $property.Value.GetEnumerator()) {
            $newObject[$addproperty.Key] = $addproperty.Value
        }
        continue
    }
    $newObject[$property.Name] = $property.Value
}
[pscustomobject] $newObject

The output from this would become a flattened object like this, which also, can be converted to Csv without any issue:

DeletedDateTime   : placeholder
Id                : placeholder
displayName       : placeholder
mail              : placeholder
userPrincipalName : placeholder

It's also worth noting that above example is not handling possible key collision, if there are 2 or more properties with the same name, one would override the others.

  • Related