First of all—I feel like such a n00b to be posting this. It’s fair to say that I know a bit about PowerShell but, man, the world is so big and I certainly do not know it all. As I always say, if I didn’t learn something today, then I must be dead.
Ok, on to the learning. As you may have heard, I changed jobs recently. I now work at a 500-person insurance company with a 70-person IT staff. By far the smallest company I’ve ever worked for (following MCI, HP, IBM, The Home Depot). In this new job, I have to wear many hats, which should be no surprise to those of you who work in SMB! I think it’s great, actually, because I’m exercising my brain in ways it hasn’t been in ages. For example, I don’t know crap about Active Directory, at least relative to other aspects of Windows considering the amount of time that I’ve called myself a Windows admin. So when it came time for me to do some routine AD cleanup, I certainly had to learn a few things—which is a good thing to me.
The task ahead of me was that there were tons of stale AD computer accounts in our domain. (See, I call it a domain, that’s how old my AD knowledge is.) Normally, this doesn’t hurt anything, but in our case, we have an anti-virus app which allocates licenses automatically based on the computer objects! So we were wasting licenses on computers which didn’t exist, and that needed cleaning up.
Of course, my first thought was to do it with PowerShell. I already had the venerable Quest AD snap-in loaded, so I just ran a quick one-liner to make my list of potential accounts. This was the easy part.
$c = Get-QADComputer -InactiveFor 90
After doing some sanity ping checks to make sure this list was good, I went to delete the first one:
PS> $c | Remove-QADObject
Warning! Are you sure you want to delete this object: CN=foobar,DC=domain,DC=com? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): Remove-QADObject : The directory service can perform the requested operation only on a leaf object. At line:1 char:25 + $c | Remove-QADObject <<<< + CategoryInfo : NotSpecified: (:) [Remove-QADObject], DirectoryServicesCOMException + FullyQualifiedErrorId : System.DirectoryServices.DirectoryServicesCOMException,Quest.ActiveRoles.ArsPowerShell eObjectCmdlet
Oops, that didn’t work! Well, I did some research and found an old newsgroup post that says that computer objects are really containers and that in order to delete them, you have to use the DeleteTree switch. So, I tried that:
PS> $c | Remove-QADObject –DeleteTree
Warning! Are you sure you want to delete this object and its children: CN=foobar,DC=domain,DC=com? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): Remove-QADObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) At line:1 char:25 + $c | Remove-QADObject <<<< -DeleteTree + CategoryInfo : NotSpecified: (:) [Remove-QADObject], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,Quest.ActiveRoles.ArsPowerShellSnapIn.Cmdlets.RemoveO bjectCmdlet
Access denied! So, I tried an elevated shell. No help. Back to Google. I searched for “access denied remove-qadobject deletetree” and the third hit looked interesting. It was a section on working with computer objects in the book Active Directory Cookbook (awesome that google books does that). From reading this, I realized that somewhere in the permissions hierarchy, these computer objects had accidental deletion prevention enabled! Luckily, they had some PowerShell code that I quickly adapted to my situation:
PS> $c | Add-QADPermission -Account 'EVERYONE' -Rights 'Delete,DeleteTree' -ApplyTo 'ThisObjectOnly'
Ctrl Account Rights Source AppliesTo ---- ------- ------ ------ --------- Everyone Special Not inherited This object only Everyone Special Not inherited This object only Everyone Special Not inherited This object only
Plus 507 more lines just like that. And then, I tried again and…
PS> $c = Get-QADComputer -InactiveFor 90 PS> $c PS>
Success! I hope that this post that illustrates my learning process helps someone else who comes across the same situation.