可以使用 Microsoft Graph PowerShell cmdlet 从AdditionalProperties 字典中提取信息吗?

Jam*_* S. 5 powershell azure-active-directory microsoft-graph-api

我尝试使用 PowerShell Graph cmdlet 而不是 Azure AD 模块 cmdlet。使用 Azure AD 模块,我可以执行以下操作:

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

DisplayName     Mail                        UserPrincipalName  ObjectId
-----------     ----                        -----------------  --------
John Smith      John.Smith@example.org      jsmith@example.org 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
Run Code Online (Sandbox Code Playgroud)

我试图找出 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']
    }
Run Code Online (Sandbox Code Playgroud)

AdditionalProperties 是一个字典 (IDictionary),其中包含显示名称、邮件和用户主体名称。我的想法是可能有更好的方法来做到这一点或获取信息。

有一些有趣的参数Get-MgGroupmember,我不清楚包括-ExpandProperty-Property。我尝试过使用这些,但没有任何运气。我想知道是否有办法使用这些来完成我想要的事情。

建议?

San*_*zon 9

给定以下$object3 个属性,其中之一AdditionalProperties是 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
}
Run Code Online (Sandbox Code Playgroud)

假设您对此对象感兴趣IddisplayName并且mail,您可以使用Select-Object计算属性

$object | Select-Object @(
    'Id'
    @{
        Name       = 'displayName'
        Expression = { $_.additionalProperties['displayName'] }
    }
    @{
        Name       = 'mail'
        Expression = { $_.additionalProperties['mail'] }
    }
)
Run Code Online (Sandbox Code Playgroud)

然而,一旦您需要从对象中选取更多属性值,这就会变得混乱,PSCustomObject在这种情况下循环会派上用场:

$object | ForEach-Object {
    [pscustomobject]@{
        Id          = $_.Id
        displayName = $_.additionalProperties['displayName']
        mail        = $_.additionalProperties['mail']
    }
}
Run Code Online (Sandbox Code Playgroud)

两种替代方案都会输出相同的“扁平”对象,可以毫无问题地转换为 Csv:

  • 作为对象
Id          displayName mail
--          ----------- ----
placeholder placeholder placeholder
Run Code Online (Sandbox Code Playgroud)
  • 作为CSV
"Id","displayName","mail"
"placeholder","placeholder","placeholder"
Run Code Online (Sandbox Code Playgroud)

从这个意义上说,您可以使用上述技术之一构造对象数组,例如:

Get-MgGroupMember -GroupId $GroupID | ForEach-Object {
    [pscustomobject]@{
        Id                = $_.id
        displayName       = $_.additionalproperties['displayName']
        mail              = $_.additionalproperties['mail']
        userPrincipalName = $_.additionalproperties['userPrincipalName']
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您正在寻找一种编程方式来展平对象,您可以从使用此示例开始,但需要注意的是,这只能处理属性仅嵌套一次的对象,换句话说,它无法处理递归:

$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
Run Code Online (Sandbox Code Playgroud)

其输出将成为像这样的扁平对象,它也可以毫无问题地转换为 Csv:

DeletedDateTime   : placeholder
Id                : placeholder
displayName       : placeholder
mail              : placeholder
userPrincipalName : placeholder
Run Code Online (Sandbox Code Playgroud)

还值得注意的是,上面的示例没有处理可能的按键冲突,如果有 2 个或多个同名属性,其中一个会覆盖其他属性。


Bonus 函数应该与来自GraphAzureADAz模块的 cmdlet 返回的对象一起使用。此功能对于扁平化其属性很有用Dictionary`2。如果属性值实现,它看起来只会深一层,IDictionary所以不要指望它会展平任何对象。对于给定的示例应该效果很好。

function Select-GraphObject {
    [CmdletBinding(PositionalBinding = $false)]
    param(
        [Parameter(Mandatory, ValueFromPipeline, DontShow)]
        [object] $InputObject,

        [Parameter(Position = 0)]
        [SupportsWildcards()]
        [string[]] $Properties = '*'
    )

    begin {
        $firstObject = $true
        $toSelect    = [Collections.Generic.List[object]]::new()
    }
    process {
        if($firstObject) {
            foreach($property in $InputObject.PSObject.Properties) {
                foreach($item in $Properties) {
                    if($property.Value -is [Collections.IDictionary]) {
                        foreach($key in $property.Value.PSBase.Keys) {
                            if($key -like $item -and $key -notin $toSelect.Name) {
                                $toSelect.Add(@{
                                    $key = { $_.($property.Name)[$key] }
                                })
                            }
                        }
                        continue
                    }

                    if($property.Name -like $item -and $property.Name -notin $toSelect) {
                        $toSelect.Add($property.Name)
                    }
                }
            }
            $firstObject = $false
        }

        $out = [ordered]@{}
        foreach($item in $toSelect) {
            if($item -isnot [hashtable]) {
                $out[$item] = $InputObject.$item
                continue
            }
            $enum = $item.GetEnumerator()
            if($enum.MoveNext()) {
                $out[$enum.Current.Key] = $InputObject | & $enum.Current.Value
            }
        }
        [pscustomobject] $out
    }
}
Run Code Online (Sandbox Code Playgroud)

使用上面示例中的副本$object,如果使用默认值-Properties,示例对象将被展平

PS /> $object, $object, $object | Select-GraphObject

DeletedDateTime Id          displayName mail        userPrincipalName
--------------- --          ----------- ----        -----------------
placeholder     placeholder placeholder placeholder placeholder
placeholder     placeholder placeholder placeholder placeholder
placeholder     placeholder placeholder placeholder placeholder
Run Code Online (Sandbox Code Playgroud)

或者我们可以过滤特定的属性,甚至是AdditionalProperties属性中的键:

PS /> $object, $object, $object | Select-GraphObject Id, disp*, user*

Id          displayName userPrincipalName
--          ----------- -----------------
placeholder placeholder placeholder
placeholder placeholder placeholder
placeholder placeholder placeholder
Run Code Online (Sandbox Code Playgroud)