获取在特定日期之后创建的所有 AD 计算机

Get all AD computers created after a certain date

我创建了下面的脚本来查找自特定日期以来创建的所有 Unix 计算机。它不会 return 一个错误,但它也不起作用。脚本中只使用了一个日期,但两种格式的结果相同。

两种日期格式都没有失败,但它们没有 return 任何东西 -- 查询只显示为 运行 但从来没有 return 任何数据:

$SomeDate1 = 'Wednesday, November 7, 2018 2:41:59 PM'
$SomeDate2 = '2018-11-07 14:41:59.000'

Get-ADComputer -Filter '*' -Properties *  | Where {$($PSitem.CanonicalName) -like '*Unix*'  -and  $($PSitem.whenCreated) -gt $SomeDate1 } |` 
        Select Name,OperatingSystem,OperatingSystemVersion,ipv4Address,Created,whenCreated,Deleted,whenChanged,Modified,Description,@{Label="ServicePrincipalNames";Expression={$_.ServicePrincipalNames -join ";" }},DisplayName,Location,DistinguishedName,DNSHostName 

这些广告过滤器往往是反复试验的。它们的工作原理并不完全明显。这对我有用,有一个 DateTime 变量、一个 ScriptBlock 过滤器和 Name 而不是 CanonicalName (“错误:传递了一个使用构造属性的过滤器”)。

get-adcomputer 的文档显示在 -Filter 下使用 Backus-Naur 形式的脚本块。

另一种方法是生成 GeneralizedTime(除了需要分钟、秒和句点?)而不是包含时区的日期时间。

$startdate = [datetime]'3/12/2018'

Get-ADcomputer -Filter {name -like '*computer*' -and 
  whencreated -gt $startDate} -property whencreated,canonicalname

使用字符串过滤器,$startDate 周围不能有额外的引号。整个表达式不能用双引号引起来。我在其他情况下看到过这项工作。

Get-ADcomputer -Filter "name -like '*computer*' -and 
  whencreated -gt '$startDate'" -property whencreated,canonicalname
# error or no result

日期不能是 DateTime 的字符串版本。

Get-ADcomputer -Filter "name -like '*computer*' -and 
  whencreated -gt '3/12/2018 12:00:00 AM'" -property whencreated,canonicalname
# no result

有效的字符串过滤器:

$startdate = [datetime]'3/12/2018'

# get string version of scriptblock
{ name -like "*computer*" -and whencreated -gt $startdate }.tostring()  
 name -like "*computer*" -and whencreated -gt $startdate

Get-ADcomputer -Filter 'name -like "*computer*" -and 
  whencreated -gt $startDate' -property whencreated,canonicalname

使用 -Filter 参数来执行此操作,但我们需要做一些工作才能以适合 whenCreated 的格式获取日期,因为它在 AD 模式中的定义不同比其他一些“日期”类型的属性。下面的代码将起作用,解释如下:

Note: I briefly mention it below but you do not want to do -Properties * if you can help it. Returning all of the static attributes for an object can cause undue load on the DC you are hitting. Only specify the properties you want to return. See my at the bottom of this answer for a more detailed explanation.


# Create a yyyMMddHHmmss.Z formatted date string in UTC
$SomeDate1= ( Get-Date 'Wednesday, November 7, 2018 2:41:59 PM' ).ToUniversalTime().ToString('yyyMMddHHmmss.Z')

# These are the properties we both want to return from AD and include in the final output
$propertiesToReturn =
  "Name",
  "OperatingSystem",
  "OperatingSystemVersion",
  "ipv4Address",
  "Created",
  "whenCreated",
  "Deleted",
  "whenChanged",
  "Modified",
  "Description",
  "DisplayName",
  "Location",
  "DistinguishedName",
  "DNSHostName"

# These are properties we need from AD but are not required directly in the final output
$additionalProperties =
  "CanonicalName",
  "ServicePrincipalNames"

# Define the computed property here for clarity
$spnComputedProperty = @{
  Label = "ServicePrincipalNames";
  Expression = {
    $_.ServicePrincipalNames -join ";"
  } 
}

# Obtain the target computer list and apply your select-object expression to it
Get-ADComputer -Filter "whenCreated -gt '${SomeDate1}'" -Properties ( $propertiesToReturn + $additionalProperties ) | Where-Object {
  $_.CanonicalName -match 'Unix'
} | Select-Object ( $propertiesToReturn + $spnComputedProperty )

现在,这里有很多变化,所以我将解释我做了什么以及为什么:


新变量和对现有变量的更改

  • 我省略了 $SomeDate2,因为您的代码示例中没有引用它。
  • $SomeDate1 未定义为 AD 架构中的 Interval 类型,这与 LastLogonDate 等其他日期类型属性不同。它被定义为格式为 yyyMMddHHmmss.Z 通用时间字符串 并且采用 UTC,因此我们需要以这种方式格式化的时间戳,而不是依赖默认的 ToString() [DateTime] 的行为。如果我们不这样做,日期比较将不起作用。这令人困惑,因为 RSAT AD Cmdlets 将此(和其他通用时间字符串)转换为本地化 DateTime 字符串,以便在数据最终 [=171] 时更容易进行 PowerShell 处理=]编辑。
    • 请注意,yyyMMddHHmmss.Z 不能直接转换回 DateTime 对象以供其他地方使用。
  • 为清楚起见,我将 return 从 Get-ADComputer
    Select-Object 定义为数组,并用我们只想从 AD 中 return 的元素定义另一个数组以进行进一步处理。它们分别是 $propertiesToReturn$additionalProperties。这使我们不必在多个地方重新定义这些属性,并允许我们避免昂贵的
    -Properties * 调用。
    • ServicePrincipalNames被包含在$additionalProperties下是因为要将属性值转化为字符串,所以我们不想在Select-Object中包含它的原始值。
    • CanonicalName 是计算的 属性,不能在 -Filter
      -LDAPFilter 中过滤。我们必须 return 并在本地处理此 属性,即使您不希望它出现在最终输出中。
    • $propertiesToReturn 下定义的某些 属性 名称无论如何都会被 return 编辑,但将它们包含在 -Properties 数组中也无妨。
  • 同样为了清楚起见,我将 Select-Object 的计算 属性 定义为 $spnComputedProperty 变量。这可以在一行中,但为了便于阅读,我在这里将其设为多行。

使用适当的 -Filter

调用 Get-ADComputer

现在我们的 属性 数组和日期字符串格式正确,我们终于可以调用
Get-ADComputer.

  • 我们可以使用 "whenCreated -gt '${SomeDate1}'" 过滤器字符串(做 而不是 使用 ScriptBlock-Filter) 到 return $SomeDate1.
  • 之后创建的所有 ADComputers
  • 通常我不建议使用 + 连接字符串或数组,但这是一个方便的例外,不太可能导致内存问题。对于 Get-ADComputer -Properties,我们提供 $propertiesToReturn$additionalProperties 作为单个数组。
    • 尝试使用语法 -Properties $propertiesToReturn, $additionalProperties 将导致类型不匹配错误。
  • 我已将您的 Where-Object 子句缩减为仅进一步过滤 CanonicalName。如上所述,CanonicalName 是一个计算属性,不能用
    -Filter-LDAPFilter 过滤,必须在此处完成。
    • 我还将 -like 更改为 -match 并从(技术上的正则表达式)表达式中删除了 * 但您可以将原始的 -like 子句与 globs 一起使用如果你愿意。
  • 最后,我们像之前一样将结果通过管道传输到 Select-Object,并执行与 Get-ADComputer -Properties 相同的连接技巧。但是,这次我们添加了 $spnComputedProperty

这应该为您提供在 $SomeDate1 中指定的日期之后创建的所有 ADComputersCanonicalName 中的 Unix 具有您想要的属性,包括自定义的 ServicePrincipalNames 字段。


关于避免将目标 DateTime 转换为 Generalized-Time 格式的注意事项

从技术上讲,您可以使用以下任一过滤器来避免需要将 DateTime 转换为使用 Generalized-Time 格式:

Get-ADComputer -Filter 'whenCreated -lt $SomeDate1'

# Double-quoted variant is useful if you have other variables which
# should be directly rendered as part of the -Filter string
Get-ADComputer -Filter "whenCreated -lt `$SomeDate1"

我避免提及这一点的原因是因为这种行为没有得到很好的理解或记录。 cmdlet 有一些魔法可以获取变量值,即使它不应该被呈现,因为它是一个文字字符串。由于人们对其了解甚少,并且不清楚什么规则集定义了 DateTime 是如何转换的(例如,规则是否根据属性和类型而改变,DateTimes 是否总是被转换为通用时间字符串?我们不知道) 我不推荐这种方法。

whenCreated 的行为在 AD Schema 文档中有详细记录,如果我从一开始就查阅这些内容,就会很清楚 -Filter 需要如何制作,而不是我为理解比较问题而经历的反复试验。文档链接如下。


其他资源

如果您在未正确过滤的 AD 属性上遇到奇怪的行为,或者您只是想了解更多关于不同属性的信息,我建议您在 OpenSpecs or the AD Schema 文档中查找该属性。

另请参阅 ,其中详细介绍了 RSAT AD cmdlet 上的 -Filter 参数。