I would like to add a schedule on a build definition taken from TFS REST API using PowerShell (add schedule to $buildDef variable on code example).
I get the build definition doing an API request but I'm not able to create a schedule for each week as trigger. I have used below Api for updating the trigger schedule.
$buildDef = Invoke-RestMethod -Method Get -UseDefaultCredentials -ContentType application/json -Uri $TfsBuildDefinitionUri
Any help would be appreciated as I am not able to get it done. Thanks!!
First of all , you have to get the build definition of the ADO build by utilizing below method:
GET https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?api-version=5.1
With additional parameters:
GET https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?revision={revision}&minMetricsTime={minMetricsTime}&propertyFilters={propertyFilters}&includeLatestBuilds={includeLatestBuilds}&api-version=5.1
Then it would give you an array of **[BuildTrigger][1]** then you have to update the schedule of DefinitionTriggerType.
schedule
A build should be started on a specified schedule whether or not changesets exist.
Here is a sample code for updating triggers of a build:
$definitionToUpdate = Invoke-RestMethod -Uri "$($collection)$($project.name)/_apis/build/definitions/$($definition.id)" -Method GET -Header $header
$trigger = $definitionToUpdate.triggers | Where {$_.triggerType -eq 'continuousIntegration'}
if ($trigger) {
$trigger.branchFilters = $branchNames | % {"+refs/heads/$_/*"}
Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions/$($definition.id)?api-version=5.0" -Method PUT -ContentType application/json -Body ($definitionToUpdate | ConvertTo-Json -Depth 10) -Header $header
}
You can refer this thread for further reference, Hope it helps.
Since you already got the build definition. Then you just need to use Definitions - Update Rest API to update
PUT https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?secretsSourceDefinitionId={secretsSourceDefinitionId}&secretsSourceDefinitionRevision={secretsSourceDefinitionRevision}&api-version=5.0
In the request body, there is a BuildTrigger represents a trigger for a buld definition. Which is an array[]. It contain the schedule
string : A build should be started on a specified schedule whether or not changesets exist.
Body sample for your reference:
Content-Type: application/json
{
"id": 29,
"revision": 1,
"name": "myFavoriteDefinition",
"definitionType": "build",
"documentQuality": "definition",
"queue": {
"id": 1
},
"build": [
{
"enabled": true,
"continueOnError": false,
"alwaysRun": false,
"displayName": "Build solution **\\*.sln",
"task": {
"id": "71a9a2d3-a98a-4caa-96ab-affca411ecda",
"versionSpec": "*"
},
"inputs": {
"solution": "**\\*.sln",
"msbuildArgs": "",
"platform": "$(platform)",
"configuration": "$(config)",
"clean": "false",
"restoreNugetPackages": "true",
"vsLocationMethod": "version",
"vsVersion": "latest",
"vsLocation": "",
"msbuildLocationMethod": "version",
"msbuildVersion": "latest",
"msbuildArchitecture": "x86",
"msbuildLocation": "",
"logProjectEvents": "true"
}
},
{
"enabled": true,
"continueOnError": false,
"alwaysRun": false,
"displayName": "Test Assemblies **\\*test*.dll;-:**\\obj\\**",
"task": {
"id": "ef087383-ee5e-42c7-9a53-ab56c98420f9",
"versionSpec": "*"
},
"inputs": {
"testAssembly": "**\\*test*.dll;-:**\\obj\\**",
"testFiltercriteria": "",
"runSettingsFile": "",
"codeCoverageEnabled": "true",
"otherConsoleOptions": "",
"vsTestVersion": "14.0",
"pathtoCustomTestAdapters": ""
}
}
],
"repository": {
"id": "278d5cd2-584d-4b63-824a-2ba458937249",
"type": "tfsgit",
"name": "Fabrikam-Fiber-Git",
"localPath": "$(sys.sourceFolder)/MyGitProject",
"defaultBranch": "refs/heads/master",
"url": "https://fabrikam.visualstudio.com/DefaultCollection/_git/Fabrikam-Fiber-Git",
"clean": "false"
},
"options": [
{
"enabled": true,
"definition": {
"id": "7c555368-ca64-4199-add6-9ebaf0b0137d"
},
"inputs": {
"parallel": "false",
"multipliers": "[\"config\",\"platform\"]"
}
}
],
"variables": {
"forceClean": {
"value": "false",
"allowOverride": true
},
"config": {
"value": "debug, release",
"allowOverride": true
},
"platform": {
"value": "any cpu",
"allowOverride": true
}
},
"triggers": [],
"comment": "renamed"
}
As how to invoke Rest API in powershell, there are multiple samples in google, you could also take a look at this one:
$body = '
{
...
}
'
$bodyJson=$body | ConvertFrom-Json
Write-Output $bodyJson
$bodyString=$bodyJson | ConvertTo-Json -Depth 100
Write-Output $bodyString
$user="name"
$token="PAT"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$Uri = "rest api url"
$buildresponse = Invoke-RestMethod -Method Post -UseDefaultCredentials -ContentType application/json -Uri $Uri -Body $bodyString -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
write-host ....
Finally I created / added an scheduled trigger to my build definition. When the build definition has not any trigger, the property (build object) or json array (build object convert to an array) doesn't exist. So, we've to add it. Here is the solution:
$triggerValue = #"
[
{
"schedules":[
{
"branchFilters":[
"+$/FilterName"
],
"timeZoneId":"W. Europe Standard Time",
"startHours":$startHoursNB,
"startMinutes":$startMinutesNB,
"daysToBuild":"all"
}
],
"triggerType":"schedule"
}
]
"#
$buildDef | add-member -Name "triggers" -value (Convertfrom-Json $triggerValue) -MemberType NoteProperty
Thanks also for help.
Related
Is there any method to add an activation date and expiration when creating secrets through arm template?
When I export the key vault template I see this:
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2021-11-01-preview",
"name": "[concat(parameters('vaults_we_devops_poc_kv_23_name'), '/DBConnectionStringPassword')]",
"location": "westeurope",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaults_we_devops_poc_kv_23_name'))]"
],
"properties": {
"attributes": {
"enabled": true,
"nbf": 1648627063, - secret activation date
"exp": 2027318262 - secret expiration date
}
}
}
I think this integers are unique per secret so I can't just add these two in arm template.
I've already tried to add these two values in the arm template and nothing happens.
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2021-11-01-preview",
"name": "[concat(parameters('vaults_we_devops_poc_kv_23_name'), '/DBConnectionStringPassword')]",
"location": "westeurope",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('vaults_we_devops_poc_kv_23_name'))]"
],
"properties": {
"attributes": {
"enabled": true
}
}
}
The integers are the times in seconds as per the docs, you can calculate their values using PowerShell:
$ActivationTime = Get-Date -Year 2022 -Month 04 -Day 15 -UFormat %s
$ExpiryTime = Get-Date -Year 2022 -Month 05 -Day 15 -UFormat %s
You can then pass those values into a template similar to this:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"activationTime": {
"type": "int"
},
"expiryTime": {
"type": "int"
},
"secretValue": {
"type": "securestring"
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2021-10-01",
"name": "my-key-vault/test-secret",
"properties": {
"attributes": {
"enabled": true,
"exp": "[parameters('expiryTime')]",
"nbf": "[parameters('activationTime')]"
},
"value": "[parameters('secretValue')]"
}
}
]
}
Then deploy that using:
$Value = "my-secret-value"
$SecretValue = $Value | ConvertTo-SecureString -AsPlainText -Force
New-AzResourceGroupDeployment -Name TestSecretTemplate -ResourceGroupName my-resources-rg -TemplateFile .\deployment.json -activationTime $ActivationTime -expiryTime $ExpiryTime -secretValue $SecretValue
I'm hitting an endpoint with this data:
{
"Id": "variableset-Projects-922",
"Variables": [
{
"Id": "30bf54b6-2e07-100f-d9f4-26879b3e9462",
"Name": "test",
"Value": "blah blah",
"Description": null,
"Scope": {},
"IsEditable": true,
"Prompt": null,
"Type": "String",
"IsSensitive": false
}
]
}
Command:
$spaces = Invoke-RestMethod -Method 'Get' -Uri $uri -Headers $header
Result:
#{Id=variableset-Projects-922; Variables=System.Object[];}
Command:
$response = Invoke-WebRequest -URI $uri -Headers $header -Method 'Get' -UseBasicParsing
Result:
{
"Id": "variableset-Projects-922",
"Variables": []
}
Despite testing with | ConvertToJson -Depth 20 the results for the Variables is always coming back as an empty array, what am I missing here?
I am also writing this script inside of a Groovy script in the Jenkins pipeline.
Well I figured it out if anyone else comes across a niche problem like this. The API key I was passing had permissions to some of the data, but not all the data.
I need help in creating a work item with the following PowerShell script, however I get this error:
Invoke-RestMethod : The remote server returned an error: (401) Unauthorized.
At C:\AutoWICreate1.PS1:64 char:11
$result = Invoke-RestMethod -Uri $uri -Method Patch -Body $json -Cont ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebEx
ception
FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Below is the script:
param(
[string]$baseurl = "http://tfs.com:8080/tfs/collection",
[string]$projectName = "teamproject",
[string]$keepForever = "true",
[string]$user = "user-name",
[string]$token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
[string]$title = "POCAutoCreation"
)
Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
function CreateJsonBody
{
$value = #"
[
{
"op": "add",
"path": "/fields/System.Title",
"value": $title
},
{
"op": "add",
"path": "/fields/System.Tags",
"value": "Tag0921;Tag0926;Tag0927;Tag0928"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.Activity",
"value": "Development"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Scheduling.Effort",
"value": "8"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.ValueArea",
"value": "Business"
},
{
"op": "add",
"path": "/fields/Microsoft.VSTS.Common.Severity",
"value": "3 - Medium"
},
]
"#
return $value
}
$json = CreateJsonBody
$uri = "$baseurl/$($projectName)/_apis/wit/workitems/"+"$"+"bug?api-version=5.0"
Write-Host $uri
$result = Invoke-RestMethod -Uri $uri -Method Patch -Body $json -ContentType "application/json-patch+json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
I am trying to retrieve keyVault values within my ARM template
I have enabled my keyVault for ARM template retrieval
My parameter file looks like this
"postleadrequesturl": {
"reference": {
"keyVault": {
"id": "/subscriptions/e0f18fe9-181d-4a38-90bc-f2e0101f8f05/resourceGroups/RG-DEV-SHAREDSERVICES/providers/Microsoft.KeyVault/vaults/MMSG-APIManagement"
},
"secretName": "DEV-POSTLEADREQUEST-URL"
}
}
My deploy file looks like this
{
"properties": {
"authenticationSettings": {
"subscriptionKeyRequired": false
},
"subscriptionKeyParameterNames": {
"header": "Ocp-Apim-Subscription-Key",
"query": "subscription-key"
},
"apiRevision": "1",
"isCurrent": true,
"subscriptionRequired": true,
"displayName": "MMS.CRM.PostLeadRequest",
"serviceUrl": "[parameters('postleadrequesturl')]",
"path": "CRMAPI/PostLeadRequest",
"protocols": [
"https"
]
},
"name": "[concat(variables('ApimServiceName'), '/mms-crm-postleadrequest')]",
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2019-01-01",
"dependsOn": []
},
The error I recieve is
Error converting value "#{keyVault=; secretName=DEV-POSTLEADREQUEST-URL}" to type 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Data.Entities.Deployments.KeyVaultParameterReference
Any thoughts?
According to my test, If we want to integrate Azure Key Vault in your Resource Manager template deployment, please refer to the following steps
Create Azure Key vault
New-AzResourceGroup -Name $resourceGroupName -Location $location
New-AzKeyVault `
-VaultName $keyVaultName `
-resourceGroupName $resourceGroupName `
-Location $location `
-EnabledForTemplateDeployment
$secretvalue = ConvertTo-SecureString 'hVFkk965BuUv' -AsPlainText -Force
$secret = Set-AzKeyVaultSecret -VaultName $keyVaultName -Name 'ExamplePassword' -SecretValue $secretvalue
$userPrincipalName = "<Email Address of the deployment operator>"
Set-AzKeyVaultAccessPolicy `
-VaultName $keyVaultName `
-UserPrincipalName $userPrincipalName `
-PermissionsToSecrets set,delete,get,list
Grant access to the key vault
The user who deploys the template must have the Microsoft.KeyVault/vaults/deploy/action permission for the scope of the resource group and key vault. The Owner and Contributor roles both grant this access.
a. Create a custom role definition JSON file
{
"Name": "Key Vault resource manager template deployment operator",
"IsCustom": true,
"Description": "Lets you deploy a resource manager template with the access to the secrets in the Key Vault.",
"Actions": [
"Microsoft.KeyVault/vaults/deploy/action"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/00000000-0000-0000-0000-000000000000"
]
}
b. Create the new role using the JSON file:
New-AzRoleDefinition -InputFile "<PathToRoleFile>"
New-AzRoleAssignment `
-ResourceGroupName $resourceGroupName `
-RoleDefinitionName "Key Vault resource manager template deployment operator" `
-SignInName $userPrincipalName
Create ARM template
template.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"service_testapi068_name": {
"defaultValue": "testapi068",
"type": "String"
},
"postleadrequesturl": {
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2019-01-01",
"name": "[parameters('service_testapi068_name')]",
"location": "Southeast Asia",
"sku": {
"name": "Developer",
"capacity": 1
},
"properties": {
"publisherEmail": "v-wenxu#microsoft.com",
"publisherName": "test",
"notificationSenderEmail": "apimgmt-noreply#mail.windowsazure.com",
"hostnameConfigurations": [
{
"type": "Proxy",
"hostName": "[concat(parameters('service_testapi068_name'), '.azure-api.net')]",
"negotiateClientCertificate": false,
"defaultSslBinding": true
}
],
"customProperties": {
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls10": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls11": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Ssl30": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TripleDes168": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls10": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls11": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Ssl30": "False",
"Microsoft.WindowsAzure.ApiManagement.Gateway.Protocols.Server.Http2": "False"
},
"virtualNetworkType": "None"
}
},
{
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2019-01-01",
"name": "[concat(parameters('service_testapi068_name'), '/demo-conference-api')]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service', parameters('service_testapi068_name'))]"
],
"properties": {
"displayName": "Demo Conference API",
"apiRevision": "1",
"description": "A sample API with information related to a technical conference. The available resources include *Speakers*, *Sessions* and *Topics*. A single write operation is available to provide feedback on a session.",
"serviceUrl": "[parameters('postleadrequesturl')]",
"path": "conference",
"protocols": [
"http",
"https"
],
"isCurrent": true
}
}
],
"outputs":{
"postleadrequesturl" :{
"type":"String",
"value":"[parameters('postleadrequesturl')]"
}
}
}
paramaters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"postleadrequesturl": {
"reference": {
"keyVault": {
"id": "/subscriptions/e5b0fcfa-e859-43f3-8d84-5e5fe29f4c68/resourceGroups/testkeyandstorage/providers/Microsoft.KeyVault/vaults/testkey08"
},
"secretName": "postleadrequesturl"
}
}
}
}
Deploy
$name = ""
$password = ""
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($name, $secpasswd)
Connect-AzAccount -Credential $mycreds
New-AzResourceGroupDeployment -ResourceGroupName "testapi06" -TemplateFile "E:\template.json" -TemplateParameterFile "E:\parameters.json"
For more details, please refer to
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-keyvault-parameter#grant-access-to-the-secrets
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-tutorial-use-key-vault
I have an internal app that uses a webhook listener and some scripting to manipulate the input data. I'm posting this to it:
curl -X POST -d '{
"assignment_id": 12345,
"updated_custom_fields": [{
"name": "RNVIDAYEBB",
"value": "updated!"
},
{
"name": "QUFTXSIBYA",
"value": "and me too"
}
],
"custom_fields": [{
"id": 981,
"name": "RDEXDPVKRD",
"fields": [
{
"id": 4096,
"name": "RNVIDAYEBB",
"default": "EDJEAJICYW",
"required": true,
"value": "Blah"
},
{
"id": 4097,
"name": "QUFTXSIBYA",
"default": "",
"required": true,
"value": ""
}]
}]
}' "https://hooks.zapier.com/hooks/catch/......"
My script is as follows:
update_custom_fields_by_name_pre_write: function(bundle) {
var updatedFields = _.map(bundle.request.data.custom_fields, function(group) {
return _.map(group.fields, function(field) {
return _.extend(field, _.findWhere(bundle.request.data.updated_custom_fields, { name: field.name} ));
});
});
bundle.request.data = updatedFields;
return bundle.request;
}
I know that the merging logic is good, but it appears that the custom_fields and updated_custom_fields arrays are not present in the bundle.request.data object. Anyone know how to get access to them in the script?
It seems like you should be using update_custom_fields_by_name_catch_hook to capture the incoming static webhook data (instead of _pre_write). If you use that, you can capture the data within bundle.cleaned_request.custom_fields and bundle.cleaned_request.updated_custom_fields.