能否使用Microsoft Graph PowerShell cmdlets从AdditionalProperties字典中提取信息?

5

我正在尝试使用PowerShell Graph cmdlets代替Azure AD模块cmdlets。使用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

我正在尝试找出使用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是一个字典(IDictionary),其中包含displayname、mail和userprincipalname。我的想法是可能有更好的方法来做这个或者获取信息。

Get-MgGroupmember中有一些有趣的参数,包括-ExpandProperty-Property,我不太清楚它们的含义。我尝试过调整这些参数,但没有成功。我想知道是否有一种方法可以使用它们来实现我想要的功能。

有什么建议吗?


如果AdditionalProperties是一个IDictionary,除非cmdlet内置了一些东西,否则您需要循环遍历键/值对并创建一个对象。您现在正在将字典转换为字符串,这将不容易在之后进行操作。 - Santiago Squarzon
1
@SantiagoSquarzon - 我明白你的意思 - 你能提供一个创建对象的例子吗?我的最终目标是将其导出到CSV文件中,然后再导入到类似数据库的结构中。 - James S.
希望这个答案能给你一个开始的提示。 - Santiago Squarzon
1
@SantiagoSquarzon - 哇,太棒了!PowerShell 对我来说就像第二语言一样。我通常使用 Python。我明白你的意思了,之前我并不知道这一点。谢谢! - James S.
1个回答

9
给定以下的$object,其中有3个属性,其中一个是AdditionalProperties,它是一个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
}

假设你对这个对象中的IddisplayNamemail感兴趣,你可以使用Select-Object计算属性
$object | Select-Object @(
    'Id'
    @{
        Name       = 'displayName'
        Expression = { $_.additionalProperties['displayName'] }
    }
    @{
        Name       = 'mail'
        Expression = { $_.additionalProperties['mail'] }
    }
)

然而,当你需要从对象中选择更多的属性值时,使用循环来取出PSCustomObject的属性值会变得混乱无章。
$object | ForEach-Object {
    [pscustomobject]@{
        Id          = $_.Id
        displayName = $_.additionalProperties['displayName']
        mail        = $_.additionalProperties['mail']
    }
}

这两种方法都会输出相同的"扁平化"对象,可以轻松转换为Csv格式:

  • 作为对象
Id          displayName mail
--          ----------- ----
placeholder placeholder placeholder

作为Csv文件返回
"Id","displayName","mail"
"placeholder","placeholder","placeholder"

在这个意义上,你可以使用上述技术之一构建一个对象数组,例如:
Get-MgGroupMember -GroupId $GroupID | ForEach-Object {
    [pscustomobject]@{
        Id                = $_.id
        displayName       = $_.additionalproperties['displayName']
        mail              = $_.additionalproperties['mail']
        userPrincipalName = $_.additionalproperties['userPrincipalName']
    }
}

如果您正在寻找一种编程方式来展开对象,您可以从以下示例开始。但是需要注意的是,此方法仅适用于属性嵌套只有一层的对象,换句话说,它无法处理递归:
$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

这将生成一个扁平化的对象,就像这样,也可以轻松转换为Csv:

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

值得注意的是,上面的示例未处理可能的键冲突,如果有两个或更多具有相同名称的属性,则一个将覆盖其他属性。

奖励功能应该能够与从Graph, AzureADAz模块返回的对象一起使用。该函数可以用于展平它们的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
    }
}

使用上面示例中的$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

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

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

Id          displayName userPrincipalName
--          ----------- -----------------
placeholder placeholder placeholder
placeholder placeholder placeholder
placeholder placeholder placeholder

很好的回答,希望我能早点找到这个!评论:多个模块都包含了ConvertTo-FlatObject命令,用于对深层对象进行扁平化处理。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接