Use the -Filter
parameter to do this, though we'll need to do some legwork to get the date in a format appropriate for whenCreated
, as it is defined differently in the AD schema than some other "Date" type attributes. The code below will work, explanation is below it:
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 linked answer 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 )
Now, there are a lot of changes here, so I'll explain what I've done and why:
New variables and changes to existing ones
- I've omitted
$SomeDate2
since it was not referenced otherwise in your code sample.
$SomeDate1
is not defined as an Interval
type in the AD schema, unlike other date-type properties such as LastLogonDate
. It is instead defined as a Generalized-Time string in the format yyyMMddHHmmss.Z
and is in UTC, so we need the timestamp formatted in this way rather than rely on the default ToString()
behavior of a [DateTime]
. If we don't do this, the date comparison will not work. This is confusing because the RSAT AD Cmdlets will convert this (and other Generalized-Time strings) to a localized DateTime
string for easier PowerShell processing when the data is ultimately returned.
- Note that
yyyMMddHHmmss.Z
cannot be directly converted back into a DateTime
object for use elsewhere.
- For clarity, I've defined the common properties to return from
Get-ADComputer
and
Select-Object
as an array, and defined another array with the elements we only want to return from AD for further processing. These are $propertiesToReturn
and $additionalProperties
, respectively. This prevents us from having to redefine these properties in multiple places, and allows us to avoid the costly
-Properties *
invocation.
ServicePrincipalNames
is included under $additionalProperties
because you want to transform the attribute value to a string, so we don't want to include the original value of it in Select-Object
.
CanonicalName
is a computed property, and cannot be filtered on in either -Filter
or
-LDAPFilter
. We must return and process this property locally, even though you don't want it in the final output.
- Some property names defined under
$propertiesToReturn
are returned regardless but it does not hurt to include them in the -Properties
array.
- Also for clarity, I've defined your computed property for
Select-Object
as the $spnComputedProperty
variable. This can be on a single line but I've made it multiline here for readability.
Invoking Get-ADComputer
with a proper -Filter
Now that we have our property arrays and date string formatted correctly, we can finally call
Get-ADComputer
.
- We can use the
"whenCreated -gt '${SomeDate1}'"
filter string (do not use a ScriptBlock
with -Filter
) to return all ADComputers
created after $SomeDate1
.
- Normally I don't recommend concatenating strings or arrays using
+
but this is a convenience exception where it's unlikely to cause memory issues. For Get-ADComputer -Properties
we provide $propertiesToReturn
and $additionalProperties
as a single array.
- Trying to use the syntax
-Properties $propertiesToReturn, $additionalProperties
will result in a type mismatch error.
- I have reduced your
Where-Object
clause to only further filter on CanonicalName
. As mentioned above, CanonicalName
is a computed attribute and cannot be filtered on with
-Filter
or -LDAPFilter
and must be done here.
- I have also change
-like
to -match
and removed the *
from the (technically regex) expression but you could use your original -like
clause with the globs if you prefer.
- Finally, we pipe the result to
Select-Object
as you did before, and do the same concatenation trick we did with Get-ADComputer -Properties
. However, this time we add $spnComputedProperty
instead.
This should give you all ADComputers
created after the date specified in $SomeDate1
with Unix
in the CanonicalName
with the properties you wished, including the customized ServicePrincipalNames
field.
Note about avoiding converting the target DateTime
to the Generalized-Time format
Technically speaking, you can use either of the following filter to avoid needing to convert your DateTime
to the use the Generalized-Time format:
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"
The reason I avoided mentioning this is because this behavior is not well understood or documented. There is some magic which the cmdlet does to get the variable value even though it should not be rendered as it is a literal string. As it's poorly understood, and is unclear what ruleset defines how the DateTime
is transformed (e.g. do the rules change per attribute and type, do DateTimes
always get converted to a Generalized-Time string? We don't know) I don't recommend this approach.
The behavior of whenCreated
is well documented in the AD Schema docs, and had I consulted these from the get go it would have been clear how the -Filter
needed to be crafted, rather than the trial-and-error I underwent to understand the comparison issue. Documentation links are below.
Additional Resources
If you get strange behavior on AD attributes not filtering correctly, or you just want to understand more about different attributes, I suggest looking the attribute up in OpenSpecs or the AD Schema documentation.
Also, see this answer of mine which goes into great detail about the -Filter
parameter on the RSAT AD cmdlets.