Regardless of how you manage Active Directory (AD) day-to-day, every so often you'll probably need to perform bulks operations against AD. Whether you're searching for objects that meet particular criteria so you can take some action on them or modifying objects in bulk, the Active Directory module for Windows PowerShell is proving to be a worthy tool.
In PowerShell and Active Directory, I discussed how to load and access the Active Directory module, which is new to Windows Server 2008 R2 and Windows 7. Now I'll show you two examples of how to use the module to automate bulk operations in your environment.
Searching High and Low
One of the most common bulk operations is searching for AD objects that meet particular criteria—say the value of an attribute or the status of a computer account. Let's start exploring the Active Directory module by creating such a scenario.
Suppose I want to find all the disabled computer accounts in three organizational units (OUs) in my AD domain and move them to a temporary holding OU so I can dispose of them later. One way to do this is to create a list of OUs to search, find all the disabled computer accounts in those OUs, and move them as they're found. You might think it would be easier to search the entire domain, but providing a list of OUs reduces the number of objects to search and lets you experiment with providing input to PowerShell commands, which is useful to know how to do.
So, I first need a way to feed the OU names to PowerShell. One approach is to put the names in a comma-separated value (CSV) file, then use PowerShell's Import-CSV cmdlet to read in the names, storing them in a variable. This approach is good if you have a long list of items to feed to a command. However, since I want to search only three OUs, I'll use an array to store their names.
The OU names give PowerShell a place to start its search from, which is called the search base. The search base typically takes the form of an LDAP distinguished name (DN)—for example, OU=Marketing, DC=cpandl,DC=com—so that's what I'll store in my array. The following command creates my array of OUs to search:
$searchBase = "OU=Test,DC=cpandl,DC=com",
"OU=Sales,DC=cpandl,DC=com",
"OU=QA,DC=cpandl,DC=com"
(Although this command wraps here, you'd enter it all on one line. The same holds true for the other commands that wrap.) This command assigns the string array to the $searchBase variable. If you want to make sure that an array is created, run the command
$searchBase\[0]
PowerShell should return the first element in the array (OU=Test,DC=cpandl,DC=com).
Now I need a command that does the searching. For this particular task, I've chosen the Search-ADAccount cmdlet. The great thing about this cmdlet is that it has all the parameters I need to search for inactive computer accounts, so I don't have to build a complex LDAP filter. For example, to find all inactive computer accounts in a domain, I can simply run
Search-ADAccount
-AccountDisabled -ComputersOnly
Figure 1 shows an example of what the results will look like.
Finally, I need a command that moves the disabled computers to a holding OU. To perform the move, I'll use the Move-ADObject cmdlet, which lets you easily move an object or container from one place to another in AD. For example, the following command uses this cmdlet to move a disabled computer account to an OU called BitBucket:
Move-ADObject -Identity "CN=NT4,CN=Computers,DC=cpandl,DC=com"
-TargetPath
"OU=BitBucket,DC=cpandl,DC=com"
In this case, the -Identity parameter specifies the DN of the object I want to move (a workstation named NT4) and the TargetPath parameter specifies the DN of the OU I want to move the object to. It's as simple as that.
I now have all the pieces to perform the bulk search-and-move operation: I have the list of OUs, the command to find disabled computer accounts, and the command to move them. There are two ways to put them all together, depending on how comfortable you are with PowerShell.
The simplest approach is to search for inactive computer accounts in a single OU, then use PowerShell's built-in pipelining capability to pipe the results to the command that will move those accounts. This can be done with code such as
Search-ADAccount -AccountDisabled -SearchBase
"OU=SDM,DC=cpandl,DC=com" |
Move-ADObject -TargetPath
"OU=BitBucket,DC=cpandl,DC=com"
In this code, I use the Search-ADAccount cmdlet to search for disabled computer accounts in the SDM OU. I pipe the resulting list of disabled computer accounts to the Move-ADObject cmdlet, which will move those accounts to the BitBucket OU. Note that I didn't need to include the -Identity parameter for Move-ADObject because the pipeline takes care of passing the name of each disabled computer account without me explicitly stating it.
The limitation of this approach is that I have to type this command for each OU on my list. This is where my $searchBase array comes in handy. Using that array, I can write code to iterate through my OU list:
foreach ($ou in $searchBase) {Search-ADAccount -AccountDisabled
-ComputersOnly -SearchBase $ou |
Move-ADObject -TargetPath
"OU=BitBucket,DC=cpandl,DC=com"}
Let's look at what this code is doing. First, I use the ForEach-Object cmdlet (aliased to foreach) to iterate through my list of OU names, which is stored in $searchBase. For each OU in $searchBase, I call the Search-ADAccount cmdlet and tell it to look for disabled computer accounts in that OU. I then pipe the output to the Move-Object cmdlet, which moves them. The end result is that all disabled computer accounts in the three OUs are moved to the BitBucket OU.