PowerShell: Remove-ADComputer v. Remove-ADObject

So, as I mentioned the other day, we needed to do some major cleanup of defunct and orphaned computer accounts. Most computers that hadn't been logged in to in the last year needed to go. And there were a LOT of them! Certainly more than anyone wanted to try to do in the GUI. So, having found them, it was time to remove them, using:

$oneyear = (Get-Date).AddDays(-365)
Get-ADComputer -Filter {(LastLogonDate -lt $oneyear ) -AND ((Name -like "ws-*") -OR (Name -like "Desktop*") -OR (Name -like "XP-*"))} 
               -Properties LastLogonDate `
  | Remove-ADComputer -Confirm:$False -Verbose

And I started watching the deletions go by on the screen. Honestly, a fairly scary moment. Especially when I started to see some errors scroll by..

VERBOSE: Performing the operation "Remove" on target "CN=WS-DCOVENTRY-02,OU=\#Workstations,DC=Contoso,DC=com".
VERBOSE: Performing the operation "Remove" on target "CN=WS-VTAWARE-02,CN=Computers,DC=Contoso,DC=com".
VERBOSE: Performing the operation "Remove" on target "CN=WS-VIMALG-02,CN=Computers,DC=Contoso,DC=com".
VERBOSE: Performing the operation "Remove" on target "CN=WS-FHEMMATI-02,OU=\#Workstations,DC=Contoso,DC=com".
VERBOSE: Performing the operation "Remove" on target "CN=WS-BGL-ECOM,CN=Computers,DC=Contoso,DC=com".
Remove-ADComputer : The directory service can perform the requested operation only on a leaf object
At line:1 char:228
+ ... LogonDate | Remove-ADComputer 
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (CN=WS-BGL-ECOM,...C=Contoso,DC=com:ADComputer) [Remove-ADComputer], ADExce
    + FullyQualifiedErrorId : ActiveDirectoryServer:8213,Microsoft.ActiveDirectory.Management.Commands.RemoveADCompute

I ended up with about 15% of the computer accounts refusing to be removed with Remove-ADComputer. So I checked the man pages for Remove-ADComputer, and there were no additional parameters that would overcome it. Well, phooie!


OK, so time to haul out the seriously powerful tool, Remove-ADObject -Recursive. A word of warning here -- you can do some serious damage with this command.  First, I verified the cause of the failures -- the offending computer accounts had subsidiary objects that they probably shouldn't ever have had. OK, all that was before my time, but none of them were any longer relevant. So, now, my command needed to morph due to the somewhat more annoying syntax of Remove-ADObject. I couldn't just pipe the results of Get-ADComputer to it, I needed to return a list of objects and walk through them with a ForEach loop, like this:

$oneyear = (Get-Date).AddDays(-365)
$adFilter = {(LastLogonDate -lt $oneyear ) -AND ((Name -like "ws-*") -OR (Name -like "Desktop*") -OR (Name -like "XP-*"))} 

ForEach ($Computer in (Get-ADComputer -Filter $adFilter -Properties LastLogonDate)) {
     Remove-ADObject $Computer -Recursive -Confirm:$False -Verbose

And there go the last of the orphaned accounts! Notice, by the way, the use of a variable to hold the filtering criteria. This is a useful trick if you're iterating through a bunch of filters, or dealing with a fairly long and complicated one. You need to edit the variable with each iteration, but the actual command stays the same. Plus, IMHO, it makes the whole thing more readable.