1
Get-ADUser -SearchBase "OU=Purgatory,DC=domain,DC=com" -Filter {'enabled -eq $false' -and 'whenChanged -lt $ChangeDate'}

I cant figure out how to filter by two traits. I want to filter by disabled users that are older than the $ChangeDate variable. If I filter just by 'enabled -eq $false', it works, and if I filter just by 'whenChanged -lt $ChangeDate' , it works. But if i use the -and to combine them, no luck.

colbyt
  • 497
  • 1
  • 5
  • 6

1 Answers1

1

Generally, you should avoid the use of script blocks ({ ... }) as -Filter arguments.

Ultimately, whatever is passed to the -Filter parameter is a string, and using { ... } only obscures that fact, because it falsely suggests that the enclosed expression is a piece of PowerShell code - it is not; it is a severely constrained, PowerShell-like language described in Get-Help about_ActiveDirectory_Filter

What muddies the waters is that the AD provider happens to recognize simple variable references (e.g., $ChangeDate) in the strings it ultimately receives (and use of { ... } effectively passes ... as a string literal), whereas any expression (e.g., $ChangeDate.Year) is not recognized.

  • Generally, the safest approach is to use expandable (interpolating) strings (double-quoted; "...") as -Filter arguments and "bake in" variable values; that is, PowerShell replaces the variable references with their values before the AD provider sees the string.

  • However, it's unclear how date values must be represented inside such a string in order to be recognized as such, so taking advantage of the variable interpretation offered by the AD provider happens to be the safest choice in this case (note the use of single quotes ('...'), which means that the string is passed as-is - PowerShell performs no interpolation):

Get-ADUser -SearchBase "OU=Purgatory,DC=domain,DC=com" `
  -Filter 'enabled -eq $false -and whenChanged -lt $ChangeDate'

Again, be aware that you're passing a string literal to -Filter, and that it is the AD provider interpreting the embedded variable references, which only works with simple variable references, not expressions.


As for what you tried:

{'enabled -eq $false' -and 'whenChanged -lt $ChangeDate'} is effectively passed by calling the .ToString() method on it, which passes everything between the { and } as-is.

That is, the cmdlet / AD provider sees
'enabled -eq $false' -and 'whenChanged -lt $ChangeDate'
as the string value, including the single quotes, which is not what you intended.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I'm trying to do this (with Get-ADComputer) where one of the filters needs to be `'OperatingSystem -like ""'`, where `` is a variable that may contain spaces, e.g. `"*windows 7*"`. I can use `'OperatingSystem -like $os'` and it works, but that's kind of scary since you're not really quoting the value of `$os`. However `'OperatingSystem -like "$os"'` returns no results and `'OperatingSystem -like ``"$os``"'` (markdown won't let me use single backticks there) throws a parsing error. How can I ensure that spaces in `$os` are safely quoted, or do I not need to worry about it? – mmseng Aug 05 '19 at 18:37
  • @mmseng: `'OperatingSystem -like $os'` works thanks to the AD provider's ability to recognize simple variable references. If you want to let PowerShell perform string interpolation up front, you must use `"..."`, not `'...'`: that is, use either `"OperatingSystem -like '$os'"` or `"OperatingSystem -like \`"$os\`""`. – mklement0 Aug 05 '19 at 20:44
  • That's fine for the single query of `$os`, but I can't see how you combine that with a date, which also needs to be quoted and safely interpreted by the AD provider, as you mentioned in your answer. That is, neither `"LastLogonTimeStamp -lt \`"$time\`" -and OperatingSystem -like \`"$os\`""`, nor `'LastLogonTimeStamp -lt "$time" -and OperatingSystem -like "$os"'` will work properly. – mmseng Aug 06 '19 at 21:23
  • @mmseng: To use date-time variables, you _must_ rely on the AD provider's variable access; whenever you do: use outer single-quoting (`'...'`) and do _not_ use embedded quoting around the operands: `'LastLogonTimeStamp -lt $time -and OperatingSystem -like $OSFilter'`, but remember that only simple variable references, not expressions with property access can be used. If you have follow-up questions, please create a new question post. – mklement0 Aug 06 '19 at 21:44