I have a strange behavior when I perform a DevOps API request in Powershell to retrieve a Work Item with its relations. I found a bunch of other posts talking about this but I didn't find my scenario.
Some code to let you understand what I'm doing.
This is the wrapper around Invoke-WebRequest that I use for the API calls:
Function New-WebRequest {
[CmdletBinding()]
Param (
[ValidateNotNullOrEmpty()]
[ValidateSet("GET", "POST")]
[string] $Method = "GET",
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $ApiCall,
[ValidateNotNullOrEmpty()]
[string] $RequestBody,
[ValidateNotNullOrEmpty()]
[string] $RequestContentType = "application/json"
)
if($ApiCall -notmatch $REGEX_URL) {
Write-Error "The provided URL ($ApiCall) is not in the correct format"
Exit 1
}
try
{
Write-Debug "API Request Call: [$ApiCall]"
$Command = "Invoke-WebRequest
-Method $Method
-Uri `"$ApiCall`"
-UseBasicParsing
-Headers @{Authorization = `"Basic $ENCODED_PAT`"}
-ContentType $RequestContentType"
if($PSBoundParameters.ContainsKey("RequestBody") -and -not([string]::IsNullOrWhiteSpace($RequestBody))) {
Write-Debug "API Request Body: [$RequestBody]"
$Command += " -Body '$RequestBody'"
}
$Exec = [ScriptBlock]::Create($Command -Replace "\r\n")
$Response = & $Exec
$StatusCode = $Response.StatusCode
}
catch {
$StatusCode = $_.Exception.Response.StatusCode.value__
Write-Error "Error Occured: $_"
}
if ($StatusCode -eq 200) {
$ResponseBody = $Response.Content | ConvertFrom-Json
} else {
throw "API Call failed (Status code: $StatusCode)"
}
return $ResponseBody
}
This is the method I use to retrieve a work item:
Function Get-WorkItem {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[ValidatePattern("\d{5,6}")]
[string] $Id,
[ValidateSet("All", "None", "Fields", "Links", "Relations")]
[string] $Expand = "All",
[string[]] $Fields,
[switch] $IncludeUpdates
)
Write-Debug "Retrieving Work Item [$Id]..."
$ApiCall = "$API_BASE_URL/wit/workitems/$($Id)?"
$Params = @("`$expand=$Expand")
if($PSBoundParameters.ContainsKey("Fields")) {
if($Expand -ne "None" -or $Expand -ne "Links" ) {
Write-Error "The 'Fields' parameter can be used only if 'Expand' is 'None' or 'Links' as per API definition"
} else {
$Params += "fields=$($Fields -Join ",")"
}
}
$ApiCall = Add-APIPart -URL $ApiCall -Params $Params
$Body = New-WebRequest -ApiCall $ApiCall
if($PSBoundParameters.ContainsKey("IncludeUpdates")) {
$Call = "$API_BASE_URL/wit/workitems/$Id/updates"
$Updates = (New-WebRequest -ApiCall $Call).Value
}
return (?: { $null -eq $Updates } `
{ $Body } `
{ @{
Body = $Body;
Updates = $Updates;
} }
)
}
As you can see, the "$expand" parameter is "All" by default (even if I tried also "Relations").
The issue is that when printing out the response in Powershell, I don't have the "Relations" field at all:
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
fields NoteProperty System.Management.Automation.PSCustomObject fields=@{System.AreaPath=....; System.TeamProject=....; System.IterationPath=....
id NoteProperty int id=135215
rev NoteProperty int rev=39
url NoteProperty string url=https://dev.azure.com/nestle-globe/......./_apis/wit/workItems/135215
_links NoteProperty System.Management.Automation.PSCustomObject _links=@{self=; workItemUpdates=; workItemRevisions=; workItemComments=; html=; workItemType=; fields=}
But if I open the link inside my browser I can see it:
This is what I pass to the Web request:
DEBUG: Retrieving Work Item [135215]... DEBUG: API Request Call: [https://dev.azure.com/......./......../_apis/wit/workitems/135215?$expand=All&api-version=7.0]
I tried to pass different values to the "$expand" parameter of the REST API but it didn't make any difference. I also tried to remove the "-UseBasicParsing" switch in the Invoke-WebRequest but it didn't change anything.
From the response, it has API request call below:
https://dev.azure.com/......./......../_apis/wit/workitems/135215?$expand=All&api-version=7.0
Tried to put it directly in the Invoke-WebRequest
method, it will report error as below:
The $
in $expand
caused the error. Can use below format to fix:
+
to combine: $ApiCall = "https://dev.azure.com/{org}/{project}/_apis/wit/workitems/33223?$" + "expand=All&api-version=7.0"
%24
instead of $
: $ApiCall = "https://dev.azure.com/wadez0770/wadetest1/_apis/wit/workitems/33223?%24expand=All&api-version=7.0"
In addition, for the Invoke-WebRequest
response, you need to parse the json response:
$response = Invoke-WebRequest -Method GET -Uri $ApiCall -Headers $headers -ContentType $RequestContentType
# Parse the JSON response
$jsonResponse = $response.Content | ConvertFrom-Json
# Access the relations
$relations = $jsonResponse.relations
# Output the relations
$relations
Relations returned: