Get-Aduser -Filter不接受变量

Jus*_*Guy 16 powershell filtering active-directory powershell-3.0

我想检查系统中是否已存在用户帐户.

$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq "$SamAc"}
Run Code Online (Sandbox Code Playgroud)

我不确定为什么,但$User即使{sAMAccountName -eq "$SamAc"}应该是真的,也总会返回null .

我在这里错过了什么?

编辑:

这是缺少的:

$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Run Code Online (Sandbox Code Playgroud)

编者按:脚本块({ ... })用替换字符串.

mkl*_*nt0 35

现有答案中有宝贵的信息,但我认为更有针对性的总结是有帮助的:

TL;博士

  • 切勿使用脚本块 - { ... }-构建-Filter-parameter的说法,对于任何 cmdlet的.

    • 它仅在非常有限的情况下起作用 - 见下文.
    • 它给出了错误的印象,即过滤器是PowerShell代码的一部分,它不是(Active Directory提供程序仅支持少数类似 PowerShell的运算符,但它们的行为部分不同于它们的PowerShell代码 - 请参阅Get-Help about_ActiveDirectory_Filter).
  • 总是使用字符串来构造-Filter参数参数,因为参数的实际类型 [string]


正确和可靠的方法是构造一个字符串

  • 任何参数传递给-Filter被强制转换为字符串第一无论如何,之前它被传递到Get-ADUsercmdlet的,因为-Filter参数的类型为[string]-跨所有支持该参数的cmdlet; 验证Get-ADUser -?

  • 随着-Filter在一般情况下,它是由该cmdlet的解释该字符串,使用特定领域的语言,往往有什么共同之处使用PowerShell.

使用PowerShell的 字符串插值(从文字和变量引用/表达式或字符串连接),以"烤"的任何变量引用到字符串,在前面.

例如,以下命令全部工作且在功能上等效,使用各种PowerShell技术构造字符串,引用样式和转义字符的变化:

# All these commands are equivalent.
Get-ADUser -Filter "sAMAccountName -eq ""$SamAc"""
Get-ADUser -Filter "sAMAccountName -eq `"$SamAc`""                                    #`
Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
Get-ADUser -Filter ('sAMAccountName -eq "' + $SamAc + '"')
Run Code Online (Sandbox Code Playgroud)

重要的是确保通过双引号字符串或显式字符串连接()来$SamAc预先扩展(由其值替换)."..."+ $SamAc + ...

例如,如果$SamAc包含jdoe上述命令,则将以下(等效)文字之一传递给-Filter:

sAMAccountName -eq "jdoe"
sAMAccountName -eq 'jdoe'
Run Code Online (Sandbox Code Playgroud)

但是,对于数字和字符串以外的数据类型,您可能仍需要使用AD提供程序的变量评估(请参阅下文):

例如,AD提供者[1]不会将字符串化[datetime]值(例如08/15/2018 12:45:58)识别为日期.

在那种情况下:

  • 使用引号字符串('...')
  • 一定要只使用简单的变量引用(例如$date),而不是表达式($date.Year$($date.Year)); 例如:
# Note the use of '...' and be sure to use just a variable reference, 
# not an expression.
# With this approach, never use embedded quoting, even with string variables.
Get-ADUser -Filter 'whenChanged -ge $date' 
Run Code Online (Sandbox Code Playgroud)

警告:此方法不适用于隐式远程处理模块,因为然后在远程计算机上评估变量引用.


如果指定脚本块 - 应该避免:

转换为字符串时,脚本块会生成和之间的文字内容- 不会发生变量扩展(插值):{}

 PS> {sAMAccountName -eq "$SamAc"}.ToString()
 sAMAccountName -eq "$SamAc"  # !! $SamAc was *not* expanded
Run Code Online (Sandbox Code Playgroud)

因此,它是传递给的文字 .sAMAccountName -eq "$SamAc"Get-ADUser

Get-ADUser,也许是为了支持脚本块语法/更像PowerShell,支持引用变量引号 - 注意缺少"around$SamAc:

{ sAMAccountName -eq $SamAc }  # as stated, Get-ADUser doesn't see the { and }
Run Code Online (Sandbox Code Playgroud)

也就是说,Get-ADUser它对字符串文字有类似 Powershell的解释:就像你不必在PowerShell表达式中包含变量引用一样(例如),你也不必在这里 - 实际上一定不能,正如OP的尝试失败所证明的那样. sAMAccountName -eq $SamAc"..."'Windows_NT' -eq $env:OS

但是,这种常规PowerShell脚本块的模拟不仅令人困惑 - 因为用户仍然认为他们需要封闭引号 - 但也是半生不熟的,因此很脆弱:


脚本块混淆的来源

而:

除了一个例外,这些示例仅使用脚本块中的文字,问题永远不会出现.那个例外(截至本文撰写时)是:

-filter { lastLogon -le $logonDate }
Run Code Online (Sandbox Code Playgroud)

这个例子恰好起作用 - 它使用一个没有引号的简单变量引用 - 但是,由于选择了非字符串值,在这种情况下没有人会错误地应用封闭引号- 与比较字符串字段时不同.

脚本块语法诱人且方便,因为引用变得更容易:您不需要嵌套引用.
但是,由于所讨论的所有原因,应该避免.


[1]所述的串-膨胀-的前期的等效可变评价按AD-提供商语句
Get-ADUser -Filter 'whenChanged -ge $date'
Get-ADUser -Filter "whenChanged -ge '$date'"
这意味着AD提供商最终看到像
whenChanged -ge '01/15/2018 16:00:00'
作为过滤器表达式; 为了实现这一点,它必须(a)接受一个字符串作为操作数,并且(b)理解PowerShell的日期/时间格式,这是不变文化的格式(类似于美国的日期,首先列出月份,但是24 - 小时).
虽然我无法亲自测试这种行为,但Luke报告称AD提供商确实无法识别此格式.


Jos*_*orn 11

当我第一次开始使用ActiveDirectory模块时,这就是我的一点点,这很难理解.

-FilterActiveDirectory模块cmdlet 的参数实际上是在查找字符串.当你做{sAMAccountName -eq "$SamAc"}这个值时,它实际上是在寻找"sAMAccountName -eq ""`$SamAc"""

基本上,Powershell解析参数并将其值转换为字符串,并且不会插入变量.尝试先建立字符串,它应该工作.

像这样的东西:

$SamAc = Read-Host 'What is your username?'    
$filter = "sAmAccountname -eq ""$SamAc"""
$User = Get-ADUser -Filter $filter
Run Code Online (Sandbox Code Playgroud)