I'm developing Powershell scripts and .Net Regex to find pattern matching in the network device configuration using powershell and regex. I am having problem trying to extract a block of strings from the config file and also having problem to write regex statement to match the carriage return and the new line. Below is my example. I have a config file with information below that I want to extract
vlan no description ports 999 unused Gi1/2,Gi1/3, Gi1/4, Gi1/5, Gi1/6, Gi/7, Gi/8, Gi1/9 Gi1/0, Gi1/11, Gi1/12, Gi1/13, Gi1/14, Gi1/15, Gi1/16 Gi1/17, Gi1/18
Here is my code
$File = Get-content C:\config.txt
$Regex = "(?sm)(^999.*(\r\n\s+.*)"
$unused_ports = Select-String -path $File -Pattern $Regex
Write-host $Unused_ports
it only displays the first line
999 unused Gi1/2,Gi1/3, Gi1/4, Gi1/5, Gi1/6, Gi/7, Gi/8, Gi1/9
I also tried the following $Regex
$Regex = '(?m)(^999.*\s+Gi1/10.*)
$Regex = '(?m)(^999.*\r\n\s+Gi1/10.*)
But none of the regex statements I used extracted all the ports (3 lines)
I also used get-content c:\config.txt -raw
but this would display everything thing in the config file.
Really appreciate if someone can help to extract all three lines with port numbers and how to use carriage return and new line to match the new line.
Wiktor Stribiżew provided the crucial pointer in a comment on the question[1]
: You must use Get-Content -Raw
to read the file contents into a single string so your regex can match across lines:
if ((Get-Content -Raw C:\Config.txt) -match '(?ms)^999.*?(?=\r?\n\S|\Z)') {
$Matches[0] # automatic variable $Matches reflects what was captured
}
The regex needed some tweaking, too, including the use of non-greedy quantifier .*?
, as suggested by TheMadTechnician:
(?ms)
sets regex options m
(treats ^
and $
as line anchors) and s
(makes .
match \n
(newlines) too`.
^999.*?
matches any line starting with 999
and any subsequent characters non-greedily.
(?=\r?\n\S|\Z)
is a positive look-ahead assertion ((?=...)
) that matches either a newline (\r?\n
) followed by a non-whitespace character (\S
) - assumed to be the start of the next block - or (|
) the very end of the input (\Z
) - in effect, this matches either the end of the file or the start of the next block , but without including it in in the match recorded in $Matches
.
[1] Wiktor also suggests regex (?m)^999.*(?:\r?\n.*){2}
, which works well with the sample input, but is limited to blocks that have exactly 3 lines - by contrast, the solution presented here finds blocks of any length, as long as the non-initial block lines all have leading whitespace.