为什么在使用基于括号的 -Filter 参数时$PSItem没有按预期运行?



我正在帮助一位用户解决这个问题,链接到我的答案:仅使用电子邮件地址将用户从.csv添加到a/D组的Powershell脚本?

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

Import-CSV "C:usersBalbahagwdesktoptest1.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不会跟随吗?

  • -Filter参数通常是字符串参数(使用
    Get-Help Get-AdUser -Parameter Filter验证)

    • 它们通常不接受PowerShell代码-筛选器是特定于提供程序的,并且通常有自己的语法,尽管在AD cmdlet的情况下,它恰好是类似于的PowerShell
      此外,他们通常不了解PowerShell变量(请参阅下文)
  • 因此,当传递脚本块({ ... })时,它被转换为字符串,该字符串的计算结果为其文本内容(开头{和结尾}之间的所有内容):

    • { EmailAddress -eq $_.EmailAddress }.ToString()产生文本字符串EmailAddress -eq $_.EmailAddress-没有任何求值-这就是Get-AdUser所看到的-没有求值发生。

    • 为了支持将脚本块传递给AD cmdlet的-Filter参数这一广泛但不明智的做法,这些cmdlet实际上似乎在接收的字符串文本中显式扩展了简单的变量引用,如$_,但这对表达式不起作用,例如访问变量($_.EmailAddress)的属性

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

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

也就是说,唯一稳健的解决方案是通过字符串扩展,使用字符串和中烘焙的变量部分在前面,如上所示。

对于既不是数字也不是字符串的值,例如日期,您可能必须使用文字字符串('...'),并依赖AD提供程序评估对PowerShell变量(例如$date)的简单引用的能力-有关详细信息,请参阅我的回答。

如上所述,AD筛选器的语法仅为PowerShell-类似于:它只支持PowerShell支持的运算符的一个子集,并且支持的运算符在行为上略有不同-请参阅Get-Help about_ActiveDirectory_Filter

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

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

有关更全面的讨论,请参阅我的回答。

你没有错,这是模块的错

您必须与-Filter参数一起使用的有效负载类型因您使用的提供商而异,这一设计决策可能会非常令人困惑!

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

这里有一个例子:

#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

如何让你的工作

现在,由于这种令人困惑的过滤器实现,您需要将5行上的用户查找更改为以下内容:

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

我们以字符串的形式提供-Filter有效载荷。接下来,我们想使用字符串扩展来提取.EmailAddress属性,所以我们将字符串封装在$( )中以表示字符串扩展。最后,提供者希望我们的过滤器比较包含在引号中,所以我们在它周围加上双引号,然后使用反勾字符转义引号。

现在它应该起作用了。

TLDR-指责提供商和模块,Active Directory模块有很多不一致之处。

相关内容

  • 没有找到相关文章

最新更新