Azure DevOps API: powershell get list of test points - powershell

Is there a way to get list of test points data via Azure DevOps API?
list
I tried this powershell script
function GetUrl() {
param(
[string]$orgUrl,
[hashtable]$header,
[string]$AreaId
)
# Area ids
# https://learn.microsoft.com/en-us/azure/devops/extend/develop/work-with-urls?view=azure-devops&tabs=http&viewFallbackFrom=vsts#resource-area-ids-reference
# Build the URL for calling the org-level Resource Areas REST API for the RM APIs
$orgResourceAreasUrl = [string]::Format("{0}/_apis/resourceAreas/{1}?api-preview=5.0-preview.1", $orgUrl, $AreaId)
# Do a GET on this URL (this returns an object with a "locationUrl" field)
$results = Invoke-RestMethod -Uri $orgResourceAreasUrl -Headers $header
# The "locationUrl" field reflects the correct base URL for RM REST API calls
if ("null" -eq $results) {
$areaUrl = $orgUrl
}
else {
$areaUrl = $results.locationUrl
}
return $areaUrl
}
$orgUrl = "https://dev.azure.com/fodservices"
$personalToken = "<my token pat>"
Write-Host "Initialize authentication context" -ForegroundColor Yellow
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalToken)"))
$header = #{authorization = "Basic $token"}
Write-Host "Demo 3"
$coreAreaId = "3b95fb80-fdda-4218-b60e-1052d070ae6b"
$tfsBaseUrl = GetUrl -orgUrl $orgUrl -header $header -AreaId $coreAreaId
$relDefUrl = "$($tfsBaseUrl)/_apis/testplan/Plans/70152/Suites/70154/TestPoint?api-version=5.0-preview.2"
try {
$output = Invoke-RestMethod -Uri $relDefUrl -Method Get -ContentType "application/json" -Headers $header
}
catch{
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
}
$output.value | ForEach-Object {
Write-Host $_.id
}
the result is:
Demo 3
StatusCode: 404
StatusDescription: Not Found
Can anyone tell me what i'm doing wrong im new to using powershell and azure devops rest api

Look at the contents of the $tfsBaseUrl variable. It includes the organization name, but not the project name. You need to include the project name in the URL. Look at the documentation and compare your URL to the documentation's URL.

Related

Get SPO sites using MS Graph API powershell not working

I'm trying to get all SharePoint Online sites' name and url via PowerShell using MS Graph API, but it's not seem to be working. That's all I get from the request:
#{#odata.context=https://graph.microsoft.com/v1.0/$metadata#sites; value=System.Object[]}
The application I use have all the needed Application type API permissions (Sites.Read, Sites.ReadWrite.All) with admin consent.
Do you have any idea why my script not working?
The code:
$TenantID = 'xxxxxxxxx.ONMICROSOFT.COM'
$ApplicationId = "xxxxx-xxxxxx-xxxx-xxxx"
$ApplicationSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$body = #{
'resource' = 'https://graph.microsoft.com'
'client_id' = $ApplicationId
'client_secret' = $ApplicationSecret
'grant_type' = "client_credentials"
'scope' = "openid"
}
$ClientToken = Invoke-RestMethod -Method post -Uri "https://login.microsoftonline.com/$($tenantid)/oauth2/token" -Body $body -ErrorAction Stop
$headers = #{ "Authorization" = "Bearer $($ClientToken.access_token)" }
$AllSites = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/sites?search=*" -Headers $headers -Method Get
Write-Host $AllSites
I've also tried these URIs:
https://graph.microsoft.com/v1.0/sites?search=*
https://graph.microsoft.com/v1.0/sites
https://graph.microsoft.com/v1.0/sites$select=siteCollection,webUrl&$filter=siteCollection/root%20ne%20null
The Write-Host cmdlet's primary purpose is to produce
for-(host)-display-only output, such as printing colored text like
when prompting the user for input in conjunction with Read-Host.
Write-Host uses the ToString() method to write the output. By
contrast, to output data to the pipeline, use Write-Output or implicit
output.
reference
This mean that your output is transformed for display purposes. Where you see System.Object[], there is actually data in there just waiting for you.
Based on your current results, your query look good.
Just do not use Write-Host and dig into the object as needed.
To get the site names, just use $AllSites.Value.Name
$AllSites = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/sites?search=*" -Headers $headers -Method Get
# Return site names
$AllSites.Value.Name
If you need to get additional information from each return you can loop into them, like this to do whatever you need. Here is a custom display of the site name along with an arbitrary index and the associated URL
$index = 0
# Will display results like
# 0: SiteName - www.contoso.sharepoint.com/SiteUrl
foreach ($Site in $AllSites.Value) {
Write-Host "$($index.ToString().PadRight(3,' ')): $($Site.Name) - " -NoNewline
Write-Host $site.webUrl -ForegroundColor Cyan
$index += 1
}
Also, here is an additional reference when working with Azure Graph API that will confirm your requests are working as expected: https://developer.microsoft.com/en-us/graph/graph-explorer

How to get 'Deployment group's target's capabilities in Azure Devops using Powershell rest

I am trying to get a target's capabilities under azure devops deployment group using Powershell REST API. However I am not sure which URL will work to fetch those capabilities. My Powershell script is working till fetching status of 'targets'. Please help if there is anything we can do to fetch capabilities.
Below is my script which is working till fetching target details:
$projects = "testing"
$projectlist = $projects.split(';')
$PAT = "#######################################33"
$Header = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PAT)")) }
foreach($projectName in $projectlist){
write-host "================================================="
$baseURL = "https://dev.azure.com/abc/$($projectName)/_apis/distributedtask/deploymentgroups"
$deploymentgroup=Invoke-RestMethod -Uri "https://dev.azure.com/abc/$($projectName)/_apis/distributedtask/deploymentgroups?api-version=6.0-preview.1" -Method get -Headers $Header
$deploymentgroupsname=$deploymentgroup.value.name
foreach($deploymentgroupname in $deploymentgroupsname){
$deploymentGroupURL = "$($baseURL)?name=$($deploymentgroupname)&api-version=6.0"
try{
$deploymentgroup=Invoke-RestMethod -Uri "$deploymentGroupURL" -Method get -Headers $Header
}catch{
write-host "URL is not accessible - $deploymentGroupURL"
}
$deploymentGroupResponse=$deploymentgroup.value
$deploymentGroupid=$deploymentGroupResponse.id
try{
$targets=Invoke-RestMethod -Uri "https://dev.azure.com/abc/$($projectName)/_apis/distributedtask/deploymentgroups/$($deploymentGroupid)/targets?api-version=6.0-preview.1" -Method get -Headers $Header
}catch{
write-host "URL is not accessible - $deploymentGroupURL"
}
if($null -ne $deploymentGroupId){
$targets.value.agent|select name, status|%{
$hostname=$_.name
$Status=$_.status
if($status -eq "offline"){
$targetURL = "$($baseURL)/$deploymentGroupId/targets?name=$($hostName)&api-version=6.0-preview.1"
try{
$target = (Invoke-RestMethod -Uri $targetURL -Method get -Headers $Header).value
$targetId = $target.id ;
if($null -ne $targetId){
$url = "$($baseURL)/$deploymentGroupId/targets/$($targetId)?api-version=6.0"
try{
write-host "Projectname is : $projectName"
write-host "deploymentGroupname is : $deploymentgroupname"
write-host "Server $hostname is not pingble"
}
catch{
write-host "TARGET DELETE ERROR: $hostName";Write-Error $_.Exception.Message
}
}
else{
write-host "Target $hostName NOT Found in DeploymentGroup $environment."
}
}catch {
write-host "TARGET LIST ERROR";Write-Error $_.Exception.Message
}
}
}
}else{
write-host "DeploymentGroup $deploymentgroupname NOT FOUND in $projectName"
}
}
}
To to fetch capabilities of the Deployment Group Targets, you can use the Rest API: Targets - Get. You need to add the parameter: $expand=capabilities in the URL.
GET https://dev.azure.com/{organization}/{project}/_apis/distributedtask/deploymentgroups/{deploymentGroupId}/targets/{targetId}?$expand=capabilities&api-version=6.0-preview.1
Then you will get the capabilities of the Deployment Group Targets.
To use the Rest API URL in the PowerShell, you can use the following format:
$url="https://dev.azure.com/{organization}/{project}/_apis/distributedtask/deploymentgroups/{deploymentGroupId}/targets/{targetId}?`$expand=capabilities&api-version=6.0-preview.1"
Update:
When we add the $expand=capabilities in the Rest API url, it will return the capabilities in the API Response.
Here is an example:

Post Method - Changing a Nested Value

I am trying to change a value - specifically a variable - of one of my TFS 2017 builds. To my understanding, Patch is not supported at all. I can successfully queue a build with the Post method and I am trying to use the same command change a value as well.
When I run the Get method, I have:
*A bunch of text*
"variables": {
"system.debug": {
"value": "false",
"allowOverride": true
},
"BuildVersion": {
"value": "ValueIWantToChange"
}
},
*A bunch of text*
I need to change the Build Version and everything else will stay the same. My body in Postman looks like:
{
"Variables":
{
"BuildVersion":
{
"value": NewValue
}
}
}
When I run this in Postman, I get this error:
"Value cannot be null.\r\nParameter name: definition.Repository"
Could anyone tell me where I am going wrong or if this is possible using another method?
Seems you want to update the build definition base on you description.
To update the build definition with the REST API you need to use PUT method, please see Definitions - Update Definition for details.
Get the build definition first:
GET http://server:8080/tfs/DefaultCollection/ScrumProject/_apis/build/definitions/6?api-version=3.2
Copy all the json response from the first step as the request body,
then change the value of the specific variable which you want to be
modified.
PUT http://SERVER:8080/tfs/DefaultCollection/ScrumProject/_apis/build/definitions/6?api-version=3.2
Content-Type: application/json
Note that you need to provide the latest revision in request body:
UPDATE:
You can also use PowerShell by calling the REST API to update the specific variable value, just try below sample: (the variable name is lctest in below sample, you just need to replace it with your own variable name.)
Param(
[string]$collectionurl = "http://server:8080/tfs/DefaultCollection",
[string]$project = "ProjectName",
[string]$definitionid = "6",
[string]$user = "username",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#Get build definition
$defurl = "$collectionurl/$project/_apis/build/definitions/$($definitionid)?api-version=3.2"
$definition = Invoke-RestMethod -Uri $defurl -Method Get -UseDefaultCredential -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
#Set new value for the specific variable
$definition.variables.lctest.value = "1.0.0.4"
$json = #($definition) | ConvertTo-Json -Depth 99
#Update the definition
$updatedef = Invoke-RestMethod -Uri $defurl -Method Put -Body $json -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host $definition.variables.lctest.value
I figured out my problem awhile back and forgot to update. My initial task was to get the API for octopus so this is the long version. If youre only interested in the REST commands, refer to the last section of code. Just wanted to add the rest in for extra context.
#Create a folder
if(test-Path C:\Test){}
else{
new-item -path "C:\" -name "Test" -ItemType "directory"}
$encodedPAT = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$TFSAPIKeyForAutomatedBuild"))
$GetURI = "$MyURI"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $encodedPAT")
[string]$Global:ChangeVersion = [version]$OctopusParameters["Octopus.Action[Deploy Package].Package.NuGetPackageVersion"]
write-host $ChangeVersion
$GetBuildresponse = Invoke-RestMethod -Method Get -header $headers -ContentType "application/json" -Uri $GetUri
write-host $GetBuildResponse
$y = convertTo-json $GetBuildresponse -depth 99 | Out-file -FilePath "C:\test\FromPostmanCopy.json"
$z = (get-content "C:\test\FromPostmanCopy.json") | select-string -pattern '(?<=value": "2.)(.*)(?=")' | % { $_.Matches} | % { $_.value }
Write-Host $z
$Content = (Get-Content "C:\Test\FromPostmanCopy.json")
$content -replace "2.$z", $changeVersion | out-file "C:\Test\FromPostmanCopy.json"
$Content = (Get-Content "C:\Test\FromPostmanCopy.json")
$Buildresponse = Invoke-RestMethod -URI $GetURI -Method Put -header $headers -Body $content -ContentType application/json

How to assign a group as Users on an endpoint in VSTS via the API?

I'm trying to tidy up VSTS and ensure that the AzureRM endpoints are consistent across our 40+ projects. I've written a Powershell script to call the rest API and ensure that the same endpoints are available for all projects. This works fine.
One thing I want to do though is grant the Contributors group for each project User rights on the non-prod endpoints. This doesn't seem to work and the official documentation (create or update) doesn't provide any real guidance on it.
I can get the group and pass this as being the "readersGroup" in the JSON Body of the call and this is then echoed in the response, implying it worked, but this doesn't appear to change anything on the endpoint itself.
Has anyone done this before who can give me some guidance as to where I'm going wrong?
[CmdletBinding()]
Param(
[ValidateSet("Production","NonProduction","RandD")][string]$Environment,
[string]$SubscriptionName,
[string]$SubscriptionDisplayName = $SubscriptionName,
[string]$SubscriptionId,
[string]$TenantId,
[string]$ClientId,
[string]$ClientKey,
[string]$Token #Required Scopes: Graph (read), Project and team (read), Service Endpoints (read, query and manage)
)
#Set up Endpoint data
$EndpointDisplayName = "$Environment ($SubscriptionDisplayName)"
$EndpointConfiguration = #"
{
"data": {
"SubscriptionId": "$SubscriptionId",
"SubscriptionName": "$SubscriptionName",
"creationMode" : "Manual"
},
"name": "$EndpointDisplayName",
"type": "azurerm",
"url" : "https://management.azure.com/",
"authorization": {
"parameters": {
"serviceprincipalid" : "$ClientId",
"serviceprincipalkey" : "$ClientKey",
"tenantid" : "$TenantId"
},
"scheme": "ServicePrincipal"
}
}
"#
#Set up API data
$Authentication = [Text.Encoding]::ASCII.GetBytes(":$Token")
$Authentication = [System.Convert]::ToBase64String($Authentication)
$Headers = #{
'Authorization' = "Basic $Authentication"
'Content-Type' = "application/json"
}
$BaseURI = "https://contoso.visualstudio.com"
$APIVersion = "?api-version=4.1-preview.1"
#get all vsts projects
$ListProjectsURI = "$BaseURI/DefaultCollection/_apis/projects$APIVersion"
$ProjectList = (Invoke-RestMethod -Method GET -Uri $ListProjectsURI -Headers $Headers).value
#Get VSTS Contributor groups for "user" role assignment
$ListGroupsURI = "https://Contoso.vssps.visualstudio.com/_apis/graph/groups$APIVersion"
$GroupsList = (Invoke-RestMethod -Method GET -Uri $ListGroupsURI -Headers $Headers).value
$AllContributorsGroups = $GroupsList | Where-Object -Property principalName -like "*\Contributors"
foreach($Project in $ProjectList)
{
$ProjectName = $Project.name
$ProjectId = $Project.id
#get all AzureRM SP endpoints
$ListEndpointsURI = "$BaseURI/$ProjectId/_apis/serviceendpoint/endpoints$APIVersion&type=azurerm&authschemes=ServicePrincipal"
$EndpointList = (Invoke-RestMethod -Method GET -Uri $ListEndpointsURI -Headers $Headers).value
$Exists = $false
#set up the endpoint settings for this project
if($Environment -eq "Production")
{
$EndpointJSON = $EndpointConfiguration
}
else #grant devs access to use non-prod/R&D endpoints
{
Write-Host "Setting [$ProjectName]\Contributors as Users on $EndpointDisplayName in $ProjectName"
$ReadersGroup = ($AllContributorsGroups | Where-Object -Property principalName -eq "[$ProjectName]\Contributors") | ConvertTo-Json
$ReadersConfiguration = #"
,"readersGroup" : $ReadersGroup
}
"#
$EndpointJSON = $EndpointConfiguration.TrimEnd('}') + $ReadersConfiguration #Append the readers role for this project to the base configuration
}
#Look for existing matching endpoints
foreach($Endpoint in $EndpointList)
{
$EndpointName = $Endpoint.name
$EndpointId = $Endpoint.id
#check if it uses the subscription Id we're updating,
if($Endpoint.data.subscriptionId -eq $SubscriptionId)
{
#if so, update it
Write-Host "Updating endpoint `"$EndpointName`" in Project `"$ProjectName`" (Endpoint ID: $EndpointId)"
$UpdateEndpointURI = "$BaseURI/$ProjectId/_apis/serviceendpoint/endpoints/$EndpointId$APIVersion"
Invoke-RestMethod -Method PUT -Uri $UpdateEndpointURI -Headers $Headers -Body $EndpointJSON
$Exists = $true
}
}
#if no existing endpoints match, create one
if(!$Exists)
{
Write-Output "No endpoint found for $SubscriptionName in `"$ProjectName`". Creating endpoint `"$EndpointDisplayName`"."
$CreateEndpointURI = "$BaseURI/$ProjectId/_apis/serviceendpoint/endpoints$APIVersion"
Invoke-RestMethod -Method POST -Uri $CreateEndpointURI -Headers $Headers -Body $EndpointJSON
}
}
Using this API instead:
Put
https://{account}.visualstudio.com/_apis/securityroles/scopes/distributedtask.serviceendpointrole/roleassignments/resources/{project id}_{endpoint id}?api-version=5.0-preview.1
Body (application/json)
[{"roleName":"User","userId":"{group or user id (originId)"}]

Azure Automation Account: How to Pass Webhook data to a runbook?

I have an Azure Runbook in an Azure Automation account, which I would like to trigger with a webhook which contains some parameters.
The runbook looks like this
workflow do-something
{
param
(
[object]$WebhookData
)
inlinescript {
if ($WebhookData -ne $null) {
$WebhookName = $WebhookData.WebhookName
$WebhookBody = $WebhookData.RequestBody
$webhookBodyObject = $WebhookBody | ConvertFrom-JSON
$customerEmail = $webhookBodyObject.customerEmail
$customerName = $webhookBodyObject.customerName
$dataLocation = $webhookBodyObject.dataLocation
} else {
"The WebhookData is totally and completely null"
exit (0)
}
$webhookjson = $WebhookData | ConvertTo-JSON
"The webhookdata is $webhookjson"
"The webhook name is $WebhookName"
"The customer email is $customerEmail"
"The body s $WebhookBody"
}
}
I then saved it and published it, and then got a webhook for it. As per instructions, i wrote a little Powershell script to trigger the webhook:
#Not the real URI, but similar in structure
$uri = "https://s10events.azure-automation.net/webhooks?token=Qt%xyxyxyxyxyxyxyxyxyxyxyxy%ababababab%3d"
$headers = #{"From"="babu#bhatt.com";"Date"="05/28/2015 15:47:00"}
$params = #{"customerName"="Jay Godse"; "customerEmail"="jaygodse#exmple.com"; "dataLocation"="Canada"}
$body = ConvertTo-Json -InputObject $params
#$response = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body
$webresp = Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -Body $body -Verbose
When I invoked the request, i got a 202 response code which suggested that the request was successfully queued.
Then I went to the Jobs section in the Runbook, and and looked at the input and output of the job. The input looked like this:
{"WebhookName":"test1","RequestBody":"{\r\n \"customerEmail\": \"jaygodse#exmple.com\",\r\n \"customerName\": \"Jay Godse\",\r\n \"dataLocation\": \"Canada\"\r\n}","RequestHeader":{"Connection":"Keep-Alive","Date":"Thu, 28 May 2015 19:47:00 GMT","From":"babu#bhatt.com","Host":"s10events.azure-automation.net","User-Agent":"Mozilla/5.0","x-ms-request-id":"d8995f98-1344-4822-af69-ababababababa"}}
The output looked like this:
The WebhookData is totally and completely null
What do I have to do to pass data successfully from the webhook to the my Azure Automation runbook? I couldn't find any examples on the web which actually worked.
You should use $using: scope inside the inlinescript {} block like that:
workflow do-something
{
param
(
[object]$WebhookData
)
inlinescript {
if ($using:WebhookData -ne $null) {
$WebhookName = $using:WebhookData.WebhookName
$WebhookBody = $using:WebhookData.RequestBody
$webhookBodyObject = $WebhookBody | ConvertFrom-JSON
$customerEmail = $webhookBodyObject.customerEmail
$customerName = $webhookBodyObject.customerName
$dataLocation = $webhookBodyObject.dataLocation
} else {
"The WebhookData is totally and completely null"
exit (0)
}
$webhookjson = $using:WebhookData | ConvertTo-JSON
"The webhookdata is $webhookjson"
"The webhook name is $WebhookName"
"The customer email is $customerEmail"
"The body s $WebhookBody"
}
}
See the explanation here: https://technet.microsoft.com/en-us/library/jj574197(v=ws.11).aspx ("Variables in InlineScript" section).