Does create service endpoint work? REST method fails, CLI Hangs - azure-devops-rest-api

I am trying to create a service endpoint (aka service connection) in Azure DevOps. I first attempted to use the DevOps CLI but this method hangs. Using az devops as shown below.
az devops service-endpoint azurerm create --name “Azure subscription 1 endpoint” --azure-rm-service-principal-id $serviceprincipleid --azure-rm-subscription-id $subscriptionid --azure-rm-tenant-id $tenantid --azure-rm-subscription-name $serviceprinciplename --organization $organization --project $project
Hangs till i restart PowerShell
I suspect the logged in account doesn't have access?? IDK. And there's no way to specify a personal access token which is what I need anyway.
I then turned my attention towards calling the DevOps REST method using a Personal Access Token (PAT) to authenticate. I'm using the documentation from this sample
Here is the basic code in PowerShell
$body = '{
"data": {
"subscriptionId": "1272a66f-e2e8-4e88-ab43-487409186c3f",
"subscriptionName": "subscriptionName",
"environment": "AzureCloud",
"scopeLevel": "Subscription",
"creationMode": "Manual"
},
"name": "MyNewARMServiceEndpoint",
"type": "AzureRM",
"url": "https://management.azure.com/",
"authorization": {
"parameters": {
"tenantid": "1272a66f-e2e8-4e88-ab43-487409186c3f",
"serviceprincipalid": "1272a66f-e2e8-4e88-ab43-487409186c3f",
"authenticationType": "spnKey",
"serviceprincipalkey": "SomePassword"
},
"scheme": "ServicePrincipal"
},
"isShared": false,
"isReady": true,
"serviceEndpointProjectReferences": [
{
"projectReference": {
"id": "c7e5f0b3-71fa-4429-9fb3-3321963a7c06",
"name": "TestProject"
},
"name": "MyNewARMServiceEndpoint"
}
]
}' | convertto-json | convertfrom-json
$bo = $body | convertfrom-json
$bo.data.subscriptionId = $subscriptionid
$bo.data.subscriptionName = "subscription name"
$bo.name = $serviceprinciplename
$bo.authorization.parameters.tenantid = $tenantid
$bo.authorization.parameters.serviceprincipalid = $serviceprincipalid
$bo.authorization.parameters.serviceprincipalkey = $serviceprincipalkey
$bo.serviceEndpointProjectReferences = #{}
$readybody = $bo | convertto-json -Depth 100
#POST https://dev.azure.com/{organization}/_apis/serviceendpoint/endpoints?api-version=6.0-preview.4
function createazurermserviceendpoint($body, $pat, $org, $project)
{
#POST https://dev.azure.com/{organization}/_apis/serviceendpoint/endpoints?api-version=6.0-preview.4
$requestpath = "/_apis/serviceendpoint/endpoints?api-version=6.0-preview.4"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$pat"))
$uribase = "https://dev.azure.com/" + $org
$uri = $uribase+$requestpath
$authheader = "Authorization=Basic " + $token
$result = az rest --method post --uri $uri --headers "Content-Type=application/json" $authheader --body $body | convertfrom-json
return $result
}
$result = createazurermserviceendpoint $readybody $pat $org $project
The method throws a Bad Request exception as shown below
az : Bad Request({"$id":"1","innerException":null,"message":"TF400898: An Internal Error Occurred. Activity Id:
10a098a9-b4b5-4def-8356-307a5cad0579.","typeName":"Newtonsoft.Json.JsonReaderException,
Newtonsoft.Json","typeKey":"JsonReaderException","errorCode":0,"eventId":0})
So, i went into the UI with fiddler and captured both an automated and manual create service endpoint believing the contract would be the same. I'm not certain it is. The resulting json body from the API is shown below. When I attempt to pass this through the script I get the exact same error as above for both of them. None of the json is like the other; I started with the sample json structure in the article mentioned above. Now I'm not certain what the issue is at all.
#hack a version from fiddler to try it
#fiddler body capture from automated service connection
$readybody = '{"authorization":{"parameters":{"tenantid":"xxxxxxxx-34e9-4306-ac1a-5f28c1d08fb1","serviceprincipalid":"","serviceprincipalkey":"","authenticationType":"spnKey"},"scheme":"ServicePrincipal"},"createdBy":{},"data":{"environment":"AzureCloud","scopeLevel":"Subscription","subscriptionId":"yyyyyyyy-75c4-4dfd-bdd5-c8c42d1a5dd0","subscriptionName":"Azure subscription 1.1","creationMode":"Automatic","appObjectId":"","azureSpnPermissions":"","azureSpnRoleAssignmentId":"","spnObjectId":""},"isShared":false,"name":"Azure sub 1.1 test","owner":"library","type":"azurerm","url":"https://management.azure.com/","administratorsGroup":null,"description":"","groupScopeId":null,"operationStatus":null,"readersGroup":null,"serviceEndpointProjectReferences":[{"description":"","name":"Azure sub 1 test","projectReference":{"id":"zzzzzzzz-fad9-427f-ad6c-21f4ae2d311f","name":"Connected2someone"}}]}'
$result = createazurermserviceendpoint $readybody $pat $org $project
Fails the same way
#fiddler body capture from manual service connection
$readybody = '{"dataSourceDetails":{"dataSourceName":"TestConnection","dataSourceUrl":"","headers":null,"resourceUrl":"","requestContent":null,"requestVerb":null,"parameters":null,"resultSelector":"","initialContextTemplate":""},"resultTransformationDetails":{"callbackContextTemplate":"","callbackRequiredTemplate":"","resultTemplate":""},"serviceEndpointDetails":{"administratorsGroup":null,"authorization":{"scheme":"ServicePrincipal","parameters":{"serviceprincipalid":"xxxxxxxx-65b2-470d-adc7-c811fc993014","authenticationType":"spnKey","serviceprincipalkey":"{a key}","tenantid":"yyyyyyy-34e9-4306-ac1a-5f28c1d08fb1"}},"createdBy":null,"data":{"environment":"AzureCloud","scopeLevel":"Subscription","subscriptionId":"zzzzzzzz-75c4-4dfd-bdd5-c8c42d1a5dd3","subscriptionName":"azure test 2 ","creationMode":"Manual"},"description":"","groupScopeId":null,"name":"azure test 2 connection","operationStatus":null,"readersGroup":null,"serviceEndpointProjectReferences":null,"type":"azurerm","url":"https://management.azure.com/","isShared":false,"owner":"library"}}'
$result = createazurermserviceendpoint $readybody $pat $org $project
Fails the same way.
Can someone confirm the REST API works? what version of the API is specified and does the body json look like what I posted?

I did a test with your PowerShell script and got the same error you did.
Then I switched to another PowerShell script with the same body, and it worked.
Here is my script:
$pat = "{PAT}"
$pat = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
$url="https://dev.azure.com/{organization}/_apis/serviceendpoint/endpoints?api-version=6.0-preview.4"
$body = #'
{
body
}
'#
$head = #{ Authorization =" Basic $pat" }
Invoke-RestMethod -Uri $url -Method Post -Headers $head -Body $body -ContentType application/json
So the cause of the error may be your PowerShell script (probably az rest) and not the REST API request body. You can try out the PowerShell script I've provided.
By the way:
You can sign in Azure DevOps CLI with a PAT. Please click this document for detailed information.

Related

Update customfield in JIRA using REST API without CURL

I am new to working with PowerShell and trying to use JIRA's Rest API (without cURL-command) to update certain custom field like "Description".
But I can not get the right way.
Below is my code:
$body = {"update":
{"customfield_17526":
[
{
"set":
[
{ "description": "trying to use JIRA's Rest API to update custom field" }
]
}
]
}
}
Invoke-RestMethod -uri $restapiuri -Headers $Headers -Method PUT -ContentType
"application/json" -Body $body
What is wrong in the code above?
Thanks and regards
The problem was actually in the JSON format.
In my case the parameter '$body' must be edited like following:
$body = #{
fields = #{
project = #{
key = "TEST"
}
summary = "Test summary
description = "Test description"
issuetype = #{
id = "123"
}
}
}
I came to this solution after multiple tries.
It is also very important to follow jira rules according the order of the fields, otherwise you get a 'bad request 400'.
Generally it is recommended to see some examples, as CraZ mentioned in his links or in this one:
https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/
In this case, Description is system field and you seem to update a custom field (with ID 17526).
If you mean the Description system field, then use this JSON:
{
"update": {
"summary": [{
"set" : "New description"
}]
}
}
If you really mean a Description custom field (that one with ID 17526), then update it this way:
{
"fields": {
"customfield_17526": [{
"set" : "Some text"
}]
}
}
It's wise to use official Atlassian documentation:
Jira Server/DC REST API Reference
Jira Cloud REST API Reference
Also it's worth installing REST API Browser add-on onto your instance.

How to link a work item to a pull request using REST API in Azure DevOps?

Within a release pipeline a new Pull Requested is created using REST API.
How to link a specific (already existing) Work Item to the Pull Request using REST API?
In the current version (DevOps 2019) it is not supported to link Work Items using Pull Request API. (See also related community issue.)
Using PowerShell the following snipped may help.
$requestUri = "$tfsCollectionUri/$teamProject/_apis/wit/workitems/$workItemId" + "?api-version=5.0"
$json = '
[ {
"op": "add", "path": "/relations/-",
"value": {
"rel": "ArtifactLink",
"url": "$pullRequestArtifact",
"attributes": { "name": "pull request" }
}
} ]'
$response = Invoke-RestMethod -Uri $requestUri -UseDefaultCredentials -ContentType "application/json-patch+json" -Method Post -Body $json
Note, $pullRequestArtifact needs to be set. You can get it e.g. from get request.

Write requests are only supported on contained entities, Microsoft Graph API, Groups, PowerShell

I try to run the PS script, but receive an error "Write requests are only supported on contained entities", any ideas?
API Application permission access granted: GroupMember.ReadWrite.All, Group.ReadWrite.All, Directory.ReadWrite.All;
Access token well received;
PS:
function AddB2BToDisabledGroup (){
param(
[string]$AccessToken
)
$B2BAddToDisabledGroupHeaders = #{Authorization = "Bearer $AccessToken"}
$url = "https://graph.microsoft.com/v1.0/groups/$groupID/members/$ref"
$Body = #"
{
"#odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/$b2buserID"
}
"#
$addtogroupres = Invoke-RestMethod -Uri $url -Method Post -Headers $B2BAddToDisabledGroupHeaders -Body $Body -ContentType 'application/json' -ErrorAction Stop
$addtogroupres.status
}
Using the Tenant Admin account, using Graph Explorer, using the same group and user ID, POST works fine.
Tested also with:
"#odata.id": "https://graph.microsoft.com/v1.0/users/$b2buserID"

TFS 2017 API; Queuing a build with variables

I am trying to create a build request and specify new values for custom variables defined in the TFS build definition. I assume I can do this without updating the build definition first. I posted the following JSON to the URL: http://<server-name>/tfs/DefaultCollection/<project-name>/_apis/build/builds?api-version=3.1. The build queued up but the variable value passed in did not override the default value. What am I missing? Do I need to specify the variable name differently?
{
"definition": {
"id": 24,
"variables": {
"IssueNumber": {
"value": "98765"
}
}
}
}
You're providing the wrong JSON structure. It's parameters, not variables, and the way you're specifying the key/value pairs is incorrect.
This PowerShell snippet should point you in the right direction:
$url = 'http://test-tfs-instance:8080/tfs/myCollection'
$body = #{
definition = #{
id = 1435
}
parameters = '{"MyParam":"OverriddenValue","system.debug":"false"}'
}
Invoke-RestMethod -Uri "$($url)/TeamProject/_apis/build/builds?api-version=3.1" -UseDefaultCredentials -Method Post -ContentType 'application/json' -body ($body | convertto-json -Compress -Depth 10)
For what it's worth, this kind of thing is trivial to discover by opening up the developer tools in your browser and looking at the REST call the TFS UI makes. Sometimes the documentation is unclear (as it is in this case), but it's hard to get mixed up when you're copying the same REST calls the application makes.

Get a list of users from Atlassian's Cloud / On-Demand Service

I'm trying to pull a list of users from our Atlassian Confluence/Jira instance. However I'm struggling to find good documentation on what REST services are available, and it seems the SOAP services are deprecated.
The following code does get results, but we have over 100 users, and this returns 0.
if(-not ($credentials)) { #put this here so I can rerun the same script in the same IDE session without having to reinput credentials each time
$credentials = get-credential 'myAtlassianUsername'
}
$tenant = 'myCompany'
invoke-restmethod -Method Get -Uri ('https://{0}.atlassian.net/rest/api/2/groupuserpicker?query=users' -f $tenant) -Credential $credentials | ConvertTo-Json -Depth 5
(The ConvertTo-Json is just to make it simpler to see the expanded result set).
{
"users": {
"users": [
],
"total": 0,
"header": "Showing 0 of 0 matching users"
},
"groups": {
"header": "Showing 2 of 2 matching groups",
"total": 2,
"groups": [
{
"name": "confluence-users",
"html": "confluence-\u003cb\u003eusers\u003c/b\u003e",
"labels": [
]
},
{
"name": "jira-users",
"html": "jira-\u003cb\u003eusers\u003c/b\u003e",
"labels": [
]
}
]
}
}
I think the result's trying to give me the URLs for the JIRA and Confluence User APIs; but I can't figure out how those relative URLs map to the root URL (I've tried appending at various positions in the URL, all of which give me a 404 or dead link error).
The query parameter in your following call is a search query on the Name or E-mail address.
Reference: https://docs.atlassian.com/jira/REST/cloud/#api/2/groupuserpicker.
You can use maxResults parameter to get more than 50 results.
Sadly, this REST API call will not give you all users in one call.
The only way that I know to do with Jira to get all users is to make one call by starting letter (iterate on each letter):
GET .../rest/api/2/user/search?username=a&maxResults=1000
GET .../rest/api/2/user/search?username=b&maxResults=1000
GET .../rest/api/2/user/search?username=c&maxResults=1000
...
Reference: https://docs.atlassian.com/jira/REST/cloud/#api/2/user-findUsers
Sample Code
function Get-AtlassianCloudUsers {
[CmdletBinding()]
param (
[Parameter(Mandatory)][string]$Tenant
,
[Parameter(Mandatory)][System.Management.Automation.Credential()]$Credential
,
[Parameter(Mandatory=$false)][string]$UserFilter = '%'
,
[Parameter(Mandatory=$false)][int]$MaxResults = 9999
)
process {
#refer to http://stackoverflow.com/questions/40424377/get-a-list-of-users-from-atlassians-cloud-on-demand-service for additional notes
[string]$uri = 'https://{0}.atlassian.net/rest/api/2/user/search?username={1}&maxResults={2}' -f $Tenant, $UserFilter, $MaxResults
Invoke-RestMethod -Method Get -Uri $Uri -Credential $credential | select -Expand syncRoot | Select-Object name, displayName, active, self
#| ConvertTo-Json -Depth 5
}
}
Get-AtlassianCloudUsers -Tenant 'MyCompany' -credential (Get-Credential 'MyUsername') | ft -AutoSize
As an alternate answer, I recently discovered the PSJira project on GitHub: https://github.com/replicaJunction/PSJira.
This library provides a nice set of wrapper functions around the JIRA services, and seems well documented and maintained.
To achieve the above requirement follow the steps below:
Installing the package:
Documented here: https://github.com/replicaJunction/PSJira#downloading
Upgrade to PS5 (optional; but required for this method of installation): https://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7AndW2K8R2-KB3191566-x64.zip
Install NuGet Package Manager: Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install PSJira Module: Install-Module PSJira
Configuring PSJira:
Set-JiraConfigServer -Server "https://$Tenant.atlassian.net" (assigning $Tenant to your instance's name)
Using:
Create a credential for your Jira/Atlassian account: $cred = get-credential $JiraUsername
Get list of users: Get-JiraUser -UserName '%' -IncludeInactive -Credential $cred | select Name, DisplayName, Active, EmailAddress

Resources