Closely related: Grabbing specific sections of a txt file via Powershell
If it's acceptable to read the entire file into memory first:
$regex = '(?ms)\A.*?^\[Servers\]\s*\r?\n(.*?)(?:\r?\n\[.*|(?:\r?\n)?\Z)'
$servers = (Get-Content -Raw file.txt) -replace $regex, '$1' -split '\r?\n'
Refactored into a simple function that accepts the input file and the name of the section of interest:
function get-SectionLines([string] $LiteralPath, [string] $SectionName) {
$regex = '(?ms)\A.*?^\[{0}\]\s*\r?\n(.*?)(?:\r?\n\[.*|(?:\r?\n)?\Z)' -f [regex]::Escape($SectionName)
(Get-Content -Raw -LiteralPath $LiteralPath) -replace $regex, '$1' -split '\r?\n'
}
$servers = get-SectionLines file.txt Servers
Explanation:
Get-Content -Raw
reads the entire file into memory as a single string.
-replace
then operates on that one multi-line string, using a regex (regular expression) to match the entire input string, with a capture group ((...)
) matching only the lines of interest, and replacing the entire string with just the capture group, effectively returning just the section's lines.
- Finally,
-split '\r?\n'
splits the extracted multi-line string into an array of lines.
Explanation of the regex:
Inline regex options (?sm)
turn on both the multi-line and the single-line option:
m
means that ^
and $
match the start and end of each line rather than the input string as a whole.
s
means that metacharacter .
matches \n
characters too, so that an expression such as .*
can be used to match across lines.
\A
matches the very start of the (multi-line) input, and \Z
the very end.
\r?\n
matches a single line break, both the CRLF and the LF variety.
(.*?)
is the capture group that (non-greedily) captures everything inside the section.
(?:\r?\n\[.*|(?:\r?\n)?\Z)
uses non-capturing groups ((?:...)
) to match everything after the section of interest, which can either be the start of the next section (a line break followed by a [
) or the end of the input file (either with or without a trailing line break).
Note that the regex matches the entire input string, and then replaces it with just the substring (range) of interest, captured in the 1st (and only) capture group ($1
).