Where-Object multiple conditions not working

Viewed 1110

I am trying to get all the running builds (in progress) + with a template parameter in a specific definition. I am using Powershell@2 task in Azure DevOps to accomplish this but multiple conditions are not running using Where-Object. Below is the code:

$token = "123"
$organization = "foo"
$project = "abc"

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))

$ThisBuildDefinitionID = "8430"
[int]$ThisBuildID = "1571327"


$GET_BUILDS_BY_DEFINITION_URL = "https://azure.com/$organization/$project/_apis/build/builds?api-version=6.0&definitions=$ThisBuildDefinitionID"

do
{
    $GET_BUILDS_BY_DEFINITION_RESPONSE = ""
    try
    {
      $GET_BUILDS_BY_DEFINITION_RESPONSE = Invoke-RestMethod -Uri $GET_BUILDS_BY_DEFINITION_URL `
                                  -Method GET `
                                  -ContentType "application/json" `
                                  -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}
    }
    catch
    {
      continue
    }
    
    Write-Host $GET_BUILDS_BY_DEFINITION_RESPONSE.value
    
    [array]$runningBuilds = $GET_BUILDS_BY_DEFINITION_RESPONSE.value | Where-Object {"status" -eq "inProgress" -and "templateParameters.param1" -eq "myparam"}

    Write-Host "running builds count: " $runningBuilds.count
    if ($runningBuilds.count -gt 0) {
      [int]$currentRunningBuild = ($runningBuilds | Sort-Object -Property "Id")[0].Id
    }

    Write-Host "This Build ID: " $ThisBuildID
    Write-Host "Currently Running Build ID: " $currentRunningBuild
    Write-Host "Waiting..." 
    Write-Output ""
    Start-Sleep -Seconds 5
}
while($ThisBuildID -ne $currentRunningBuild)

Write-Host "Waiting Complete."
Write-Host "Starting Build: " $ThisBuildID
Start-Sleep -Seconds 5

Where-Object {"status" -eq "inProgress" -and "templateParameters.param1" -eq "myparam"} is the part where I am having issues as to what would be condition to get this running fine.

When I use only one single condition like Where-Object "status" -eq "inProgress", it works fine and gets me the builds in progress but I want to also include a template parameter condition

Can someone assist me what I am doing wrong?

PS: Credit to Devin Lambert's script in the visualstudio developer community.

1 Answers

Where-Object { "status" -eq "inProgress" -and "templateParameters.param1" -eq "myparam" }

You're comparing (distinct) string literals to each other, whereas you presumably mean to compare property values to string literals.

You need the automatic $_ variable to refer to the pipeline input object at hand inside a script block ({ ... }), which allows you to access its properties:

Where-Object { 
  $_.status -eq "inProgress" -and $_.templateParameters.param1 -eq "myparam" 
}

Note that Where-Object (and also ForEach-Object) alternatively supports simplified syntax, where you don't need a script block and where the use of $_ is implied, but this syntax is limited to:

  • a single conditional

  • non-nested property access.

Therefore, its use is not an option in your case.

Only the first -eq comparison, with its access to the immediate status property only could be expressed in simple syntax (as you show in your question):

# Equivalent of:
#    Where-Object { $_.status -eq 'inProgress' }
# 'status' binds positionally to the -Property parameter.
Where-Object status -eq 'inProgress'

By contrast, the nested property access would not work:

# !! Does NOT work as intended.
Where-Object templateParameters.param1 -eq 'myparam'

The reason is that templateParameters.param1, which positionally binds to the -Property parameter, is as a whole interpreted as the name of a single property.

While chaining multiple simple-syntax Where-Object calls may be worth it for syntactic convenience, in your case you'd have to chain a simple-syntax with a regular-syntax call, in which case you may as well stick with your original, single regular-syntax approach.

Related