【问题标题】:Issue with using properties in an array and custom calculated property在数组和自定义计算属性中使用属性的问题
【发布时间】:2022-08-17 23:59:28
【问题描述】:

所以我有以下代码在域控制器上摄取 AD 用户。以下引发错误:

# User Props to select
$user_props = @(
        \'Name\',
        \'DistinguishedName\',
        \'SamAccountName\',
        \'Enabled\',
        \'SID\'
        )

# Get AD groups an AD user is a member of
$user_groups = @{ label = \'GroupMemberships\'; expression = { (Get-ADPrincipalGroupMembership -Identity $_.DistinguishedName).Name } }

# Get AD Users
$users = Get-ADUser -Filter * -Property $user_props | Select-Object $user_props, $user_groups -ErrorAction Stop -ErrorVariable _error

但是,如果我要将 $users 更改为以下内容:

$users = Get-ADUser -Filter * -Property $user_props | Select-Object Name, DistinguishedName, SamAccountName, Enabled, SID, $user_groups -ErrorAction Stop -ErrorVariable _error

我不再收到此错误。有没有一种方法可以定义$user_props,这样我就不需要输入每个属性并仍然使用我的自定义计算属性$user_groups?

我相信这个问题与将数组 ($user_props) 与哈希表 ($user_groups) 混合有关,但我不确定如何最好地编写这个。感谢您的帮助!

    标签: powershell active-directory


    【解决方案1】:

    将两个变量“连接”到一个平面数组中的最简单方法是使用 @(...) 数组子表达式运算符:

    ... |Select-Object @($user_props;$user_groups) ...
    

    【讨论】:

    • 这正是我想要的,谢谢!
    【解决方案2】:

    由于这个问题不断出现,让我补充一些 Mathias R. Jessen's effective solution背景信息:

    • Select-Object's (潜在的位置隐含)-Property 参数需要一个平坦的属性名称数组和/或calculated properties(为简洁起见,两者都称为属性名称以下)。

    • 所以,如果你需要结合两个变量包含数组属性名称,或组合字面上地具有此类变量的枚举属性名称, 你必须显式构造一个平面数组.

    因此,只需将 , 放在数组变量之间即可不是工作,因为它创造了一个锯齿状(嵌套)数组:

      # Two arrays with property names.
      $user_props = @('propA', 'propB')
      $user_groups = @('grpA', 'grpB')
    
      # !! WRONG: This passes a *jagged* array, not a flat one.
      # -> ERROR: "Cannot convert System.Object[] to one of the following types 
      #           {System.String, System.Management.Automation.ScriptBlock}."
      'foo' | Select-Object $user_props, $user_groups
    
      # !! WRONG:
      # The same applies if you tried to combine one or more *literal* property names 
      # with an array variable.
      'foo' | Select-Object 'propA', $user_groups
      'foo' | Select-Object $user_groups, 'propA', 'propB'
    

    也就是说,$user_props, $user_groups 有效通过
    @( @('propA', 'propB'), @('grpA', 'grpB') ),即一个锯齿状(嵌套)数组,
    而你需要通过的是
    @('propA', 'propB', 'grpA', 'grpB'),即一个平坦的大批。

    Mathias 的解决方案很方便,因为您不必知道或关心 $user_props 和 $user_groups 是否包含数组或者只是一个属性名称,由于如何@(...),array-subexpression operator有效 - 结果将是一个平面数组:

    # Note how the variable references are *separate statements*, whose
    # output @(...) collects in an array:
    'foo' | Select-Object @($user_props; $user_groups)
    
    # Ditto, with a literal property name.
    # Note the need to *quote* the literal name in this case.
    'foo' | Select-Object @('propA'; $user_groups)
    

    在实践中,它不会对这个用例产生影响,所以这是一个方便实用的解决方案,但通常值得注意的是@(...)枚举数组变量用作其中的语句,然后将结果收集到一个新的大批。也就是说,$user_props 和 $user_groups 都被发送到管道逐个元素,并且结果,组合的元素被收集在一个新的数组中。

    平面连接数组的直接方法(或将单个元素附加到数组)是使用+ 具有(至少)一个数组值的运算符LHS.这必然会返回一个新的作为 LHS 数组的副本的数组,其中直接附加了 RHS 的元素:

    # Because $user_props is an *array*, "+" returns an array with the RHS
    # element(s) appended to the LHS element.
    'foo' | Select-Object ($user_props + $user_groups)
    

    如果您不确定 $user_props 是否为大批,您可以简单地转换为 [array],它也适用于单个文字属性名称:

    # The [array] cast ensures that $user_props is treated as an array, even if it isn't one.
    # Note:
    #   'foo' | Select-Object (@($user_props) + $user_groups) 
    #    would work too, but would again needlessly enumerate the array first.
    'foo' | Select-Object ([array] $user_props + $user_groups)
    
    # Ditto, with a single, literal property name
    'foo' | Select-Object ([array] 'propA' + $user_groups)
    
    # With *multiple* literal property names (assuming they come first), the
    # cast is optional:
    'foo' | Select-Object ('propA', 'propB'  +  $user_groups)
    

    笔记:

    • 以上使用(...),grouping operator,以通过表达式作为命令的参数 - 虽然您经常看到 $(...),但使用的是 subexpression operator,这是不是必要并且可能会产生不必要的副作用 - 请参阅this answer。

    • @(...) 并不严格需要声明数组文字,例如@('foo', 'bar') - 'foo', 'bar' 就足够了,尽管您可能更喜欢将@(...) 括起来以使视觉清晰。在争论parsing mode,引用的是可选的对于简单的字符串,Write-Output foo, name 是Write-Output @('foo', 'name') 的更简单替代方案

    • ,、array constructor operator 可能具有惊人的高 precedence,因此 1, 2 + 3 被解析为 (1, 2) + 3,导致 1, 2, 3

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-09
      • 1970-01-01
      • 2020-10-21
      • 1970-01-01
      • 2021-07-11
      • 2015-06-05
      • 1970-01-01
      • 2016-12-05
      相关资源
      最近更新 更多