export complete TFS work item incl. history with PowerShell - powershell

I am working for a customer who is running a Dynamics AX project and is using TFS. I do have access to TFS and am able to check all the different work items - however, what I am missing is an overview to build metrics as the only way to get data into a table (Excel) does not allow me to get the history of a work item.
I am hence wondering how I could do this using PowerShell. I am completely new to this, accordingly step-by-step guidance would be highly appreciated.

You can use TFS Rest API.
For example:
$serverUrl = "http://tfsServer:8080/tfs/Collection"
$workItemId = "1"
#Get the Work Item
$workItem = Invoke-RestMethod -Uri "$($serverUrl)/_apis/wit/workitems/$($workItemId)?api-version=3.0" -UseDefaultCredentials -Method Get
#Print the revisions number
Write-Host $workItem.rev
#Get the specific revision details
$revision = Invoke-RestMethod -Uri "$($serverUrl)/_apis/wit/workitems/$($workItemId)/revisions/2?api-version=3.0" -UseDefaultCredentials -Method Get
#Print the Work Item details in the specific revision
Write-Host $revision.fields

Related

Azure cli: clone pipeline

Looking at az pipelines documentation it seems it's not possible to clone a pipeline using cli.
I've looked at getting the yaml (az pipelines show -name=x > x_orig.yaml) and then trying to change json and create pipeline from modified yaml, but that feels like a lot of work that could break after next update.
Is there a way to clone a pipline without going the the Web UI?
Currently, there indeed is not available Azure CLI that can clone or export/import a pipeline to create a new pipeline.
I also searched and tried the Azure DevOps REST API for Pipelines, but did not find the available API.
Ideally, the Azure CLI "az pipelines create" can provide an input parameter that allows users specify an existing pipeline as a starting point for the new pipeline.
If your projects really need this feature, I recommend that you can directly report a feature request on the "Azure/azure-cli" repository to ask adding the parameter like as above mentioned. That will allow you directly interact with the appropriate engineering team, and make it more convenient for the engineering team to collect and categorize your suggestions.
As a workaround, we could clone the build definition via power shell script to call REST API.
Note: We need to change the original build definition name.
REST API
Get build definition:
GET https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?api-version=6.0
Create build definition
POST https://dev.azure.com/{organization}/{project}/_apis/build/definitions?api-version=6.0
Power shell script
$connectionToken="{pat}"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$BuildDefinitionInfoURL = "https://dev.azure.com/{org name}/{project name}/_apis/build/definitions/386"
$BuildDefinitionInfo = Invoke-RestMethod -Uri $BuildDefinitionInfoURL -Headers #{authorization = "Basic $base64AuthInfo"} -Method Get
Write-Host $BuildDefinitionInfo.name
$BuildDefinitionInfo.name = $BuildDefinitionInfo.name +" clone"
Write-Host $BuildDefinitionInfo.name
$body = $BuildDefinitionInfo | ConvertTo-Json -Depth 99
$createBuildDefinitionURL = "https://dev.azure.com/{org name}/{project name}/_apis/build/definitions?api-version=6.0"
$response = Invoke-RestMethod -Uri $createBuildDefinitionURL -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
Write-Host $response.id
Result:

Update Azure DevOps artifact properties using API call

Does anyone know here how to update an Artifact's properties? We've had a project assigned to us to move all of our artifact drops from one location to another - This is because our file server is about to die (We use On-Prem Azure DevOps Services)
I've wrote a PowerShell script already that updates what's needed for builds/releases and that works great.
So I wrote another PowerShell script to update what's needed within the Artifacts properties and then uses an "PUT" call to replace the info but there's an issue....
Invoke-RestMethod : {"count":1,"value":{"Message":"The requested resource does not support http method 'PUT'."}}
Does anyone know if this is possible/knows how to do it?
Here's my script;
Example of an endpoint;
https://dev.azure.com/{organization}/{project}/_apis/build/builds/{buildId}/artifacts?api-version=5.1
$artefacts = Get-Content ".\artefacts.txt"
$oldDataURL = "\\rdtstore01.main.rdt.co.uk\Horizon\Drops"
$newDataURL = "\\main.rdt.co.uk\shares\Horizon\Drops"
foreach ($line in $artefacts)
{
$var = Invoke-RestMethod -Uri $line -UseDefaultCredentials -Method Get
### Updte Data line ###
$data = $var.value.resource.data
$dataNew = $data -replace [RegEx]::Escape($oldDataURL), $newDataURL
$var.value.resource.data = #{}
$var.value.resource.data += #{"value" = $dataNew}
$result = Invoke-RestMethod -Uri $line -Method Put -ContentType "application/json" -UseDefaultCredentials -Body (ConvertTo-Json $var -Depth 10)
}
Use Rest API to update Artifacts properties is not support right now. We only provide below methods for working with artifacts produced by builds.
Sorry, there is not any workaround, you may have to use build task to publish artifacts again.

LUIS Azure DevOps pipeline, how to create any samples?

There is a requirement, to create Azure Devops pipeline which could support version, add file into application, train, test & publish application into Stage & production.
How it can be done through Azure Devops Pipeline. Any documentation or steps could be helpful.
Thanks
A.Prabhuram
I have done something similar through Azure CLI (PowerShell version 2.X) tasks, but it is not straight forward. I haven't done all of the steps as you mention above, but hopefully this will give you what you need to further build on it.
As a baseline, the functions you need are outlined in the LUIS Programmatic API. You will need the LUIS key and app id for most requests, which you can get via
$LUISKEY= & az cognitiveservices account keys list -g "resourceGroupName" --name "LUISauthoringKeyName" --query key1 -o tsv
$header = #{"Ocp-Apim-Subscription-Key"="$LUISKEY"}
$res = Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/apps/?take=1" -Method 'Get' -Headers $header
$appid = $res.id
For brevity, I'm not repeating this code. But if you have separate tasks and/or agent jobs in your pipeline (as opposed to doing this as one script, which I do not recommend), you'll need to repeat these statements for each task. Do take note of the region and modify as needed for your authoring resource.
Obviously, to update your LUIS version, you need to have the model definition. I don't do this often since we are set up to use the same LUIS app in QA and PROD. So I just add a new version to the project repo if I need to run it through DevOps. Then I add the repo as an artifact for the release pipeline. But you should be able to use the Export Application Version API to get it programmatically, though I haven't tried personally. Here is what I did to add the new version:
$body = Get-Content '$(System.DefaultWorkingDirectory)/_AveryCreek_OEM_CSC_Bot/models/luis/AveryCreek OEM_CSC Team.json' | Out-String
Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/apps/$appid/versions/import" -Method 'Post' -Body $body -Headers $header
Note that this version is not additive and will completely replace your previous version (though you can revert). In other words, if you have changes to the previous version that are NOT incorporated into the version you are importing, they will be lost. This is one of the main reasons we do not use separate LUIS apps per environment (sidebar - you can use separate predicition resources so you don't use production capacity while testing, but all of the endpoint utterances still go through to the one application).
Once the version is imported, you need to train and publish it. I personally don't have any testing built in, but I'm sure you could build some calls via the LUIS Prediction API and check for expected results. To train, you first need to grab the version, then call the training endpoint.
$res = Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/apps/$appid/versions" -Method 'Get' -Headers $header
$version = $res[0].version
Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/apps/$appid/versions/$version/train" -Method 'Post' -Headers $header
The next part is the most tricky. You can't publish the app until it is done training. To mitigate the risk of trying to publish before it is ready, I have created a separate agent job in my "Train and Publish" task to delay it.
This is typically enough delay, but I also have a check on training status and throw an error if it is not ready. Here is the snippet to get and check status and then publish.
$status = Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/apps/$appid/versions/$version/train" -Method 'Get' -Headers $header
if ($status.details[0].status -ne "Success" -and $status.details[0].status -ne "UpToDate") { throw }
Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/apps/$appid/publish" -Method 'Post' -Body $body -Headers $header
And that should do it! As I mentioned, take care to make sure you define things like the LUIS Key and App ID in each task, as I have not repeated all of those values here. And you can add additional tasks to programmatically export the version (make sure you get the right key for your source app) and test the model as desired.

Search for a repository in our Azure DevOps organization

In our azure devops organization, we have ~100 projects. Each projects holds between 1 and 20 git repositories. This makes it hard to find a specific repository unless you also remember which project it is located in.
The search box at the project list only searches by project names. Is there any way to search and find repository names?
There is a code search, but that returns results from files already in a repository, which gives both redundant and wrong results.
I think the simplest is to call this REST API.
You can call it even from the browser and use the Find feature.
Note that the project element is not required.
To automate, you can use a few lines of Powershell to search in the result JSON document, e.g.
$organization = ...
$PAT = ...a personal access token
$repoNameStart = ...initial name of repo
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("dummy:${PAT}"))
$result = Invoke-RestMethod -Method Get -Uri "https://dev.azure.com/${organization}/_apis/git/repositories?api-version=4.1" -Headers #{Authorization = "Basic $base64AuthInfo" } -Credential $credential -ContentType "application/json"
$result.value | where {$_.name -like "${repoNameStart}*"}
(Untested code, use it as an example)

Azure DevOps Build - Invoke-RestMethod - An item with the same key has already been added error

We have a powershell script as a step in our DevOps build that finds changeset details since the last good build.
$TfsUrl = 'https://' + $RestAPIAccount + '.visualstudio.com/defaultcollection/' + $ProjectName
$BaseUrl = "https://" + $RestAPIAccount + ".visualstudio.com/defaultcollection/_apis/tfvc/changesets"
$ChangeSetHistoryUrl = $TfsUrl + "/_apis/build/builds/$BuildId/changes?api-version=$RestAPIVersion"
$changeSetHistoryDef = (Invoke-RestMethod -Uri $ChangeSetHistoryUrl -Headers $Headers -Method Get).Value
The last statement has starting failing with the following error:
"Invoke-RestMethod : {"$id":"1","innerException":null,"message":"An item with the same key has already been added.","typeName":"System.ArgumentException, mscorlib, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","typeKey":"ArgumentException","errorCode":0,"eventId":0}"
We have been running the same script without any issues for the last year or more.
Any ideas on what could be causing this or how to troubleshoot further.
That's because the build you requested has no changes since the last good build.
Based on my test, if you have 2 build definitions A and B, and they have set the same sources... Edit and modify some files/code then check in the changes.
Trigger build definition A and generate a build#1, this time
it works by calling below REST API:
_apis/build/builds/build#1/changes?api-version=$RestAPIVersion
Then trigger build definition B and generate build#2, even they used the same Source version, but this
time the REST API does not work... and you will get the error message... Because build#2have no changes compare with build#1...
_apis/build/builds/build#2/changes?api-version=$RestAPIVersion (build#2/changes will not work here as no changes....)
Tested with below script: (Allow Scripts to Access OAuth Token)
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds/$env:Build_BuildId/changes"
Write-Host $url
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline:" $pipeline.value | ConvertTo-Json -Depth 100
Our build steps are working this morning, without any changes being made to our process.
Test cases I had used to troubleshoot this issue earlier in the week using particular build id's that were failing are now working also.
Something must have changed by Microsoft which has subsequently been fixed??