11

Maybe my reasoning is faulty, but I can't get this working.

Here's my regex: (Device\s#\d(\n.*)*?(?=\n\s*Device\s#|\Z))

Try it: http://regex101.com/r/jQ6uC8/6

$getdevice is the input string. I'm getting this string from the Stream/Output from a command line tool.

$dstate = $getdevice |
     select-string -pattern '(Device\s#\d(\n.*)*?(?=\n\s*SSD\s+|\Z))' -AllMatches |
     % { $_ -match '(Device\s#\d(\n.*)*?(?=\n\s*SSD\s+|\Z))' > $null; $matches[0] }
Write-Host $dstate

Output:

Device #0 Device #1 Device #2 Device #3 Device #4

Same output for the $matches[1], $matches[2] is empty.

Is there a way I can get all matches, like on regex101.com? I'm trying to split the Output/String into separate variables (one for Device0, one for Device1, Device2, and so on).

Update: Here's the Output from the command line tool: http://pastebin.com/BaywGtFE

3
  • Welcome to Stack Overflow, @Frankstar. Please put as much information as you can directly in the question. I got the regex from regex101 and put it here. (The links to regex101 are great though!). Commented Jul 19, 2014 at 0:12
  • Hello @aliteralmind ! I tryed my best - thank you for your update. Will keep that in mind for future questions. Commented Jul 19, 2014 at 8:22
  • See Also: How to capture multiple regex matches, from a single line, into the $matches magic variable in Powershell? Commented May 20, 2020 at 14:17

4 Answers 4

19

I used your sample data in a here-string for my testing. This should work although it can depend on where your sample data comes from.

Using powershell 3.0 I have the following

$getdevice | 
    select-string -pattern '(?smi)(Device\s#\d+?(.*?)*?(?=Device\s#|\Z))' -AllMatches | 
    ForEach-Object {$_.Matches} | 
    ForEach-Object {$_.Value}

or if your PowerShell Verison supports it...

($getdevice | select-string -pattern '(?smi)(Device\s#\d+?(.*?)*?(?=Device\s#|\Z))' -AllMatches).Matches.Value

Which returns 4 objects with their device id's. I don't know if you wanted those or not but the regex can be modified with lookarounds if you don't need those. I updated the regex to account for device id with more that one digit as well in case that happens.

The modifiers that I used

  1. s modifier: single line. Dot matches newline characters
  2. m modifier: multi-line. Causes ^ and $ to match the begin/end of each line (not only begin/end of string)
  3. i modifier: insensitive. Case insensitive match (ignores case of [a-zA-Z])

Another regex pattern thats works in this way that is shorter

'(?smi)(Device\s#).*?(?=Device\s#|\Z)'
Sign up to request clarification or add additional context in comments.

3 Comments

hi @Matt. this is the best answer for my question so far and it works like a charm with the test String i provided! Thank you !! anyway i have the same problem with the real-time Data (it look the same to me ...) i just get back the first line of the match. as example Device #0 Device #1
i think its something with the Line feed or carriage return. maybe i need too convert the output from the commandline tool / exe. my string is stored in here $getdevice = .\arcconf.exe getconfig $cid PD anyway the output looks the same
Just found the Solution. i piped the Output trough Out-Sting Example: $getdevice = .\arcconf.exe getconfig $cid PD | Out-String now its working.
7

With your existing regex, to get a list of all matches in a string, use one of these options:

Option 1

$regex = [regex] '(Device\s#\d(\n.*)*?(?=\n\s*Device\s#|\Z))'
$allmatches = $regex.Matches($yourString);
if ($allmatches.Count > 0) {
    # Get the individual matches with $allmatches.Item[]
} else {
    # Nah, no match
} 

Option 2

$resultlist = new-object System.Collections.Specialized.StringCollection
$regex = [regex] '(Device\s#\d(\n.*)*?(?=\n\s*Device\s#|\Z))'
$match = $regex.Match($yourString)
while ($match.Success) {
    $resultlist.Add($match.Value) | out-null
    $match = $match.NextMatch()
} 

2 Comments

ty for your help. anyway i cant get this to work with my data. The match array is always empty. will try too figure out whats wrong.
In option 1 I could not get anything using $allmatches.Item[1]. I could get the first capture group with $allmatches.Groups[1].Value though.
3

While it doesn't exactly answer your question, I'll offer a slightly different approach:

($getdevice)  -split '\s+(?=Device #\d)' | select -Skip 1

Just for fun,

$drives = 
($getdevice)  -split '\s+(?=Device #\d)' | 
select -Skip 1 |
foreach { $Stringdata = 
          $_.replace(' : ','=') -replace 'Device #(\d)','Device = $1' -Replace 'Device is a (\w+)','DeviceIs = $1'
          New-Object PSObject -Property  $(ConvertFrom-StringData $Stringdata)
          } 

$drives | select Device,DeviceIs,'Total Size'

Device                             DeviceIs                           Total Size                        
------                             --------                           ----------                        
0                                  Hard drive                         70007 MB                          
1                                  Hard drive                         70007 MB                          
2                                  Hard drive                         286102 MB                         
3                                  Hard drive                         286102 MB                

4 Comments

Excellent job converting the strings to a hash and nesting -replace thereby formatting it into a very versatile object. This showed me how to use PSObject and ConvertFrom-StringData
wow, didnt expect such a nice solution. anyway i get some erros with the "real time" Input/sring. pastebin.com/0uChjGa1. But its working with the sample Output/String i provided, so the answere is right. just need too figure out the problem and if i can continue work with that answere/solution. ty
as posted too Matts answer .. i piped the commandline Output trough Out-String and now the Output looks MUCH better and right. Anyway i got one error. ConvertFrom-StringData : Datenzeile " Device is an Enclosure services device" weist nicht das "Name=Wert"-Format auf. dont know how to get rid of it and i dont know whats different with Device is an Enclosure services device string.
sry for the comment spam - but i figured it out. its simple the replacement string, you searched for "Device is a" and in that special output its "Device is a n". Just adjusted the -replace and now its working finde. ty
2

try this variant:

[regex]::Matches($data,'(?im)device #\d((?!\s*Device #\d)\r?\n.)*?') | select value

Value
-----
Device #0
Device #1
Device #2
Device #3
Device #4

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.