Home > Blockchain >  PowerShell - matching a regex against threadjob output works but doesn't populate $matches vari
PowerShell - matching a regex against threadjob output works but doesn't populate $matches vari

Time:11-13

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.
  • Related