Install extensions when creating VSTS account with ARM template - azure-devops

I'm using powershell and an ARM template to create a new Team Services account + DevOps Project. Template type: microsoft.visualstudio/account
Is there a way to also install extensions via the template or powershell?
I have a couple of extensions I'm always using, It would be nice to automatically have them up and running on new projects.

thats an interesting question, if this is possible it should be mimicing this rest call.
That is most likely not possible with arm templates. Given this is not under reference on docs and the template says "operation": "link" i suppose there is no way of doing that.

If anybody stumbles upon this same problem, here's how you can do it with powershell.
After creating the VSTS account, you need to log in and create a personal access token with Extensions (read and manage) in selected scopes.
$accountName = "yourAccount"
$personalAccessToken = "your-personal-access-token"
$uri = "https://" + $accountName + ".extmgmt.visualstudio.com/_apis/extensionmanagement/installedextensionsbyname/ms-appinsights/appinsightsreleaseannotations?api-version=5.0-preview.1"
Write-Host "Installing extension: Release Annotations for Azure Application Insights"
Invoke-RestMethod `
-Method Post `
-Uri $uri `
-ContentType application/json `
-Headers #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)")) }

Related

How to create resources in Azure Portal using Devops CI/CD pipeline and ARM Template

I am working on creating qnamaker based Chatbot and for this I have prepared ARM template for creating and deploying resources.
PowerShell script is being used to create knowledge base once all the resources are created.
This process works just fine when I am executing PowerShell script from local PowerShell tool.
Now I want to do CI/CD for this deployment process so that deployment process can be automated
Creating resources and deploying to azure through Pipeline is quite possible through Azure ARM Template deployment task but I am not sure how to execute PowerShell script that is responsible for creating knowledge base once resources are created based on recently created qnamaker service
Any help greatly appreciated
You can refer to Create a CI/CD pipeline for .NET with the Azure DevOps Project for step by step lab to create the pipelines.
If you need help on ARM templates (if you are stuck somewhere), you can check out A quick guide on writing your Azure Resource Manager (ARM) Templates. and get started quickly.
Please clarify that your issue is creating and training the QnA Maker KB after the actual resources have been created by ARM? There are probably multiple ways to do this, but here is what I have done. First of all, I am using the Azure CLI Task version 2.* which simplifies some of the initial steps. You could probably use regular PowerShell for some of the subsequent steps. I have selected all as PowerShell script types and inline scripts. Each of these segments I do as a separate task but you could probably do all as one. I like being able to see which step fails if something happens, though.
First you need to get the key for your cognitive service
$QNAKEY= & az cognitiveservices account keys list -g "YOUR_RESOURCE_GROUP" --name "YOUR_QNA_RESOURCE_NAME" --query key1 -o tsv
Write-Output("##vso[task.setvariable variable=QNA_KEY;]$QNAKEY")
Next you need to create the KB. I have mine seeded with information via a json file in my project repository. You can do this from wherever, or just create a blank KB (I think). Note I'm checking here to see if the KB exists; KB name does not have to be unique, so if you don't do this you will end up creating a lot of duplicate KBs.
$header = #{
"Content-Type"="application/json"
"Ocp-Apim-Subscription-Key"="$(QNA_KEY)"
}
$res = Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/knowledgebases" -Method 'Get' -Headers $header
$kb = $res.knowledgebases | Where-Object name -eq "YOUR_KB_NAME"
Write-Host $res.knowledgebases
Write-Host $kb
if (!$kb) {
Write-Host "KB does not exist, so creating new KB"
$body = Get-Content '$(System.DefaultWorkingDirectory)/PATH_TO_MY_MODEL.json' | Out-String
Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/knowledgebases/create" -Method 'Post' -Body $body -Headers $header
}
Finally, you will likely want to publish your KB. With LUIS I think you need to train it first (via separate CLI task), but QnA Maker you should be able to publish directly. I do this as a dependent stage to ensure the KB is created before I try to publish.
$QNAKEY= & az cognitiveservices account keys list -g "YOUR_RESOURCE_GROUP" --name "YOUR_QNA_RESOURCE_NAME" --query key1 -o tsv
$header = #{
"Content-Type"="application/json"
"Ocp-Apim-Subscription-Key"="$QNAKEY"
}
$res = Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/knowledgebases" -Method 'Get' -Headers $header
$kb = $res.knowledgebases | Where-Object name -eq "YOUR_KB_NAME"
$qnaId = $kb.id
Invoke-RestMethod -Uri "https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/knowledgebases/$qnaId" -Method 'Post' -Headers $header
And that's it! At this point your QnA Maker knowledgebase should be created, published, and ready to go.

connect to tfs with different user by using tfs api

I am trying to run a shellscript program to connect tfs by using tfsapi service.
Jenkins run on logged user but i want to connect tfs with different user (not with windows logged user)
How can i add credential to my powershell code? I use UseDefaultCredentials but need to use different user to connect tfs. how can i do that?
$tfsServerURL = "https://test.tfs.siemens.net/test"
$BuildDefinition = "test.rgs.project"
$URL = "$($tfsServerURL)"
#Get ID of Builddefinition
$buildDefinitionID = (Invoke-RestMethod -Uri ($URL + '/_apis/build/definitions?api-version=2.0&name=' + $BuildDefinition) -Method GET -UseDefaultCredentials).value.id
We can use this official Rest API: Definitions - List to get specific build definition with additional parameter name. And this API supports Oauth2 authentication. However, OAuth 2.0 is not supported on Azure DevOps Server. So we need to use PAT authentication with below least scope: vso.build.
Therefore, if you want to connect tfs with different user using this API, please provide their corresponding PAT, and then below script should work as expected.
$tfsServerURL = "https://test.tfs.siemens.net/test"
$BuildDefinition = "test.rgs.project"
$URL = "$($tfsServerURL)"
$connectionToken="PAT here"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$AzureDevOpsAuthenicationHeader = #{authorization = "Basic $base64AuthInfo"}
#Get ID of Builddefinition
$buildDefinitionID = (Invoke-RestMethod -Uri ($URL + '/_apis/build/definitions?api-version=5.0&name=' + $BuildDefinition) -Method GET -Headers $AzureDevOpsAuthenicationHeader).value[0].id
Write-host $buildDefinitionID

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:

Authenticate Azure Pipelines Powershell task against Azure DevOps Rest API

Requirements
My requirement is that for my Azure devops release pipeline I want to tag a specific commit with an annotated tag which contains the build number and the date (which is auto-set on an annotated tag).
Proposed solution
My solution to this is to use a the Azure Powershell pipeline task, the one shown here:
The task (ignore what's in the script box right now) will use the Azure Subscription that I have set in order to authenticate towards the Azure DevOps REST API. I have successfully been able to perform the task I want using a personal access token (PAT) but this is not stable long-term for a whole team and I want to use our Azure Subscription.
The problem
My problem is that I'm not sure how to use the authentication of the Azure Subscription correctly. I seem to get some data using Get-AzureRmContext (see current code below) and then I found a GitHub issue which seems to do sort of the same thing. The code gets some kind of OAuth token but using the code below, Azure still returns to me that I need to sign in, so I assume it's not the correct token. I don't understand how things hatch into each other.
Note that my subscription should have all the permissions it needs to do what I want.
Code so far:
Function Get-AccessToken($tenantId) {
$cache = [Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::DefaultShared
$cacheItem = $cache.ReadItems() | Where-Object { $_.TenantId -eq $tenantId } | Select-Object -First 1
return $cacheItem.AccessToken
}
$context = Get-AzureRmContext
$uri = "https://dev.azure.com/<my_org>/<my_area>/_apis/git/repositories/<project_sha>/annotatedtags?api-version=5.0-preview.1"
$token = Get-AccessToken $context.tenantID
$body = #"
{
"taggedObject": {
"objectId": "$(BUILD.SOURCEVERSION)"
},
"name": "D-$(Build.BuildNumber)",
"message": "dummy"
}
"#
$header = #{"Authorization" = "Bearer" + $token}
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Body $body -Headers $header
Any help is greatly appreciated!
There is the example for the build tasks: Use a PowerShell script to customize your build pipeline
You have to enable access to token (option Allow Scripts to Access OAuth Token)
Then use it in your script. Script from the example:
$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/definitions/$($env:SYSTEM_DEFINITIONID)?api-version=5.0"
Write-Host "URL: $url"
$pipeline = Invoke-RestMethod -Uri $url -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
}
Write-Host "Pipeline = $($pipeline | ConvertTo-Json -Depth 100)"

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)