regexpowershellazure-clipowershell-jobs

PowerShell - matching a regex against threadjob output works but doesn't populate $matches variable


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.)


Solution

  • 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: