【问题标题】:Get-Aduser -Filter will not accept a variableGet-Aduser -Filter 将不接受变量
【发布时间】:2013-12-03 05:44:28
【问题描述】:

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

$SamAc = Read-Host 'What is your username?'
$User = Get-ADUser -Filter {sAMAccountName -eq "$SamAc"}

我不知道为什么,但 $User 将始终返回 null,即使 {sAMAccountName -eq "$SamAc"} 应该为真。

我在这里错过了什么?

编辑:

这是缺少的:

$User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"

编者注:脚本块 ({ ... }) 被替换为字符串

【问题讨论】:

标签: powershell active-directory filtering powershell-3.0


【解决方案1】:

现有答案中包含有价值的信息,但我认为更有针对性的总结会有所帮助。请注意,此答案的原始形式主张严格避免 脚本块 ({...}) 和 AD-provider 变量评估,但这已被更细微的建议所取代。

tl;dr

Get-ADUser -Filter 'sAMAccountName -eq $SamAc'
  • 不要引用变量引用 ("$SamAc")。

  • 只使用简单的变量引用(例如,$SamAc); 表达式受支持(例如,$SamAc.Name$("admin_" + $SamAc));如有必要,使用中间的辅助变量;例如:

    • $name = "admin_" + $SamAc; Get-ADUser -Filter 'sAMAccountName -eq $name'
  • 通常,仅支持 PowerShell 运算符的 子集,甚至那些并不总是以相同的方式运行 - 请参阅底部。

  • 使用'...'-Filter 参数作为一个整体引用。

    • 虽然使用脚本块 ({ ... }),
      Get-ADUser -Filter { sAMAccountName -eq $SamAc } 在技术上也有效,但在概念上存在问题 - 请参阅底部部分。

警告:如果您通过 implicitly remoting module 使用 Get-ADUser - 无论是通过 Import-PSSession 自行创建,还是在 PowerShell v7+ 中通过 Windows Compatibility feature 自行创建 - 两者都不是 em> '...' 也不是 { ... } 工作,因为变量引用然后在 remote 机器上进行评估,寻找变量 there(徒劳);如果(Get-Command Get-ADUser).CommandType 返回Function,则说明您使用的是隐式远程处理模块。

  • 在这种情况下,您必须使用 PowerShell 的 string interpolation ("...") 或来自文字和变量引用/表达式的字符串连接,以便将任何变量/表达式值“烘焙”到字符串中预先
    Get-ADUser -Filter "sAMAccountName -eq `"$SamAc`""
  • 请注意,对于 string 操作数嵌入引用,则 必要的。
  • 另外,请务必在 "..." 字符串中转义 `-escape 常量,例如 $true$false$null,以便 PowerShell 不会预先扩展它们。
  • 警告:此技术可能不适用于所有数据类型;至少 [datetime] 实例的默认字符串化(例如,01/15/2018 16:00:00被 AD 提供程序识别;在这种情况下,将对实例的 .ToFileTime() 方法的调用结果嵌入到该字符串可能会有所帮助(未经测试);我不清楚是否还有其他需要类似解决方法的数据类型。

背景

  • 您传递给-Filter 的任何参数都被强制转换为字符串首先之前它被传递给Get-ADUser cmdlet,因为-Filter 参数的类型为[string] - 因为它适用于支持此参数的所有 提供程序cmdlet;验证Get-ADUser -?

  • 一般来说,-Filtercmdlet(底层的PowerShell provider)使用域特定(查询)语言来解释该字符串 通常与 PowerShell几乎没有共同之处

    • 对于Get-ADUser,特定领域的语言(查询语言)记录在Get-Help about_ActiveDirectory_Filter中。

      • 注意:在撰写本文时,不存在此旧主题的更新版本; this GitHub issue 请求一个。
    • 有了Get-AdUser,这种语言肯定仿照 PowerShell,但它有许多限制和一些行为差异必须注意,特别是:

      • 仅支持有限的 PowerShell 运算符子集,并且一些表现出不同的行为;这是一个非详尽的列表:

        • -like / -notlike 仅支持通配符表达式中的 *(不支持 ? 和字符集/范围 ([...])
          • '*' 本身代表任何 非空 值(与 PowerShell 的通配符表达式不同,它也匹配一个空值)。
          • 不要使用-eq ""-eq $null 来测试字段是否为空,而是使用
            -notlike '*'
          • 某些 AD 字段,例如 DistinguishedName支持 '*' 单独,而不是更大模式的一部分;也就是说,它们只支持空性测试。
        • 不支持 regex 匹配。
        • -lt / -le-gt / -ge 仅执行词法比较。
        • 引用不存在/拼写错误的属性名称会导致 Get-ADUser 命令悄悄返回 $null
      • 如上所述,仅支持简单的变量引用(例如,$SamAc),还支持表达式(例如,$SamAc.Name$("admin_" + $SamAc))

  • 虽然您可以使用脚本块 ({ ... }) 将成为字符串的内容传递给-Filter,而这种语法对于嵌入 方便 quotes,有问题有两个原因:

    • 这可能会误导您认为您正在传递一段 PowerShell 代码;值得注意的是,您可能倾向于使用不受支持的运算符和表达式,而不是简单的变量引用。

    • 它会产生不必要的工作(尽管这在实践中不太重要),因为您强制 PowerShell 首先将过滤器解析为 PowerShell 代码,只是在参数绑定到 @ 时将结果转换回字符串987654386@.

【讨论】:

    【解决方案2】:

    当我第一次开始使用 ActiveDirectory 模块时,这个问题让我很头疼,弄起来很痛苦。

    ActiveDirectory 模块 cmdlet 的 -Filter 参数实际上是在寻找一个字符串。当您将{sAMAccountName -eq "$SamAc"} 作为值时,它实际上是在寻找"sAMAccountName -eq ""`$SamAc"""

    基本上,Powershell 会解析参数并将其值转换为字符串,并且不会对变量进行插值。尝试事先构建字符串,它应该可以工作。

    类似这样的:

    $SamAc = Read-Host 'What is your username?'    
    $filter = "sAmAccountname -eq ""$SamAc"""
    $User = Get-ADUser -Filter $filter
    

    【讨论】:

    • 这对我帮助很大,我终于用了类似的东西:Get-ADObject -Properties mail, proxyAddresses -Filter "mail -eq ""$Mail"" -or proxyAddresses -eq ""smtp:$Mail"""
    • 使用 strings 而不是脚本块的好建议,但Get-ADUser(令人惊讶)确实解释变量引用,只是它没有在这种情况下,期望包含文字 quotes
    【解决方案3】:

    我必须对此发表评论,因为解决这个问题真的让我很恼火。

    约瑟夫·奥尔康的想法是正确的。 filter 参数接受一个字符串,然后对其进行评估以处理过滤器。让人们感到困惑的是,您可以选择使用大括号而不是 {},如果您使用 Where... 它仍然必须像字符串一样处理,这不会像您期望的那样工作。

    $SamAc = Read-Host 'What is your username?'
    $User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
    

    我建议坚持使用引号,以使其对自己和他人更清晰/易读,并避免潜在的语法错误,或者坚持使用管道中的 Where{}。这样做时,我发现最好在外部使用双引号,在内部使用单引号,这样您仍然可以在变量上获得intellisense 检测。

    【讨论】:

      【解决方案4】:

      只需删除变量周围的引号:

      $SamAc = Read-Host 'What is your username?'

      $User = Get-ADUser -Filter {sAMAccountName -eq $SamAc}

      这应该可以正常工作。

      【讨论】:

        【解决方案5】:
        if (($ADUser = Get-ADUser -filter "SamAccountName -eq '$(Read-Host Username)'") -ne $null) {$ADUser.SamAccountName} else {"Not Found"}
        

        【讨论】:

        • 您的答案比现有答案好多少?您甚至没有为您的代码提供任何说明为什么它有效(或者为什么它比现有答案更好)。
        • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
        【解决方案6】:

        如果有像我这样的人到了这里并且还在扯头发,那么一点补充:

        -properties *  
        

        在这个查询中很常见。不行,我敢肯定比我聪明的人能弄明白

        -属性mail,cn,wtf

        等确实按预期工作

        【讨论】:

          【解决方案7】:

          好的,我终于用下面的语法和上面的例子来工作了:

          以前:

          $User = Get-ADUser -Filter "sAMAccountName -eq '$SamAc'"
          

          工作版本:

          $user = Get-aduser -Filter "sAMAccountName -eq '$($SamAc)'"
          

          在 PowerShell 可以访问变量字符串值之前,我必须将 $($ ) 添加到 $SamAc。

          【讨论】:

          • 这两个插值字符串 ("...") 导致将完全相同的字符串文字传递给 Get-ADUser,因此第一个应该和第二个一样工作,您可以通过以下方式验证在 PowerShell 控制台窗口中运行以下命令:$SamAc = 'jdoe'; "sAMAccountName -eq '$SamAc'"; "sAMAccountName -eq '$($SamAc)'".
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-07-05
          • 1970-01-01
          • 2016-09-15
          • 2018-03-27
          • 1970-01-01
          • 1970-01-01
          • 2015-06-21
          相关资源
          最近更新 更多