代码之家  ›  专栏  ›  技术社区  ›  codewario

为什么在使用基于括号的-filter参数时$psitem的行为不符合预期?

  •  5
  • codewario  · 技术社区  · 6 年前

    我在帮助用户回答这个问题,链接到我的答案: Powershell script to add users to A/D group from .csv using email address only?

    最初我编写脚本如下,使用基于括号的过滤器 Get-AdUser 如下:

    Import-CSV "C:\users\Balbahagw\desktop\test1.csv" | 
      Foreach-Object {
    
        # Here, $_.EmailAddress refused to resolve
        $aduser = Get-ADUser -Filter { EmailAddress -eq $_.EmailAddress }
    
        if( $aduser ) {
          Write-Output "Adding user $($aduser.SamAccountName) to groupname"
          Add-ADGroupMember -Identity groupname -Members $aduser
        } else {
          Write-Warning "Could not find user in AD with email address $($_.EmailAddress)"
        }
      }
    

    然而, $_.EmailAddress 无法填充值。但是,改变 Get-ADUser 筛选到基于字符串的筛选,按预期工作:

    $aduser = Get-ADUser -Filter "EmailAddress -eq '$($_.EmailAddress)'"

    我所经历的奇怪是什么?为什么?是因为当我使用方括号时,它被视为一个新的作用域, $PSItem 不会跟着吗?

    2 回复  |  直到 6 年前
        1
  •  6
  •   mklement0    6 年前
    • -Filter 参数通常是 一串 参数(用验证
      Get-Help Get-AdUser -Parameter Filter )

      • 他们通常是这样 接受 PowerShell代码 -过滤器是 特定于提供程序 并且通常有自己的语法,尽管它恰好是PowerShell- 喜欢 对于AD Cmdlet。
        此外,他们通常不了解PowerShell 变量 (见下文)。
    • 因此,当 脚本块 ( { ... } )通过了,就是 转换为字符串 ,其计算结果为 字面意义的 内容(开口之间的所有内容 { 和结束语 } ):

      • { EmailAddress -eq $_.EmailAddress }.ToString() 生成文本字符串 EmailAddress -eq $_.EmailAddress -没有任何评估-这就是 Get-AdUser 看到- 进行评估。

      • 为了支持将脚本块传递给 -过滤器 AD Cmdlet的参数,似乎这些Cmdlet实际上显式扩展 简单的 变量引用,例如 $_ 在它们接收的字符串文本中,但这不适用于 表达 ,例如访问 财产 变量的( $_.EmailAddress )

    因此, -过滤器 参数通常应作为 可扩展字符串 ( "..." ) ;在手头的情况下:

     -Filter  "EmailAddress -eq '$($_.EmailAddress)'"
    

    也就是说,唯一可靠的解决方案是 可变部分 烘烤 , 正面 ,通过字符串扩展,如上图所示。

    对于既不是数字也不是字符串的值,例如 日期 ,您可能需要使用 字面意义的 字符串( '...' )并依赖于广告提供商评估对PowerShell变量的简单引用的能力(例如, $date ) -见 this answer 详情请看我的。

    如前所述,AD筛选器的语法仅为PowerShell- 喜欢 :它只支持PowerShell支持的运算符的一个子集,而那些受支持的运算符在行为上略有不同-请参阅 Get-Help about_ActiveDirectory_Filter .

    • 它是 诱人的 使用脚本块,因为其中的代码不需要转义嵌入的引号/不需要交替使用引号字符,也不需要使用子表达式运算符 $(...) . 但是,除了一般将脚本块用作效率低下的字符串之外,这里的问题是 脚本块承诺它不能遵守 就像你在传递 PowerShell 代码,但你不是-而且它只在简单的情况下工作(然后仅仅是由于上面提到的错误的适应);一般来说,在什么情况下它很难记住 工作,以及如果失败如何使其工作。

    • 因此,非常不幸的是,官方文档在其示例中使用了脚本块。

    有关更全面的讨论,请参见 这个答案 我的。

        2
  •  2
  •   FoxDeploy    6 年前

    你没有错,是模块的故障

    必须使用的有效载荷类型 -Filter 参数的不同取决于您使用的是哪个提供程序,这是一个非常令人困惑的设计决策!

    的输出 Get-Help Get-ADUser -Parameter Filter 给出了一些非常详细的示例,说明了可以与Active Directory提供程序的过滤器语法实现一起使用的不同语法选项。

    下面是一个例子:

    #To get all user objects that have an e-mail message attribute, use one of the following commands:
    
    Get-ADUser -Filter {EmailAddress -like "*"}
    

    看起来ActiveDirectory提供程序放置了必须用引号括住输入的特定限制。下面是当我在电子邮件中不加引号地查找我的帐户时发生的情况。

    Get-ADUser -Filter {EmailAddress -eq stephen@foxdeploy.com}
    Get-ADUser : Error parsing query: 'EmailAddress -eq stephen@foxdeploy.com' 
    Error Message: 'syntax error' at position: '18'.
    

    但是添加引号?它起作用了!

    Get-ADUser -Filter {EmailAddress -eq "stephen@foxdeploy.com"}
    
    
    DistinguishedName : CN=Stephen,CN=Users,DC=FoxDeploy,DC=local
    Enabled           : True
    GivenName         : Stephen
    Name              : Stephen
    ObjectClass       : user
    ObjectGUID        : 6428ac3f-8d17-45d6-b615-9965acd9675b
    SamAccountName    : Stephen
    SID               : S-1-5-21-3818945699-900446794-3716848007-1103
    Surname           : 
    UserPrincipalName : Stephen@FoxDeploy.local
    

    如何让你的工作

    现在,由于这个令人困惑的过滤器实现,您需要更改您的用户在线查找 致:

     $aduser = Get-ADUser -Filter "EmailAddress -eq `"$($_.EmailAddress)`""
    

    我们提供 -过滤器 作为字符串的有效负载。接下来,我们要使用字符串扩展来拉出 .EmailAddress 属性,因此我们将字符串包装在 $( ) 信号串扩展。最后,提供者希望我们的过滤器比较用引号括起来,所以我们在它周围加上双引号,然后使用反勾字符转义引号。

    现在应该可以了。

    tldr-责备提供程序和模块,与Active Directory模块有太多不一致之处。