Match (part of) string to an array of (sub)strings

@cythraul - to answer to your comment regarding matching on a string without a loop, I believe $Matches may only return the first match encountered under this condition. I tried different strategies on a tab-delimited string to see if I could return multiple instances, but each time I only returned the first instance of the match—I even tested versions of the |Foreach-Object{$Matches} loop.

Therefore, I’m modifying a similar reply to meet your post. The output is a list of all array members that match the specified criteria. I tacked on a identity value for easy identification (i.e., “I pull the index of the table to use later”).

Procedure

  • The canonical names are stored in a array.
  • The search/ match criteria are stored in a variable that is formatted for regex matching.
  • A custom class object, CanonicalName, provides the blueprint for the data.
    • Preference: inside the class, CanonicalName($q1,$q2) is a constructor (ctor). I use ctors on small classes to keep loops clean.
  • An array list (uses the namespace declaration) object stores the results of the match.
  • A for loop iterates over an integer series and executes an if conditional.
  • The if conditional calls up the array member at the index matching the current iteration.
  • When true, a variable instantiates the CanonicalName class and the variable is added to the array list.

Regex is very efficient for matching (which -match performs). At first, regex was unintelligible to me, but a cheat sheet, a book, and practice has paid off.

Demo Code

using namespace System.Collections;

$canonicalNames = @("domain.com/Administration/country4/salary/Navision/Server1",
"domain.com/Administration/country3/salary/Navision/2017/Server2",
"domain3.com/SomethingElse/country2/salary/Navision/2019/Server3",
"domain.com/Administration/country2/salary/Server4",
"domain5.com/NotAdministration/country4/salary/saladShooter/yada3/yada2/yada1/Server5",
"domain.com/Administration/country2/Compliance/Bob, Billy",
"",
"domain2.com/Administration/country2/Compliance/Doe, Jane",
"domain.com/Administration/country4/HR/Server33",
"",
"domain5.com/Administration/country3/HR/Server11",
"domain.com/Administration/country2/HR/Server55",
"domain.com/Partners/Gold/BigWig, Senior",
"domain.com/Partners/Silver/BigWig, Junior")

$matchCriteria = "^domain.com/(\bAdministration\b|Partners(?=/\bGold\b))";

Class CanonicalName
{
    [int] $_id
    [string] $CanonicalName;

    CanonicalName($q1,$q2)
    {
        $this._id = $q1;
        $this.CanonicalName = $q2;
    }
}

$results = [ArrayList]::new();
for ($i = 0; $i -lt $canonicalNames.Count; $i++)
{
    if($canonicalNames[$i] -match $matchCriteria)
    {
        $x = [CanonicalName]::new($i,$canonicalNames[$i]);
        [void]$results.Add($x);
    }
}

cls
$results;

Match criteria

  • Item must begin with domain.com/.
  • Item must include the word Administration or Partners but only when the latter is followed by \Gold.

Preference: I use \b word boundaries to reduce the chance of character pattern matches.

Results

7 out of 14 items matched the criteria.

Remarks

Should you adapt the demo code for your own purposes, play around with the match criteria. For example, I set up the Partners only-when-followed-by \Gold to demonstrate the lookahead assertion. This patterning would not meet your domain.root/OU2 and domain.root/OU2/SubOU standard.

See also

Regular Expressions Cheatsheet