Find all deleted AD objects in the past 30 days


Currently, doing an AD clean up on my domain and now trying to generate a report on all deleted user objects or computer objects in the past 30 days or in the past 2 weeks and just not able to get it.

I can run this and it gives me ALL AD objects:
Get-ADObject -SearchBase “CN=Deleted Objects, DC=Contoso, DC=Com” -Filter {ObjectClass -eq “user”} -IncludeDeletedObjects -Properties * | ft CN,LastKnownParent,whenChanged -AutoSize

Interesting to note here also is that -Filter {ObjectClass -eq “user”} doesn’t seem to work. It also includes computer objects. Filtering for computer objects works just fine but not when I just filter for user.

So, the line I can’t get to work is this. I get no results:
Get-ADObject -SearchBase “CN=Deleted Objects, DC=Contoso, DC=Com” -Filter {ObjectClass -eq “user”} -IncludeDeletedObjects | Where-Object {$_.whenChanged -ge ((get-date).AddDays(-30)).Date} | ft CN,LastKnownParent,whenChanged -Autosize

Any suggestions? Thanks guys.

The result of {$_.whenChanged -ge ((get-date).AddDays(-30)).Date} might not in the form AD is giving you.

I mean, if it works without the Where clause, and the Where clause is the problem, that’d be my guess. Keep in mind that whenChanged comes over as a string, and what your expression is producing is likely being evaluated as a string. You probably need to make sure they’re both cast as dates.

So, if I take out the “where” clause:

Get-ADObject -SearchBase “CN=Deleted Objects, DC=Contoso, DC=Com” -Filter {(ObjectClass -eq “user”) -and ($_.whenChanged -ge ((get-date).AddDays(-30)).Date)} -IncludeDeletedObjects

This results in:
Get-ADObject : Variable: '’ found in expression: $.whenChanged is not defined.
At line:1 char:1

  • Get-ADObject -SearchBase “CN=Deleted Objects, DC=Contoso, DC=Com
  •   + CategoryInfo          : InvalidArgument: (:) [Get-ADObject], ArgumentException
      + FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Commands.GetADObject

I’m thinking I’m not formatting the query properly.

Yeah, that won’t work refactored that way. Your Where clause wasn’t the wrong idea, it’s the two values you were comparing weren’t dates. One string isn’t ever greater or equal to another string; you needed to cast both values as dates.

What you’ve done here is used $_ in a clause that’s being passed to AD. But $_ has no meaning there. It had meaning in your Where clause, because Where knows to look for $_, but it’s meaningless where you’ve used it now.

Also, AD stores whenChanged as a string. You can’t compare strings as if they were dates. AD can’t convert a string to a date in its head, so you’ll need to go about it the way you started - get the objects over, and then let PowerShell filter them, since PowerShell can convert strings to dates.

E.g., something LIKE (although perhaps not exactly this)

... | ForEach-Object { 
  [datetime]$wc = $_.whenChanged
  [datetime]$old = (get-date).AddDays(-30)
  if ($wc -ge $old) { Write $_ }

See, the idea is to convert whenChanged into a date, and then compare it to a date. Using ForEach instead of Where lets you break this down a bit, which I did solely for readability, so you could maybe see the general approach. You could definitely do this with Where also, it’d just look different.

This is assuming whenChanged is in a string format that PowerShell can recognize as a date and convert to a date.

So, I took it to another direction:

[datetime]$StartTime = “2/1/2015”
[datetime]$EndTime = “2/10/2015”
$GetDeleted = Get-ADObject -Filter {(isdeleted -eq $true) -and (name -ne “Deleted Objects”)} -includeDeletedObjects -property whenChanged,LastKnownParent | Where-Object {$.whenChanged -ge $StartTime -and $.whenChanged -le $EndTime} | sort whenChanged | ft Name,LastKnownParent,whenChanged
$GetDeleted | export-csv d:\deleted.csv -NoTypeInformation

I’m getting closer to what I’m looking for but still not quite there. So, this works but a couple of issues:

  1. Specifying ObjectClass -eq user doesn’t work so I did away with it. Is there to add it to this line?
  2. The formatting doesn’t allowed to export information to “out-gridview” or “export-csv”. Does this mean I have to create a report object?
  3. I’ve been playing with $formatenumerationlimit and can’t get the output to display the full Name or LastKnownParent path.

Any suggestions?

Get-ADUser (as opposed to Get-ADObject) only returns users. Would that work for what you want?

Otherwise, ObjectClass -eq “user” should work. If it isn’t, that might be an artifact of how AD is tracking objects in the Deleted Objects folder. I don’t know a way around that - I’d just use Where-Object to filter them out.

Once you format something, you’re done with it. See “The Big Book of PowerShell Gotchas.” There’s no way around that. I don’t know what a “Report Object” is; if your goal is to display a grid view, or export to CSV, then use Select-Object to select the properties you want. Format-Table is only when you want an on-screen table. If you don’t want an on-screen table, don’t use Format-Table. There’s a lot of under-the-hood subtleness with the format system; pick up Learn Windows PowerShell in a Month of Lunches if you’d like to start conquering that ;). But at least read the Gotchas book. It’s free - “Resources” menu right here on the site.

Once you stop using Format-Table, most of your display-related problems will go away.

Thanks Don!
I appreciate the help on this. I’ll check out “The Big Book of PowerShell Gotchas”.