Send Patch request through Rest API in powershell and TFS2015 - powershell

Please find below request body I created in powershell with Patch method to create a bug in TFS. But not able to create a bug and gettign message that "TF401320: Rule Error for field Found In. Error code: Required, HasValues, InvalidEmpty.","typeName"..... I also attached error code here.
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$pass)))
function CreateJsonBody
{
$value = #"
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "TestBug"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.TCM.ReproSteps",
"value": "Our authorization logic needs to allow for users"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.Priority",
"value": "1"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.Severity",
"value": "2 - High"
}
]
"#
return $value
}
$json = CreateJsonBody
$uri = "http://xxx-xxxxx-006:8080/tfs/xxx/xxxxx/_apis/wit/workItems/"+"$"+"bug/?api-version=2.0"
Write-Host $uri
$result = Invoke-RestMethod -Uri $uri -Method Patch -Body $json -Credential
$credential -ContentType "application/json-patch+json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
But not getting response.
Below error is getting
{
"$id": "1",
"innerException": null,
"message": "TF401320: Rule Error for field Found In. Error code: Required, HasValues, InvalidEmpty.",
"typeName": "Microsoft.TeamFoundation.WorkItemTracking.Server.RuleValidationException, Microsoft.TeamFoundation.WorkItemTracking.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"typeKey": "RuleValidationException",
"errorCode": 600171,
"eventId": 3200
}
Please help me. I already write code to create bugs for another account but not able to do here.

Related

Associate Work Item With Current Build and attach file to work item using powershell

How i can Associate Work Item With Current Build and attach file json to work item using powershell ? I use Azure Devops Service and i have this script:
$connectionToken="<my_token>"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$url= 'https://dev.azure.com/{organization}/{project_name}/_apis/wit/workitems/$Task?api-version=6.0'
$body=#"
[
{
"op": "add",
"path": "/fields/System.WorkItemType",
"value": "Risk"
},
{
"op": "add",
"path": "/fields/System.Title",
"value": "Test"
},
{
"op": "add",
"path": "/fields/System.Tags",
"value": "test"
},
{
"op": "add",
"path": "/fields/System.Description",
"value": "test"
},
{
"op": "add",
"path": "/fields/Mitigation",
"value": "test"
},
{
"op": "add",
"path": "/fields/Risk",
"value": "1 - High"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Build.IntegrationBuild",
"value": `"{value}`"}]"
}
]
"#
Write-Host "$url"
$response= Invoke-RestMethod -Uri $url -ContentType "application/json-patch+json" -Body $body -headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
But link for associate with current build not work, and i cant find what i need to add to attach json file to work item from my Azure Pipeline
To attach a file, you have to upload the file (Upload a text file) and then add the link to your work item (Add an attachment): Attach a file and create new workitem
Microsoft.VSTS.Build.IntegrationBuild is just a field without any links. You have to add ArtifactLink link with Integrated in build type: Add build link to work item using REST API

Azure-Devops remove user from projectContributor via Rest API

Using PowerShell I am attempting to remove a user from groupType projectContributor so I can move him to the Project Team. I can accomplish the add to the Project Team however I have tried everything I can to remove this users entitlement using a PATCH without success. FYI to avoid comments, OrgUrl, projectId and userId are being passed.
$b= #"
[
{
"op": "remove",
"path": "/projectEntitlements",
"value": {
"projectRef": {
"id": "$projectID"
},
"group": {
"groupType": "projectContributor"
}
}
}
]
"#
$uri = "$orgURL/_apis/userentitlements/$userId`?api-version=5.1-preview.2"
Invoke-RestMethod -Uri $uri -ContentType "application/json-patch+json" -Body $b -Method PATCH -Headers #{ Authorization = ("Basic {0}" -f $base64AuthInfo)}
The error I am getting is this:
projectId","typeName":"System.ArgumentException, mscorlib","typeKey":"ArgumentException","errorCode":0,"eventId":0}
At line:20 char:1
+ Invoke-RestMethod -Uri $uri -ContentType "application/json-patch+json ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Any help / examples are appreciated.
I have gone through all the API documentation for Azure DevOps API.
I got the same error using User Entitlement rest api.
It worked for me with Remove Member From Group rest api.
DELETE https://vsaex.dev.azure.com/{organization}/_apis/GroupEntitlements/{groupId}/members/{memberId}?api-version=5.1-preview.1
When a user is added to a project as Project Contributors. This user will be added to group [ProjectName]\\Contributors of this Project.
You can then use Group List rest api to get the group id of [ProjectName]\\Contributors. The {memberId} of above Remove Member From Group api is user's userId. Then you can just call above api to remove the user from the project contributors group.
Please try this:
$b= #"
[
{
"op": "remove",
"path": "/projectEntitlements/$projectID",
"value": {
"projectRef": {
"id": "$projectID"
},
"group": {
"groupType": "projectContributor"
}
}
}
]
"#
And since you are removing value under this path I'm not sure if you need value, so this should provide you the same:
$b= #"
[
{
"op": "remove",
"path": "/projectEntitlements/$projectID",
"value": ""
}
]
"#

Invoke-RESTMethod PowerShell

I am trying to use the Invoke-Restmethod to call a set of API's, but it fails with the below error, i have also posted the same json format, can some let me know what could be wrong ?
### Ignore TLS/SSL errors
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#Create URL string for Invoke-RestMethod
$urlsend = 'https://' + 'vrslcm-01a.corp.local/lcm/api/v1/' + '/login'
#Credential
$Username = "admin#localhost"
$password = "VMware1!"
$basicAuth = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($Username):$Password"))
$headers = #{
"description"= "Testing Authentication"
}
$body = #{
$raw= '{\n\t\"username\": \"admin#localhost\",\n\t\"password\": \"vmware\"\n}'
"mode"= $raw
}
Invoke-RestMethod -Method POST -uri $urlsend -Headers $headers -Body $body -ContentType 'application/json'
Here is the sample jSON which iam trying to invoke via powershell, it consists of the header and the body. I need to understand how we could call the same jSON POSTMAN example via the PowerShell Invoke-RestMethod
"item": [
{
"name": "authorization",
"description": "",
"item": [
{
"name": "Login",
"event": [
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
"var response=JSON.parse(responseBody)",
"postman.setEnvironmentVariable(\"token\", response.token)"
]
}
}
],
"request": {
"url": "{{Server}}/lcm/api/v1/login",
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"description": ""
}
],
"body": {
"mode": "raw",
"raw": "{\n\t\"username\": \"admin#localhost\",\n\t\"password\": \"vmware\"\n}"
},
"description": ""
},
"response": []
},
{
"name": "Logout",
"request": {
"url": "{{Server}}/lcm/api/v1/logout",
"method": "POST",
"header": [
{
"key": "x-xenon-auth-token",
"value": "{{token}}",
"description": ""
}
],
"body": {},
"description": ""
},
"response": []
}
]
},
make $raw to a hashtable like
$raw = #{
username=$Username
password=$Password
}
add this hashtable to the $body hashtable
$body = #{
mode= $raw
}
but now it still is a hashtable the api cannot use. thus convert it to json like
$jsonBody = $body | ConvertTo-Json
using $jsonBody should then work when used like
Invoke-RestMethod -Method POST -uri $urlsend -Headers $headers -Body $jsonBody -ContentType 'application/json'
Like the error states, the problem is your hash definition.
A null key is not allowed in a hash literal.
PowerShell tries to evaluate $raw as a hash table key. Since it hasn't been defined before it is null and fails because null is not allowed. Try it like this:
$raw= '{\n\t\"username\": \"admin#localhost\",\n\t\"password\": \"vmware\"\n}'
$body = #{
"mode"= $raw
}

ForEach Invoke-RestMethod

I'm trying to make a request to the AccessPointsDetails endpoint of the Cisco Prime API and then loop through that to get all URL objects for the AccessPoints so I can get data on each of them.
I get the following output:
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3373245; $=3373245}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3413720; $=3413720}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3432295; $=3432295}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3432310; $=3432310}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3462672; $=3462672}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3497980; $=3497980}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3497993; $=3497993}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3512621; $=3512621}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3526872; $=3526872}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/16162527426; $=16162527426}
#type #url $
----- ---- -
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3373245 3373245
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3413720 3413720
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3432295 3432295
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3432310 3432310
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3462672 3462672
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3497980 3497980
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3497993 3497993
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3512621 3512621
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3526872 3526872
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/16162527426 16162527426
Here is the response JSON for one store as well:
{
"queryResponse": {
"#last": 9,
"#first": 0,
"#count": 10,
"#type": "AccessPointDetails",
"#requestUrl": "https://cpist/webacs/api/v3/data/AccessPointDetails?.group=0026",
"#responseType": "listEntityIds",
"#rootUrl": "https://cpist/webacs/api/v3/data",
"entityId": [
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3373245",
"$": "3373245"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3413720",
"$": "3413720"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3432295",
"$": "3432295"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3432310",
"$": "3432310"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3462672",
"$": "3462672"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3497980",
"$": "3497980"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3497993",
"$": "3497993"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3512621",
"$": "3512621"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3526872",
"$": "3526872"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/16162527426",
"$": "16162527426"
}
]
}
}
I feel I may be a bit burnt and making a silly oversight?
Solution Code (See Accepted Answer):
Function allAP {
Write-Verbose "Getting all APs for Store $Store"
$storeApReq = "https://cpist/webacs/api/v3/data/AccessPointDetails.json?.group=$Store"
Write-Verbose "Making request to $storeApReq"
$Global:apIdListReq = Invoke-RestMethod -uri $storeApReq -method Get -ContentType 'application/json' -headers #{ Authorization = $auth }
$Global:apIdList = $apIdListReq.queryResponse.entityId
$Global:apIdCount = $apIdListReq.queryResponse."#count"
Write-Verbose "Found $siteAPCount APs in Sites Database. $apIdCount out of $siteAPCount APs found."
Write-Verbose "Response Received: $apIdList"
$Global:apIdURL = $apIdListReq.queryResponse.entityId
$Global:apURL = $apIdUrl.'#url'
Write-Verbose "Starting a loop."
ForEach($apIdURL in $apIdList) {
Invoke-RestMethod -uri $apURL -method Get -ContentType 'application/json' -headers #{ Authorization = $auth }
Write-Verbose "Making request to: $apURL"
$apURL
}
}
The biggest issue you're having is accessing the members of your returned object incorrectly. The Invoke-RestMethod is returning a pscustomobject representation of the JSON the application returns to you. Your example JSON looked like this:
{
"queryResponse": {
"#last": 9,
"#first": 0,
"#count": 10,
"#type": "AccessPointDetails",
"#requestUrl": "https://cpist/webacs/api/v3/data/AccessPointDetails?.group=0026",
"#responseType": "listEntityIds",
"#rootUrl": "https://cpist/webacs/api/v3/data",
"entityId": [
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3373245",
"$": "3373245"
},
...
]
}
}
This gets transformed into pscustomobject:
[pscustomobject]#{
'queryResponse' = [pscustomobject]#{
'#last' = 9
'#first' = 0
'#count' = 10
'#type' = 'AccessPointDetails'
'#requestUrl' = 'https://cpist/webacs/api/v3/data/AccessPointDetails?.group=0026'
'#responseType' = 'listEntityIds'
'#rootUrl' = 'https://cpist/webacs/api/v3/data'
'entityId' = #(
[pscustomobject]#{
'#type' = 'AccessPointDetails'
'#url' = 'https://cpist/webacs/api/v3/data/AccessPointDetails/3373245'
'$' = '3373245'
}
...
)
}
}
I'm unsure why accessing .'#url' isn't working for you. Below is a working implementation of what you're trying to do.
function Get-AccessPoint
{
param
(
[Parameter(Position = 0, Mandatory)]
[ValidateNotNullOrEmpty()]
[string]
$Store
)
# function is accessing above-scope variables $auth and $siteAPCount
Write-Verbose "Retrieving APs for store $Store"
$uri = "https://cpist/webacs/api/v3/data/AccessPointDetails.json?.group=$Store"
Write-Verbose "Request: $uri"
$global:apIdListReq = Invoke-RestMethod -Uri $uri -ContentType application/json -Headers #{Authorization = $auth}
$global:apIdList = $apIdListReq.queryResponse.entityId
$global:apIdCount = $apIdListReq.'#count'
Write-Verbose "Found $siteAPCount APs in Sites Database. $apIdCount out of $siteAPCount APs found."
foreach ($entity in $apIdList)
{
Write-Verbose "Making request to $($entity.'#url')"
Invoke-RestMethod -Uri $entity.'#url' -ContentType application/json -Headers #{Authorization = $auth}
}
}

How do I create a bug in TFS using REST API in PowerShell?

I am trying to create a bug in TFS using REST API in PowerShell with the code below, but I'm unable to figure out how to fill the $Bug variable with names of those param's and data.
Param(
[string]$vstsAccount = "MyAccountName",
[string]$projectName = "ProjectName",
[string]$keepForever = "true",
[string]$user = "",
[string]$token = "Mytoken"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#$uri = "https://$($vstsAccount).visualstudio.com/$($projectName)/_apis/wit/workitems/$Bug?api-version=2.2"
$result = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
I could find a sample for C# here, but not for PowerShell. Any help would be appreciated.
Cheers
You need to create a JSON body to use the REST API to create a work item in PowserShell, and the Content-Type should be application/json-patch+json, also use PATCH method. See Create a work item for details.
You can reference below sample PowerShell script to create a bug:
Param(
[string]$baseurl = "http://server:8080/tfs/DefaultCollection",
[string]$projectName = "ProjectName",
[string]$keepForever = "true",
[string]$user = "username",
[string]$token = "token"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
function CreateJsonBody
{
$value = #"
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "0925Bug"
},
{
"op": "add",
"path": "/fields/System.AreaPath",
"value": "LCScrum"
},
{
"op": "add",
"path": "/fields/System.IterationPath",
"value": "LCScrum\\Sprint 1"
},
{
"op": "add",
"path": "/fields/System.Tags",
"value": "Tag0921;Tag0926;Tag0927;Tag0928"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.Activity",
"value": "Development"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Scheduling.Effort",
"value": "8"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.ValueArea",
"value": "Business"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.Severity",
"value": "3 - Medium"
},
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": "System.LinkTypes.Dependency-Forward",
"url": "http://server:8080/tfs/DefaultCollection/_apis/wit/workItems/324",
"attributes":
{
"usage": "workItemLink",
"editable": false,
"enabled": true,
"acyclic": true,
"directional": true,
"singleTarget": true,
"topology": "dependency"
}
}
},
{
"op": "add",
"path": "/relations/-",
"value":
{
"rel": "System.LinkTypes.Hierarchy-Reverse",
"url": "http://server:8080/tfs/DefaultCollection/_apis/wit/workItems/58",
"attributes":
{
"usage": "workItemLink",
"editable": false,
"enabled": true,
"acyclic": true,
"directional": true,
"singleTarget": false,
"topology": "tree"
}
}
}
]
"#
return $value
}
$json = CreateJsonBody
$uri = "$baseurl/$($projectName)/_apis/wit/workitems/"+"$"+"bug?api-version=2.2"
Write-Host $uri
$result = Invoke-RestMethod -Uri $uri -Method Patch -Body $json -ContentType "application/json-patch+json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}