System.Management.Automation.RemoteException
name: CLD:HYB_Z_BASIS_ADMIN_SUPER
description: Basis Administrator
readOnly:
roleReferences:
- roleTemplateAppId: it!b2455
roleTemplateName: AuthGroup_Administrator
name: AuthGroup_Administrator
- roleTemplateAppId: it!b2455
roleTemplateName: AuthGroup_BusinessExpert
name: AuthGroup_BusinessExpert
OK
I have above string, each line is delimited by CRLF. I am trying to extract and split below information into two rows delimited with "-" so I can get array of two rows but I am not getting correct result.
My code is:
$Myarray = $string -split "-"
- roleTemplateAppId: it!b2455
roleTemplateName: AuthGroup_Administrator
name: AuthGroup_Administrator
- roleTemplateAppId: it!b2455
roleTemplateName: AuthGroup_BusinessExpert
name: AuthGroup_BusinessExpert
CodePudding user response:
Use the System.Text.RegularExpressions.Regex.Matches()
method to extract multiple matches from a string:
$string = @'
System.Management.Automation.RemoteException
name: CLD:HYB_Z_BASIS_ADMIN_SUPER
description: Basis Administrator
readOnly:
roleReferences:
- roleTemplateAppId: it!b2455
roleTemplateName: AuthGroup_Administrator
name: AuthGroup_Administrator
- roleTemplateAppId: it!b2455
roleTemplateName: AuthGroup_BusinessExpert
name: AuthGroup_BusinessExpert
OK
'@
# Find all matches for the given regex and return the matched
# text (.Value) for each.
# Returns 2 three-line strings.
[regex]::Matches($string, '(?m)^- . \n. \n. ').Value
Note: The solution relies on a single, multi-line string as input. If you have an array of strings, join them with [Environment]::NewLine
first; e.g. $multilineString = 'foo', 'bar' -join [Environment]::NewLine
; you can also apply this technique to output captured from external programs - see the bottom section of this answer.
For a detailed explanation of regex (?m)^- . \n.
and the ability to experiment with it, see this regex101.com page.
Note:
- As of PowerShell 7.2,
-match
, PowerShell's regular-expression matching operator, only ever finds at most one match; the need to resort to a .NET API for multiple matches introduces significant complexity; GitHub issue #7867 proposes introducing a-matchall
operator to remedy that - while the proposal has been green-lit, no one has stepped up to implement it yet.
As for what you tried:
-split "-"
:
- tokenizes the entire string, so you'll get unrelated information that requires post-filtering
- excludes the
-
from the resulting tokens (since they act as the separators), which makes it harder to filter out the relevant tokens - doesn't limit the tokens to only their first 2 lines.
A solution using -split
, is possible, but requires additional use of -match
, which makes the solution both more complex and less efficient:
# Same output as above.
$string -split '(?m)(^- . \n. \n. )' -match '^- '
Enclosing the relevant part of the regex in (...)
, i.e. making it a capture group, causes -split
to include the group's matches in the tokens returned; -match '^- '
then filters out all tokens that do not start with -
, leaving only the 2 two-line strings of interest.