Lars Panzerbjrn
Lars Panzerbjrn

Reputation: 225

Azure devops Work Item types API returns string instead of JSON

When I try to get work item types via PowerShell, I get a string instead of the expected JSON. This is my PowerShell code:

$Token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($PAT)"))
$JsonContentType = 'application/json-patch+json'
$Header = @{Authorization = 'Basic ' + $Token;accept=$JsonContentType}
$BaseUri = "https://dev.azure.com/$($Organisation)/"
$Uri = $BaseUri + "$Project/_apis/wit/workitemtypes?api-version=5.1"
$Result = Invoke-RestMethod -Uri $uri -Method GET -Headers $Header
$Result

I also tried with the newer version 6.0, but it also returns a string instead of JSON. Other responses are fine, for example:

$Uri = "https://dev.azure.com/$($Organisation)/_apis/projects?api-version=5.1"
$Projects = Invoke-RestMethod -Uri $Uri -Method get -Headers $Header

This correctly returns JSON, or if I request a work item, I also get JSON.

I cannot figure out why this is...

Any ideas anyone?

Upvotes: 0

Views: 390

Answers (1)

danielorn
danielorn

Reputation: 6147

The Invoke-Rest-Method tries to return a PSCustomObject, which does not support properties without names and thus the conversion fail and you get the plain string back:

From Invoke-RestMethod fails to parse JSON response

The problem is that by default, Invoke-RestMethod tries to convert the json to a PSCustomObject. However, PSCustomObject doesn't support a property without a name. In your script, add -AsHashTable to get an object that supports this.

However, I think that a warning instead of an error may be better here and have the resulting object not contain that property by default.

Solution for Powershell 6 and above

You can convert the string yourself to a data structure that supports empty properties (like a hashtable). This can be done using the ConvertFrom-Json method as shown below

$Token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($PAT)"))
$Header = @{Authorization = 'Basic ' + $Token}
$BaseUri = "https://dev.azure.com/$($Organization)/"
$Project = "test"
$Uri = $BaseUri + "$Project/_apis/wit/workitemtypes?api-version=5.1"
$Result = Invoke-RestMethod -Uri $uri -Method GET -Headers $Header

# Check if type is string, then convert to a hashtable
if ($Result.GetType().Name -eq "String") {
    $jsonRes = ConvertFrom-Json -AsHashtable -InputObject $Result
} else {
    $jsonRes = $Result
}

$jsonRes

Solution for Powershell 5 and below

If you are using an older verison of powershell you will need to parse the string into a hashmap yourself or using a thrid party tool. (I am not aware of any built in cmdlet that does this at least).

One option could be to use the JavaScriptSerializer .NET class, which is done in the Poshstache module. The code is available on the link so you should be able to review it and possibly customize it to fit your needs

Upvotes: 1

Related Questions