Create several queries across multiple projects in Azure DevOps - azure

I'm trying to create the same queries across several projects. I feel like I'm almost there, but can't come up with the right 'thing' to create more than one query. I've tried "," ";" "AND" - and have managed to get it to create one but never both.
Could someone assist?? I've put down a quick example snippet of the type of thing I'm trying (which is why the fields are the same). If I can get that right, I'll use it for real with all the different queries I have (there's quite a few!)
{ $url1="https://dev.azure.com/[ORGANISATION]/$($project)/_apis/wit/queries/Shared Queries?api-version=6.0"
$JSON = #'
{
"name": "All User Stories JW6", "wiql": "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State],[System.Tags],[Microsoft.VSTS.Scheduling.OriginalEstimate],[Microsoft.VSTS.Scheduling.CompletedWork] FROM workitems WHERE [System.WorkItemType] = 'User Story' AND [System.State] = 'Active' ORDER BY [System.WorkItemType]",
"name": "All User Stories JW7", "wiql": "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State],[System.Tags],[Microsoft.VSTS.Scheduling.OriginalEstimate],[Microsoft.VSTS.Scheduling.CompletedWork] FROM workitems WHERE [System.WorkItemType] = 'User Story' AND [System.State] = 'Active' ORDER BY [System.WorkItemType]"
}
'#

Create several queries across multiple projects in Azure DevOps
I am afraid we could not set duplicate Keys in JSON body.
That because the names in json object SHOULD be unique, check the state in RFC-7159:
The current standard for JSON published by the Internet Engineering
Task Force (IETF), states "The names within an object SHOULD be
unique".
I use the body in the postman, I got the same warning:
If we use the duplicate Keys in JSON body, most popular parsers may take only the last value present in the object for a particular key and ignore the previous ones.
In your sample, only query All User Stories JW7 will be created.
To resolve this issue, we have to create a another body $JSON2, and send another request:
$JSON2 = #'
{
"name": "All User Stories JW7", "wiql": "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State],[System.Tags],[Microsoft.VSTS.Scheduling.OriginalEstimate],[Microsoft.VSTS.Scheduling.CompletedWork] FROM workitems WHERE [System.WorkItemType] = 'User Story' AND [System.State] = 'Active' ORDER BY [System.WorkItemType]"
}
'#
$CreateQuery1= Invoke-RestMethod -Uri $url -headers $headers -Method Post -ContentType "application/json" -Body $Json1
$CreateQuery2= Invoke-RestMethod -Uri $url -headers $headers -Method Post -ContentType "application/json" -Body $Json2

Related

Azure DevOps API error: Field state 'Active' not supported when Work Item has been "Removed"

I have a work item of type feature with a state of "Removed." When trying to update the field state back to "Active" on certain conditions, I'm getting the following error:
resp = Invoke-RestMethod -Uri $updateUri -Method Patch -ContentType application/json-patch+json -Headers $header -Body $jsonBody
Invoke-RestMethod : {"$id":"1","customProperties":{"FieldReferenceName":null,"FieldStatusFlags":"none","ErrorMessage":"The field 'State' contains the value 'Active' that is not in
the list of supported values","FieldStatusCode":0,"RuleValidationErrors":[{"fieldReferenceName":"System.State","fieldStatusFlags":"required, hasValues, limitedToValues,
invalidListValue","errorMessage":"The field 'State' contains the value 'Active' that is not in the list of supported
values","fieldStatusCode":4194317,"ruleValidationErrors":null}]},"innerException":null,"message":"The field 'State' contains the value 'Active' that is not in the list of supported
values","typeName":"Microsoft.TeamFoundation.WorkItemTracking.Server.RuleValidationException,
Microsoft.TeamFoundation.WorkItemTracking.Server","typeKey":"RuleValidationException","errorCode":0,"eventId":3200}
At line:1 char:9
+ $resp = Invoke-RestMethod -Uri $updateUri -Method Patch -ContentType ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Note that my code works updating field.'System.State' in all cases except when it's trying to change a "removed" work item. Is there a special way to do this?
Is there a special way to do this?
I am afraid there is no such way to do this.
That is because the workitem that is already in the Removed state cannot be converted to other states except New.
You could check the document Agile workflow states for some more details.
In addition, when we have chosen to Remove a certain workitem, it means that we have abandoned the workitem. If the workitem is re-enabled, it should return to the state of New.

Using $filter through Microsoft graph API request

I'm trying to use MS graph API via a small Powershell script as described here https://learn.microsoft.com/en-us/graph/api/riskyusers-list?view=graph-rest-beta&tabs=http
this filter doesn't give any result and if I remove it it works but do not give the complete list (only few results)
$ApplicationID = "45xxxxxxxx"
$TenatDomainName = "2a3xxxxx"
$AccessSecret = Read-Host "Enter Secret"
$Body = #{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
client_Id = $ApplicationID
Client_Secret = $AccessSecret
}
$ConnectGraph = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenatDomainName/oauth2/v2.0/token" -Method POST -Body $Body
$token = $ConnectGraph.access_token
#$GrapRisk = "https://graph.microsoft.com/v1.0/identityProtection/riskyUsers"
$GrapRisk = "https://graph.microsoft.com/beta/identityProtection/riskyUsers?$filter=riskLevel eq microsoft.graph.riskLevel'medium'"
$riskyList= (Invoke-RestMethod -Headers #{Authorization = "Bearer $($token)"} -Uri $GrapRisk -Method Get).value |select userPrincipalName, riskState, riskLastUpdatedDateTime, riskLevel
$riskyList
I execute this script through Powershell ISE but even with curl and terminal I cannot use the filter parameter.
Thanks
Whenever a string literal uses double-quotes ("'s), PowerShell interprets it as expandable, meaning PowerShell will attempt to resolve and expand variable expressions (like $filter) when evaluating the string.
Use a backtick (`) to escape the $, and it should work:
$GrapRisk = "https://graph.microsoft.com/beta/identityProtection/riskyUsers?`$filter=riskLevel eq microsoft.graph.riskLevel'medium'"
For more details about the semantics of different types of string literals in PowerShell, read the about_Quoting_Rules help topic

Functionality of Attachments and their use in Work Item Tracking API

I stumbled across the documentation for creating attachments, listed under work item tracking, and I'm curious about the functionality. According to this stack overflow post, the functionality seems to be that it uploads a file to the "backend" without any association to a work item. I am having some trouble understanding what the use case for this endpoint is... Is it just a glorified storage space? What is its intended use if there is no UI to view the item and no relations to any existing entities other than a project? Is there any available end point that I am missing that would allow me to add an attachment to an existing work item?
You also need to use Work Items - Update rest api to add the attachments to a work item. See below:
1, First use Attachments - Create rest api to update the attachment to azure devops server.
When the attachment is successfully uploaded, The attachment id and url will be returned to you. And you will need to use the attachment url in the Work Items - Update rest api. See examples
2, Use Work Items - Update to add the attachment to the work item. Put the attachment url in the request body like below example:
[{
"op": "add",
"path": "/relations/-",
"value": {
"rel": "AttachedFile",
# attachment url
"url": "https://dev.azure.com/fabrikam/_apis/wit/attachments/098a279a-60b9-40a8-868b-b7fd00c0a439?fileName=Spec.txt",
"attributes": {
"comment": "Spec for the work"
}
}
}]
See below full example in powershell scipts:
# Attachments - Create REST API
$url = "https://dev.azure.com/{org}/{proj}/_apis/wit/attachments?fileName=textAsFileAttachment.txt&api-version=6.0"
$PAT="Personal access token"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($PAT)"))
$body= 'this a attached text file'
# update attachment to azure devops server. attachment id and url will be returned
$attachment= Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic {0}" -f $base64AuthInfo} -ContentType "application/octet-stream" -Method post -Body $body
# Work Items - Update REST API
$wurl ="https://dev.azure.com/{org}/{proj}/_apis/wit/workitems/{workitem Id}?api-version=6.0"
$wbody=#(
#{
"op"= "add";
"path"= "/relations/-";
"value"= #{
"rel"= "AttachedFile";
"url"= $attachment.url; #Attachment url
"attributes"= #{
"comment"= "attachment Test"
}
}
})
# add attachment to workitem.
Invoke-RestMethod -Uri $wurl -Headers #{Authorization = "Basic {0}" -f $base64AuthInfo} -ContentType "application/json-patch+json" -Method patch -Body (convertto-json $wbody -Depth 10)
Then the attachment you uploaded to azure devops will be attached to a workitem. See below result of above example:

Current Iteration Query Script Devops Looping Through Projects

I'm trying to put a script together that will let me loop through projects and create queries relevant to the current iteration.
I can loop through and create queries until it comes to looking at the iteration path and then it doesn't seem to like it.
When I run my script all of the other queries are created, and this one is as well, but it brings up an error when I go to look at it because it's posting that it's not in the right form. How can I get this query to loop through like the others and bring back the appropriate team in the process?
I'm assuming that somehow I've got to put project and team as variables? I tried $project as well but that just presented a similar error. Although I'm also confused about about the "" since the code doesn't like that either, and it won't even create the query when I've tried that.
$JSON27 = #'
{
"name": "Current Sprint Query", "wiql": "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State],[System.Tags],[Microsoft.VSTS.Scheduling.OriginalEstimate],[Microsoft.VSTS.Scheduling.CompletedWork],[System.IterationPath] FROM workitems WHERE [System.TeamProject] = #project AND [System.WorkItemType] <> '' AND [System.State] = 'Closed' AND [System.IterationPath] = #CurrentIteration('[Project]/Team') ORDER BY [System.WorkItemType]"
}
'#
$response27 = Invoke-RestMethod -Uri $url1 -Headers #{Authorization = "Basic $token"} -Method Post -Body $JSON27 -ContentType application/json
Please refer to the following script to get the project name first, and then create a query by looping through the obtained project name.
Please use #CurrentIteration('[Project]\\Team') instead of #CurrentIteration('[Project]/Team') or #CurrentIteration('[Project]\Team')
$token = "your PAT"
$url="https://dev.azure.com/org name/_apis/projects?api-version=6.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Get -ContentType application/json
echo $url
foreach ($project in $response.value.name){
$url3="https://dev.azure.com/org name/$($project)/_apis/wit/queries/My Queries?api-version=6.1-preview.2"
echo $url1
$body = "{
`"name`": `"query name`",
`"wiql`": `"Select [System.Id], [System.State] From WorkItems where [System.IterationPath] = #CurrentIteration('[$project]\\$project Team') `"
}"
echo $body
$response3 = Invoke-RestMethod -Uri $url3 -Headers #{Authorization = "Basic $token"} -Method Post -Body $body -ContentType application/json
echo $response3
}
Summarizing the discussion in comments as an answer below:
So, as the error message calls out, I think the issue is that you have #CurrentIteration('[Project]/Team') in your query instead of #CurrentIteration('[Project]\Team').
Your query should be this instead:
$JSON27 = #'
{
"name": "Current Sprint Query", "wiql": "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State],[System.Tags],[Microsoft.VSTS.Scheduling.OriginalEstimate],[Microsoft.VSTS.Scheduling.CompletedWork],[System.IterationPath] FROM workitems WHERE [System.TeamProject] = #project AND [System.WorkItemType] <> '' AND [System.State] = 'Closed' AND [System.IterationPath] = #CurrentIteration('[Project]\Team') ORDER BY [System.WorkItemType]"
}
'#
EDIT:
By default, shared queries and new queries are scoped to the current project. For querying across multiple projects, you can add the TeamProject field to filter to a select number of projects as:
..
AND [System.TeamProject] IN ('Project 1', 'Project 2', 'Project 3')
However, using the #CurrentIteration macro would need you to select a Team and may not work across Projects and Teams. Check this idea on Developer Community for more details.

VSTS Rest API queries for linked work items in Powershell

Using REST APIs of VSTS in PowerShell, I wanted to create a report on my VSTS Team Project which consists of the details of the Work Item Linking relationships of all workitems under particular "Iteration Path" and "Area Path".
Ex: Epics→Features→UserStories. Since there are parent/child relationships between Epics & Features and also between Features & UserStories.
So the input would be Iteration Path and Area Path, and the corresponding output would be a report (.csv or .xls) which has all the details of these workitems and their relationships.
Could someone let me know on how to achieve this using REST APIs in PowerShell?
I wrote the code for getting the hierarchical workitems in a Team Project but need to modify to filter the the list based on a given Iteration and Area paths.
Also when executing the below code, the string comparison in the query(due to presence of '') is returning an error in the power-shell.
Error: Invoke-RestMethod : {"count":1,"value":{"Message":"After parsing a value an unexpected character was encountered: G.
Path 'query', line 1, position 163.\r\n"}}
$vstsAccount = "xxxx"
$projectName = "xxxx"
$user = "xxxx"
$token = "xxxx"
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
# Construct the REST URL to obtain Build ID
$uri = "https://$($vstsAccount).visualstudio.com/$($projectName)/_apis/wit/wiql?api-version=1.0"
$body = "{'query': 'Select [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State] From WorkItemLinks WHERE
((Source.[System.TeamProject] = '$projectName' and Source.[System.State] <> 'Removed') and (Source.[System.WorkItemType] = 'Epic') and
([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') and (Target.[System.WorkItemType] = 'UserStory') mode(Recursive)'}"
# Invoke the REST call and capture the results (notice this uses the POST method)
$result = Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $body
Modify part of your code like this:
$query = "Select
[System.Id],
[System.WorkItemType],
[System.Title],
[System.AssignedTo],
[System.State]
From WorkItemLinks
WHERE (
Source.[System.TeamProject] = '$projectName'
AND Source.[System.State] <> 'Removed'
) AND (
Source.[System.WorkItemType] = 'Epic')
AND ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward'
) AND (Target.[System.WorkItemType] = 'UserStory') mode (Recursive)
"
$body = #{query=$query} | ConvertTo-Json
$result = Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Headers #{Authorization=("Basic $base64AuthInfo")} -Body $body

Resources