2

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

两种日期格式都不会失败,但它们不返回任何内容——查询只是显示为正在运行,但从不返回任何数据:

$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 
4

2 回答 2

4

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

注意:-Properties *我在下面简要提到它,但如果你能帮助它,你不想这样做。返回对象的所有静态属性可能会导致您所击中的 DC 上的负载过大。仅指定要返回的属性。有关更详细的说明,请参阅此答案底部的链接答案。


# 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了,因为在您的代码示例中没有以其他方式引用它。
  • $SomeDate1Interval与其他日期类型属性(例如LastLogonDate. 相反,它被定义为格式中的通用时间字符串yyyMMddHHmmss.Z并且采用 UTC,因此我们需要以这种方式格式化的时间戳,而不是依赖于ToString()a 的默认行为[DateTime]。如果我们不这样做,日期比较将不起作用。这是令人困惑的,因为 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变量。这可以在单行上,但为了便于阅读,我在这里将其设置为多行。

Get-ADComputer用适当的调用-Filter

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

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

这应该会为您提供所有在您希望的属性中指定的日期之后创建的内容,包括自定义ADComputers字段。$SomeDate1UnixCanonicalNameServicePrincipalNames


关于避免将目标转换DateTime广义时间格式的注意事项

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

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 属性有奇怪的行为,或者您只是想了解更多关于不同属性的信息,我建议您在OpenSpecsAD Schema文档中查找该属性。

另外,请参阅我的这个答案,其中详细介绍-Filter了 RSAT AD cmdlet 上的参数。

于 2021-09-08T18:22:34.023 回答
-2

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

get-adcomputer 的文档使用 -Filter 下的 Backus-Naur 表单中的脚本块显示。

另一种选择是生成GeneralizedTime(除了需要分钟、秒和时间段?)而不是包含时区的 Datetime。

$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
于 2021-09-08T18:05:42.583 回答