使用 -Filter 参数来执行此操作,但我们需要做一些工作才能以适合 whenCreated 的格式获取日期,因为它在 AD 架构中的定义与其他一些“日期”不同类型属性。下面的代码将起作用,解释如下:
注意:我在下面简要提到它,但如果你能提供帮助,你不想这样做-Properties *。返回对象的所有静态属性可能会导致您所击中的 DC 上的负载过大。仅指定要返回的属性。有关更详细的说明,请参阅此答案底部的linked answer。
# 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 格式的Generalized-Time 字符串,并且是UTC,因此我们需要以这种方式格式化的时间戳,而不是依赖@ 的默认ToString() 行为987654335@。如果我们不这样做,日期比较将不起作用。这很令人困惑,因为 RSAT AD Cmdlet 将将此(和其他通用时间字符串)转换为本地化的 DateTime 字符串,以便在最终返回数据时更轻松地进行 PowerShell 处理。
- 请注意,
yyyMMddHHmmss.Z 不能直接转换回 DateTime 对象以在其他地方使用。
- 为了清楚起见,我已经定义了从
Get-ADComputer 返回的公共属性和
Select-Object 作为一个数组,并定义了另一个数组,其中包含我们只想从中返回的元素AD 进行进一步处理。它们分别是$propertiesToReturn 和$additionalProperties。这使我们不必在多个地方重新定义这些属性,并允许我们避免代价高昂的
-Properties * 调用。
-
ServicePrincipalNames 包含在$additionalProperties 下,因为您想将属性值转换为字符串,所以我们不想将它的原始值包含在Select-Object 中。
-
CanonicalName 是一个计算属性,不能在-Filter 或
-LDAPFilter 中过滤。我们必须在本地返回并处理此属性,即使您不希望它出现在最终输出中。
- 在
$propertiesToReturn 下定义的一些属性名称无论如何都会返回,但将它们包含在-Properties 数组中并没有什么坏处。
- 另外,为了清楚起见,我将
Select-Object 的计算属性定义为$spnComputedProperty 变量。这可以在单行上,但为了便于阅读,我在此处将其设置为多行。
用正确的-Filter 调用Get-ADComputer
现在我们的属性数组和日期字符串格式正确,我们终于可以调用
Get-ADComputer。
- 我们可以使用
"whenCreated -gt '${SomeDate1}'" 过滤字符串(不要不使用ScriptBlock 和-Filter)返回在$SomeDate1 之后创建的所有ADComputers .
- 通常我不建议使用
+ 连接字符串或数组,但这是一个方便的例外,不太可能导致内存问题。对于Get-ADComputer -Properties,我们将$propertiesToReturn 和$additionalProperties 作为单个数组提供。
- 尝试使用语法
-Properties $propertiesToReturn, $additionalProperties 将导致类型不匹配错误。
- 我已将您的
Where-Object 子句缩减为仅进一步过滤CanonicalName。如上所述,CanonicalName 是一个计算属性,不能使用
-Filter 或-LDAPFilter 进行过滤,必须在此处完成。
- 我还将
-like 更改为-match 并从(技术上的正则表达式)表达式中删除了*,但如果您愿意,您可以将原始-like 子句与glob 一起使用。
- 最后,我们像以前一样将结果通过管道传输到
Select-Object,并执行与Get-ADComputer -Properties 相同的连接技巧。但是,这次我们添加了$spnComputedProperty。
这应该为您提供在$SomeDate1 中指定的日期之后创建的所有ADComputers,CanonicalName 中的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 或 AD Schema 文档中查找该属性。
另外,请参阅 this answer of mine,其中详细介绍了 RSAT AD cmdlet 上的 -Filter 参数。