5

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

最初我编写脚本如下,使用基于括号的过滤器,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不会跟随?

4

2 回答 2

7
  • -Filter参数一般是字符串参数(用 验证
    Get-Help Get-AdUser -Parameter Filter

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

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

    • 为了支持将脚本块传递给 AD cmdlet 的参数的广泛但不明智的做法-Filter,这些 cmdlet 似乎实际上显式地扩展了简单的变量引用,例如$_在它们收到的字符串文字中,这是一种可能是善意但被误导的努力,但这不适用于表达式,例如访问变量的属性( $_.EmailAddress)

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

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

也就是说,唯一可靠的解决方案是使用带有可变部分字符串预先通过字符串扩展,如上所示。

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

如前所述,AD 过滤器的语法仅类似于PowerShell :它仅支持 PowerShell 支持的运算符的子集,而受支持的运算符在行为上略有不同 - 请参阅Get-Help about_ActiveDirectory_Filter

  • It is tempting to use script blocks, because the code inside requires no escaping of embedded quotes / no alternating of quote chars and no use of subexpression operator $(...). However, aside from using script blocks as strings being inefficient in general, the problem here is that the script block is making a promise that it cannot keep: it looks like you're passing a piece of PowerShell code, but you're not - and it works only in simple cases (and then only due to the misguided accommodation mentioned above); generally, it's hard to remember under what circumstances it doesn't work and how to make it work if it fails.

  • It is therefore really unfortunate that the official documentation uses script blocks in its examples.

For a more comprehensive discussion, see this answer of mine.

于 2018-07-02T14:41:37.560 回答
2

你没看错,是模块的错

您必须与参数一起使用的有效负载类型-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

如何让你的工作

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

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

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

现在它应该可以工作了。

TLDR - 责怪提供者并责怪模块,与 Active Directory 模块有很多不一致之处。

于 2018-07-02T14:24:08.040 回答