When I run the following script from a newly opened PowerShell console, the loop exits so there is clearly a match, but the $matches variable (and thus $matches.PORT) is not populated the first time around. When the script is run again, it is populated.
./ssh.ps1
$BLOCK = { az webapp create-remote-connection --subscription <MY-SUBSCRIPTION> --resource-group <RESOURCE-GROUP> -n <NAME> }
$global:CONNECTION = Start-ThreadJob -ScriptBlock $BLOCK
$done = 0
$match_string = ".*Opening tunnel on port: (?<PORT>\d{1,5})\b.*"
while ($done -lt 1) {
if ($CONNECTION.HasMoreData)
{
$DATA = Receive-Job $CONNECTION 2>&1
if ($DATA -match $match_string)
{
$port = $matches.PORT
Write-Output "Connection open on port $port."
$done = 1
}
}
}
Write-Output "Loop ended."
exit
Output in the PowerShell console is:
PS <LOCAL-DIR>> ./ssh
Connection open on port .
Loop ended.
PS <LOCAL-DIR>> ./ssh
Connection open on port 63182.
Loop ended.
By contrast, when I try running the following script, $matches is populated the first time it is run.
./match.ps1
$string1 = "hello, hello, you big beautiful world of wonder!"
$match_str = ".*\b(?<gotcha>world)\b.*"
$done = 0
while ($done -lt 1)
{
if ($string1 -match $match_str)
{
write-output "Matches:"
write-output $matches
$done = 1
}
}
Output:
PS <LOCAL-DIR>> ./match
Matches:
Name Value
---- -----
gotcha world
0 hello, hello, you big beautiful world of wonder!
If anyone can fathom why the text is matched in the first script without $matches being populated I would be incredibly grateful.
P.S. The script existing after the loop is just for investigative purposes and not what my code will actually do.
P.P.S.
For reference, the output from az webapp create-remote-connection
, after a delay whilst connecting, is:
Verifying if app is running....
App is running. Trying to establish tunnel connection...
Opening tunnel on port: 63341
SSH is available { username: root, password: Docker! }
Ctrl C to close
(The port varies each time.)
CodePudding user response:
If the automatic $Matches
variable isn't populated after a -match
operation, the implication is that the LHS operand was a collection rather than a single string.
Therefore, loop over the value of $DATA
and match each line individually:
foreach ($line in $DATA) {
if ($line -match $match_string)
{
$port = $matches.PORT
"Connection open on port $port."
$done = 1
break
}
}
By design:
$Matches
is only populated if the LHS is a string (scalar).- With a collection (array) as the LHS,
-match
- as many comparison operators do - acts as a filter and returns the (potentially empty) sub-array of matching elements. - Any prior
$Matches
value is preserved if either a given string-scalar-match
operation happens not to find a match or its LHS is a collection.