0

I write powershell scripts and regex below to extract a block of text between the first line (Port Name Status Vlan Speed Type) and the last line (End Here)but it didn't work. If you have suggestion, please help! Thx

Running this script, it just returned the first line.

Function Find_Ports($String)

foreach ($File in $Files)
 {
    $Config = Get-Content $File
    $Port =  Select-String -Path $File -Pattern $String | Select - 
     ExpandProperty line | Select-Object -First 1


   if($Port)
     {
       $Port 
     } 
     Else
     {
        Write-Host "no port"
      }   

      }


       Find_Ports " (smi)^Port\s.+Name\s.+Status\s.+Vlan\s.+Duplex\s.+Speed\sType\r\n.*End\Here$"

Below is the text file

Port Name Status Vlan Duplex Speed Type Gi1/1 disabled 1 auto auto 10/100/1000-TX Gi1/2 disabled 1 auto auto 10/100/1000-TX Gi1/3 disabled 1 auto auto 10/100/1000-TX Gi1/4 disabled 1 auto auto 10/100/1000-TX Gi1/5 disabled 1 auto auto 10/100/1000-TX Gi1/6 disabled 150 auto auto 10/100/1000-TX Po1 connected trunk a-full a-1000 End Here

CBLT
  • 124
  • 1
  • 2
  • 10

1 Answers1

0

In your regex you use \s.+ where .+ will match any character except a newline. I think you mean matching 1+ whitespace characters which can be written as \s+ without the dot.

You are also escaping the \H which can just be H. You could also omit the case insensitive flag because the dot will match upper and lowercase characters.

Your regex could look like:

(?sm)^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType\r\n.*End Here$

Regex demo

Without using the option that the dot could match the newline, you could use:

^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType\r\n(?:.*\r\n)*?End Here$

That will match

  • ^ Assert the start of the string
  • Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType Match literally followed by 1+ whitespace characters but after Speed just a single whitespace character
  • \r\n Match CR + LF
  • (?: Non capturing group
    • .*\r\n Match any character except a newline followed by CR + LF
  • )*? Close non capturing group and repeat 0+ times non greedy
  • $ Assert the end of the string

Regex demo

The fourth bird
  • 154,723
  • 16
  • 55
  • 70
  • your regex worked on the regexstorm tester, but didn't not work in my PowerShell script. For some reason, the \r\n was not recognized as the carriage return and newline when I ran the code. I am assuming I use the .NET regex. Do you have any other tips? – CBLT Dec 28 '18 at 13:43
  • Try replacing `\r\n` with `(?:\r?\n|\r)+` for example `^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType(?:\r?\n|\r)+(?:.*(?:\r?\n|\r)+)*?End Here$` [demo](https://regex101.com/r/cdQ0Nr/1) – The fourth bird Dec 28 '18 at 13:44
  • so it would be like this ^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType(?:\r?\n|\r)+(?:.*(?:\r?\n|\r)+)*?End Here$ I ran it and it returned no port – CBLT Dec 28 '18 at 13:47
  • It worked perfectly on the RegexStorm site but not sure why the \r\n did not work when I run my Powershell script – CBLT Dec 28 '18 at 14:06
  • @Justin So you do get the match you are looking for using the regex? – The fourth bird Dec 28 '18 at 14:30
  • No, the regex statement didn't work when I ran it with Powershell script....It just return no port – CBLT Dec 28 '18 at 14:42
  • Is it possible to run your script in parts to see if the part with `elect-String -Path $File -Pattern $String` does select the right text? – The fourth bird Dec 28 '18 at 15:17
  • yes, if I run the script with "^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\s+Type" then it printed out Port Name Status Vlan Duplex Speed Type , but if I run the script with yes, if I run the script with ^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType(?:\r?\n|\r)+(?:.*(?:\r?\n|\r)+)*?End Here$ then it just returned no port Somehow, the script did not recognize the carriage return and continue to the next line until the End Here – CBLT Dec 28 '18 at 15:48
  • Are you sure [`Select-String`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-string?view=powershell-6) selects multiple lines? Perhaps you could try an approach using [Get-Content](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content?view=powershell-6) like on [this page](https://stackoverflow.com/questions/48171976/select-string-find-a-string-that-spans-multiple-lines) – The fourth bird Dec 28 '18 at 16:14
  • ok, so I tried this and printed out the next two line Port Name Status Vlan Duplex Speed Type Gi1/1 disabled 1 auto auto 10/100/1000-TX Gi1/2 disabled 1 auto auto 10/100/1000-TX if((Get-Content -raw $Files) -match '(?m)^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType(\r?\n\S|\Z).*(\r?\n\S|\Z).*') { $Unused_VLAN = Matches[0] if($Unused_VLAN -eq $Null) { Write-Host "No port" continue } else { Write-Host $Unused_VLAN}} – CBLT Dec 28 '18 at 16:47
  • '(?m)^Port\s+Name\s+Status\s+Vlan\s+Duplex\s+Speed\sType(\r?\n).*' matches the carriage return and return the next line. If I want it to return all the lines until it hits the End Here then I have to repeat the (\r\n).* many times . It does not continue on the next line by itself until it hits the End Here – CBLT Dec 28 '18 at 17:12
  • That is because you match only 1 line and at the end of the line match a newline followed by `.*` which matches all characters except a new line resulting in 2 lines. That is why you either have to use `(?sm)` to make the dot match the newline like the first regen in my answer, or use the second one where that is repeated and will match `End Here` – The fourth bird Dec 28 '18 at 17:32
  • You are welcome. Glad it works for you. Feel free to [mark the answer](https://stackoverflow.com/tour) as accepted if it helped solving your problem – The fourth bird Dec 28 '18 at 17:57