Using PowerShell in Parallel with the Active Directory Cmdlets

Let’s continue our exploration of parallel processing with PowerShell by taking a look at the Active Directory cmdlets. I came across the scenario in an online forum, so let’s start with that and how it led to my experiments in parallelization.

The question was about the best way to search for certain computers, but exclude a location. This seems like a reasonable use case. For my test, I have computers in a development organizational unit,f and I don’t want them to show up in the results. You should also know that I am testing from a Windows 8.1 desktop running PowerShell 4.0.
Because the distinguished name contains the OU, you might think that the following expression would work:

​
But I get no results. Not even an error message. When I run into a situation like this, I try to simplify and test each component. I already know that the first part of the filter that grabs computers where the name starts with CHI works. So I try a number of variations on the second part, even trying to match case.
​
No change, no results, and no errors. For whatever reason, this approach will not work. Next, I try to filter on the canonical name, e.g. GLOBOMANTICS.local/Development/CHI-HV02.
​
I like to test for positive results to make sure it works before testing with –Notlike. But this also fails.
052915 1953 ParallelPow1
This means I don't think there is a way to do early filtering with Get-ADComputer for a location. Remember, I want to exclude an OU. Thus, it seems like I have no choice but to use Where-Object to exclude a location.
​
An advantage to using late filtering with Where-Object is that I can exclude multiple locations.
Using Where-Object to exclude multiple locations. (Image Credit: Jeff Hicks)
Using Where-Object to exclude multiple locations. (Image Credit: Jeff Hicks)
As much as I would prefer to have early filtering, sometimes you have no choice. But this is what led me to the next step. What if I could search multiple organizational units? The Get-ADComputer cmdlet, like others in the ActiveDirectory module, has a SearchBase parameter.
The SearchBase parameter. (Image Credit: Jeff Hicks)
The SearchBase parameter. (Image Credit: Jeff Hicks)
But the SearchBase parameter doesn't take an array, accept wildcards, or pipeline input. It's more than likely that you have computer accounts organized into several organizational units. For my demonstration, I want to limit my search to these OUs.
​
In a perfect world, I could do this:
​
But I can't.
052915 1953 ParallelPow4
The first alternative that comes to mind is to use ForEach.
​
This has effect of running the command once for each location. If the number of locations is small, this might not be too bad. But I'm still searching sequentially. In my mind, if Get-ADComputer could search all locations simultaneously, that should be better. I can try some of the techniques I explored in the previous article.

Let's see if a workflow helps.
​
The workflow takes a hashtable of parameters for Get-ADComputer so that it can be splatted. The workflow takes a second parameter for an array of search location. I probably could have added logic to test the $Params hashtable for –SearchBase, but I wanted to keep the code as simple as possible. The only parameter I need to pass in my example is for –Filter.
​
I'll run the workflow on the domain controller in hopes that it runs faster.
052915 1953 ParallelPow5
I will report that when testing, the workflow was slower than using ForEach. Perhaps I need a larger number of locations to search to justify the workflow overhead. I'll get all OUs in my domain except Development.
​
In my domain, this is 40 locations. Re-running the workflow with these locations works:
​
And took 12 seconds. However, this approach took about 300ms.
​
And using the ForEach enumerator was about the same.
​

From my testing, it would appear that the cmdlet alone searches a single location pretty quickly. I just need to construct a PowerShell expression to do process multiple locations. Because I want easy, I'm going to need a new tool. I'll show you that next time.