Reputation: 77
I'm able to match the string I need for regex but it is matching twice.
https://regex101.com/r/KmgGwS/7
if ( $_.PSPath -match ("(?<=\::)(.*?)(?=\\)+")) {
$matches.Values
}
For example, the input string is something like:
'Microsoft.PowerShell.Security\Certificate::CurrentUser\Root\A43489159A520F0D93D032CCAF37E7FE20A8B419'
It expect it to get:
CurrentUser
With the current code, it gets that string twice:
CurrentUser CurrentUser
Upvotes: 0
Views: 137
Reputation: 439277
tl;dr
$Matches[0]
contains what your regex matched overall, $Matches[1]
contains what the 1st (and only) capture group (parenthesized sub-expression, (...)
) matched - in your case, both values happen to be the same.
Unless you need to explicitly enumerate the overall match as well as capture-group matches, don't use $Matches.Value
.
To enumerate capture-group values only, i.e. to enumerate all matches except the overall match, use:
# Enumerate all matches except the overall one (key 0)
$Matches.GetEnumerator().Where({ $_.Key -as [int] -ne 0 }).Value
The automatic $Matches
variable, in which PowerShell reflects the results of the most recent -match
operation[1], is a hashtable (System.Collections.Hashtable
):
Entry 0
($Matches[0]
) contains what the regex matched in full.
All other entries, if any, contain the substrings that capture groups (parenthesized subexpressions, (...)
) matched, with entry 1
representing the 1st capture group's match, 2
the 2nd, and so on.
If you use named capture groups (e.g. (?<foo>...)
, the entries use that name (e.g., $Matches['foo']
or, alternatively, $Matches.foo
).
If you use non-capturing groups ((?:...)
), they result in no entry in $Matches
.
(Similarly, look-around assertions - (?<=...)
, (?<!...)
, (?=...)
, and (?!...)
- do not result in entries.)
As for what you tried:
$Matches.Values
outputs a collection of the values of all entries in the hashtable, meaning the overall match (entry 0
) as well as any capture-group matches.
Since your regex contains a capture group that effectively captures the same as the regex as a whole, (.*?)
, $Matches.Values
outputs a collection of values that is the equivalent of array
'CurrentUser', 'CurrentUser'
, which, when output to the console, yields the result shown in the question.
Note that if you regex happens not to contain any capture groups, as suggested in sln's answer, $Matches.Values
may appear to return a single string, but in reality it returns an ICollection
instance that just happens to have only one element.
Now, that distinction between a single-element collection and a scalar may often be irrelevant in PowerShell, but it's something to be aware of, because there are cases where it matters.
[1] Caveats:
* If the regex didn't match at all, $Matches
isn't updated, so the previous value may linger.
* If the LHS of -match
is an array (collection), -match
acts as a filter, and $Matches
isn't updated.
Note that $Matches
is also set in the branch handlers of a switch -Regex
statement.
Upvotes: 1
Reputation:
What you're seeing is the match value and the
group 1 value. Both of which contain the same thing.
If you want to see only a single value, remove the capture group.
(?<= :: )
.*?
(?= \\ )
Or, like this (?<=::).*?(?=\\)
Upvotes: 0