【问题标题】:How to assign multiple 'where' conditions to variable in Powershell如何在Powershell中为变量分配多个“where”条件
【发布时间】:2021-06-12 02:41:18
【问题描述】:

我正在开发一个 Powershell 脚本(带有 GUI),以帮助我的同事更轻松地找到冗余和禁用的 AD 帐户。

这是一个小预览......

$props = "Name, Enabled, PasswordExpired, Company,passwordNeverExpires, Office"

$propsAsArray = $props -split ',\s*'

Get-ADUser -filter * -properties $propsAsArray | where {$_.Enabled -eq $true} | where {$_.PasswordNeverExpires -eq $false}| where {$_.passwordexpired -eq $false} | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"

一切正常并输出 CSV 报告。

问题在于如何将 AD 帐户状态的所有可能组合和排列分配给变量,然后将变量替换为 Get-ADUser cmdlet(取决于用户在 GUI 中单击的单选按钮)。

我已经尝试了所有能想到的但只能返回错误Expressions are only allowed as the first element of a pipeline

我确定$accountStatus = "where {$_.Enabled -eq $true} | where {$_.PasswordNeverExpires -eq $false}"(或微妙的变体)不是它的完成方式。

我对 Powershell 比较陌生,渴望获得经验。谢谢,威廉。

【问题讨论】:

  • 每次运行此类查询时从您的 AD 中查询所有用户并随后使用多个 Where-Objects 过滤它们实际上并不是最好的主意。最好创建适当的过滤器字符串以与参数 -Filter 一起使用,因为这会给您的 AD 带来更少的压力。 ;-)
  • 感谢您的提示。脚本的最终版本将使用“SearchBase”参数来减少 DC 上的负载。我很乐意使用 -Filter 参数来查找密码已过期的用户,但看起来这是不可能的。我的研究表明,“PasswordExpired”是一种方法,而不是标准属性,因此无法过滤。 “链式” where 语句是唯一可行的解​​决方法。
  • 我的代码基于serverfault.com/questions/723217/… 上的最终建议解决方案。我主要关心的是如何将链接的“Where-Object”语句转换为我可以替换为“Get-ADUser”cmdlet 的变量。谢谢。
  • @WilliamLombard - 我怀疑我误解了你的问题......但W-O 脚本块可以像任何其他脚本块一样。使用适当的-and-or 运算符将每个测试放在一个脚本块中。

标签: windows powershell active-directory


【解决方案1】:

注意:此答案解决了所问问题,使用基于脚本块 ({ ... }) 的基于Where-Object 的通用解决方案 strong>,但在目前的情况下,基于Get-ADUser-Filter 参数的基于字符串 的解决方案可以有效地过滤,如图所示Thomas' answer 中的第二个命令更可取。


将表示条件的script blocks ({ ... }) 数组存储在变量中,并使用索引数组根据用户的 GUI 选择来选择应用哪些条件:

# All individual conditions to test, expressed as an array of script blocks.
# Note: No need for `-eq $true` to test Boolean properties, and
#       `-eq $false` is better expressed via the `-not` operator.
$blocks = 
  { $_.Enabled },
  { -not $_.PasswordNeverExpires },
  { $_.PasswordExpired }


# Select the subset of conditions to apply using AND logic, using 
# an array of indices, based on the GUI selections.
$indices = 0..2   # e.g., all 3 conditions (same as: 0, 1, 2)

Get-ADUser -Filter * -properties $propsAsArray | Where-Object { 
  # The following is equivalent to combining the conditionals of interest
  # with -and (AND logic):
  foreach ($block in $blocks[$indices]) { # Loop over selected conditionals
    if (-not (& $block)) { return $false } # Test, and return $false instantly if it fails.
  }
  $true # Getting here means that all conditions were met.
}

注意每个块是如何通过&call operator 执行的。

【讨论】:

    【解决方案2】:

    您可以通过用 连接每个条件来压缩多个 Where-Object 调用:

    Get-ADUser -Filter * -Properties $propsAsArray | Where-Object {(($_.Enabled -eq $true) -and ($_.PasswordNeverExpires -eq $false)) -and ($_.passwordexpired -eq $false)} | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"
    

    但正如 Olaf 在 cmets 中已经指出的那样,最好已经使用 Get-ADUser-Filter 参数。在那里,您可以使用类似的条件组合:

    Get-ADUser -Filter {((Enabled -eq $true) -and (PasswordNeverExpires -eq $true)) -and (passwordexpired -eq $false)} -Properties $propsAsArray | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"
    

    【讨论】:

    • 谢谢,但是如何将链接的“Where-Object”语句分配给一个变量,然后再将其替换回“Get-ADUser”cmdlet(然后生成报告)?根据帐户是否仍然启用但密码是否已过期等,会有很多变体。
    • 谢谢,我刚刚做了一个非常快速的尝试,它不会返回任何错误。传奇! :-)
    • 您可以将每个单选按钮设置存储在一个变量中并插入它们而不是$true$false。例如:((Enabled -eq $rbEnabled) -and (PasswordNeverExpires -eq $rbPasswordNeverExpires)) -and (passwordexpired -eq $rbpasswordexpired)
    • 很好,但顺便说一句:use of script blocks ({ ... }) as -Filter arguments 虽然很方便,但在概念上存在问题,可能会导致误解。但是,在这种情况下它会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 2017-03-30
    相关资源
    最近更新 更多