Search for partial match in array

Hey!

Im trying to loop through an list of servers, an match if they resides in an array of Active Directory Organizational Units.
But im having some troubles with this, without doing an foreach inside my foreach object - which i would like to avoid.

The snippet is like this:

$ExcludedOUs = @(
    "OU=salary,OU=country1,OU=Servers,OU=Administration,DC=domain,DC=com"
    "OU=salary,OU=country2,OU=Servers,OU=Administration,DC=domain,DC=com"
    "OU=salary,OU=country3,OU=Servers,OU=Administration,DC=domain,DC=com"
    "OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com"
)
foreach ($WinServer in $WinServers) {
    #Confirm that the server actually exist in the AD, since the $WinServers list comes from multiple ADs
    $DistinguishedName = $(Get-ADComputer -Filter "Name -eq '$WinServer'").DistinguishedName
    IF ($DistinguishedName) {
        if ($DistinguishedName -in $ExcludedOUs) {
            $WinServer
        }
    }
}

The DistinguishedName for the servers are always longer than the OU, and can have several sub OUs under each of them - an example of an server DN could be:
“CN=Server1,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

“CN=Server1,OU=2017,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

I need to match if the DN is an exact match for the substring, since i would like to have the servers under this OU included:
OU=HR,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

OU=Compliance,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

I hope this makes sense, and that you can help me out of this struggle, before i go bald :slight_smile:
Thanks in advance!

Why that? What’s wrong with a nested loop if it does the job?

I’m not sure. Your explanation with the examples does not fit to the code you posted. Are you just looking for a particular part of the DN of the servers?

Hi Olaf,

Thanks for the fast reply.

In my head, an foreach inside an foreach is not the best solution - might be my OCD kicking in :slight_smile:

Im trying to exclude all servers, that are in one of those “base OUs”.
So i would like to find these servers:
“CN=Server1,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”
“CN=Server2,OU=2017,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”
“CN=Server3,OU=2019,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

But still include the servers, that is in these OUs:
OU=HR ,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

OU=Compliance ,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”

So i need the server substring DN to match against the $ExcludedOUs

Please, when you post code or sample data format it as code.
Thanks in advance.

I still cannot see any problem with that. Why don’t you try it at least? !!! :wink:

If it’s just that you could “outsource” the check to a small helper function. This way it wouldn’t look like a nested loop even if it is. :wink:

1 Like

@ksl28 - if I understood your posts correctly, you were matching DNs by criteria. Regular Expressions are an efficient way to parse strings for this purpose.

In the demo code below:

  • I create an array of DNs with included noise for testing the regex.
  • Store the match criteria in variable matchOUs.
  • Instantiate an ArrayList object to hold the results in memory.
  • Used a single foreach to iterate over the array and execute an if statement.

I do not have AD on my laptop. Therefore, I did not include the DN check in the code.

Demo Code

using namespace System.Collections;

$WinServers = @(“CN=Server1,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server2,OU=2017,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server3,OU=2019,OU=Navision,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server4,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server5,OU=yada1,OU=yada2,OU=yada3,OU=saladShooter,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Bob\, Billy,OU=Compliance,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Doe\, Jane,OU=Compliance,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server33,OU=HR,OU=country3,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server44,OU=HR,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server202,OU=HR,OU=country3,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server22,OU=HR,OU=country3,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server30019,OU=Extra,OU=HR,OU=country3,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Server313,OU=HR,OU=country3,OU=ExtraStuff2,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Smith\, John,OU=salary,OU=country4,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=Smith\, John,OU=salary,OU=country5,OU=Servers,OU=Administration,DC=domain,DC=com”,
“CN=BigWig\, BigWig,OU=Gold,OU=Partners,OU=Vendors,DC=domain,DC=com”);

$matchOUs = "^CN=Server(\d)+(?:`.+)?,OU=(\bsalary\b|\bHR\b|\bCompliance\b),OU=country[1-4],OU=Servers,OU=Administration,DC=domain,DC=com";

$results = [ArrayList]::new();

foreach ($i in $WinServers)
{
    if($i -match $matchOUs)
    {
        [void]$results.Add($i);
    }
}
cls
$results;

Results

If my eyes aren’t tricking me, then there should be 10 matches. Careful with CN=Server313~. That one threw me at first.

Remarks

Regex can reduce the amount of code and processing because of its compact nature. I can break down the match criteria if you’d like.

I also tested a for loop that used array indexing, but saw no gain in performance over foreach—both repeatedly measured at 2 milliseconds with Measure-Command on my laptop. There could be a greater time difference looping over larger sets.

Using a for loop

$results1 = [ArrayList]::new();
for ($i = 0; $i -lt $WinServers.Count; $i++)
{
    if($WinServers[$i] -match $matchOUs)
    {
        [void]$results1.Add($WinServers[$i]);
    }
}

See also

Regular expression syntax cheatsheet.