VSTS Build: Replacing token with build number - azure-devops

I'm trying to update a web.config app setting called 'AppVersion' with the build number when building my application in VSTS.
Here are my build steps:
The 'Replace tokens' step converts any variables you set for your build and replaces the tokens you've set in your config files. This part works but what it won't do is get an environment variable like the build number and do a replace. It will just replace whatever text has been specified. Here's my build variables:
So after the build step is completed, my app setting is...
<add key="AppVersion" value="$(BuildNumber)" />
when it should be something like...
<add key="AppVersion" value="20160520.1" />
Can anyone point me in the right direction?
Many thanks.

I did something similar using the "Replace Tokens in **/*config" task.
To update the value for the key "AppVersion" with the current build number, your line should look like the following,
<add key="AppVersion" value="#{Build.BuildNumber}#" />

You can add a PowerShell script task before "Replace Token" task to pass the "BuildNumber" to "AppVersion" variable as following.

In VSTS, use $(Build.BuildNumber) as specified in this doc.
Note that you cannot use $(Build.BuildNumber) to set a variable's value, because it is taken literally; it should be an argument to the task. If your task does not accept it, you can replace with a little Powershell script and the BUILD_BUILDNUMBER environment variable.
param (
[Parameter(Mandatory = $true)]
[String]$fileWithTokens,
[Parameter(Mandatory = $false)]
[String]$tokenRegex = "__(\w+)__"
)
$vars = Get-ChildItem -path env:*
$contents = Get-Content -Path $fileWithTokens
$newContents = "";
$contents | % {
$line = $_
if ($_ -match $tokenRegex) {
$setting = Get-ChildItem -path env:* | ? { $_.Name -eq $Matches[1] }
if ($setting) {
Write-Host ("Replacing key {0} with value from environment" -f $setting.Name)
$line = $_ -replace $tokenRegex, $setting.Value
}
}
$newContents += $line + [Environment]::NewLine
}
Set-Content $fileWithTokens -Value $newContents
```
Source https://github.com/colindembovsky/cols-agent-tasks/tree/master/Tasks/ReplaceTokens

After a day of research, finally found/created a better option than using any random app (Replace Token) from Marketplace.
The option I am talking is already available in VSTS, Azure CLI task.
Here are the stpes:
Add setting BUILD_NUMBER with initial value of 1.0 in appsettings.json
Read appsettings.json in your app and display it. I am sure you all are smart enough to figure out how to use appsettings to display Build Number on your WebApplication.
In Azure Portal, similarly create an App Setting named BUILD_NUMBER with initial value of 1.0 in Azure Application settings section under App Services for your App.
In VSTS, In your Release definition, add a task Azure CLI.
Populate required fields such as Azure Subscription, Script Location with Inline script and last but most important Inline Script with following CLI command
az webapp config appsettings set -n iCoreTestApi -g ArchitectsSandbox -s Dev --settings BUILD_NUMBER=$(Build.BuildNumber)
Command explanation:
iCoreTestApi should be replaced by your real WebApp or Api name in Azure
ArchitectsSandbox should be replaced by your resource group in Azure
Dev is the slot name, you may or may not have it.
Rest of the command remains same.
Once you will queue new build, after successful completion of the deployment, you can see app settings section on Azure is updated with new BUILD_NUMBER.
Let me know if you still have any question.

Related

Set-AzDataFactoryV2Trigger fails in Azure Powershell Task in Release pipeline but works fine on Powershell in frontend machine

I want to create all the triggers in ADF after the Release pipeline has been run successfully . This is because there is a hard 256 parameters limit for ARM template max no. of parameters.
The idea is we will delete all the triggers in DEV, TEST, QA and in PROD. In our published artifact, we would have all the JSONs trigger files using which we can create triggers. The Release pipeline would run a PowerShell script and create the Triggers using Set-AzDataFactoryV2Trigger.
I am able to run the below script correctly on my frontend -
$AllTriggers = Get-ChildItem -Path .
Write-Host $AllTriggers
$AllTriggers | ForEach-Object {
Set-AzDataFactoryV2Trigger -ResourceGroupName "<MyResourceGroupName>" -DataFactoryName "<MyTargetDataFactoryName>" -Name "$_" -DefinitionFile ".\$_.json"
}
In the Azure Powershell script, the first line has to be changed a little to read all the JSON's from the Published Artifact -
$AllTriggers = Get-ChildItem -Name -Path "./_TriggerCreations/drop/" -Include *.json
I receive the below error when trying to run this script via Az Powershell task in the release pipeline (you may note that the error is gibberish) -
The yellow blurred line is the name of the Trigger.
Stuck on this for some time now. Any help would be highly appreciated.
Regards,
Sree

""Your build pipeline references an undefined variable" : it's just a powershell variable

I have a Powershell task in a job in a Pipeline in Azure Devops Server 2020. Here's part of the powershell:
$xml = [xml](Get-Content $configPath)
Write-Output "Iterating over appSettings"
ForEach($add in $xml.configuration.appSettings.add)
{
#Write-Output "Processing AppSetting key $($add.key)"
$SecretVarKey = "MAPPED_"+$add.key
Write-Output $SecretVarKey
$matchingEnvVar = [Environment]::GetEnvironmentVariable($SecretVarKey)
if($matchingEnvVar)
{
Write-Output "Found matching environment variable for key: $($add.key)"
Write-Output "Replacing value $($add.value) with $matchingEnvVar"
$add.value = $matchingEnvVar
}
}
This works fine in the task -- my builds are doing what I want. But when I view the YAML I see comments like this:
#Your build pipeline references an undefined variable named ‘$add.key’. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab. See https://go.microsoft.com/fwlink/?linkid=865972
Again, this doesn't interfere with the execution of the script.
However, now I want to extract this Task into a Task Group. When I do so, the harmless misdetection is now a problem, because it insists these are new parameters:
Is there some magic I can do to change my Powershell script so they are not thought to be parameters?
Your build pipeline references an undefined variable named ‘$add.key’
This is triggered by the line below:
Write-Output "Found matching environment variable for key: $($add.key)"
The $($add.key) is parsed by Azure DevOps as macro syntax. You could avoid this by using string formatting:
'Found matching environment variable for key: {0}' -f $add.key
Btw, in most cases you don't need to use Write-Output - it's slow and superfluous. See this blog post for details: Let’s Kill Write-Output.

Custom variables in TFS Release Management

I'm using TFS 2017.1 Builds and Release feature.
In my release definition, I have a couple of release variables which I need to refer in my PowerShell task (execute on remote machine). So far, I've tried the following options but couldn't get it to work.
Added an Execute PowerShell task to store release variables into Environment variables:
$releaseVaraiables = Get-ChildItem Env: | Where-Object { $_.Name -like "ACL_*" }
Write-Host "##vso[task.setvariable variable=aclVariables]$releaseVaraiables"
Added an Execute PowerShell on remote machine task:
Here I can't read the Environment variables (maybe because this is remote machine task?)
Write-Verbose "problem reading $env:aclVariables" -Verbose
Then I tried passing the environment variable as an argument, but that didn't work either
param
(
$RbacAccessTokenParams
)
$RbacAccessTokenParams.GetEnumerator() | % {$_.Name}
$RbacAccessTokenParams | % {
Write-Verbose "variable is $_" -Verbose
Write-Verbose "name is $_.Name" -Verbose
Write-Verbose "value is $_.Value" -Verbose
}
This is how I passed as argument
-RbacAccessTokenParams $(aclVariables)
What I'm missing here?
I've tested your scenario on my side with TFS 2017.3.1, and it works when pass the environment variable as an argument. You can upgrade your TFS first and try again. Attach my steps for your reference:
1.
2.
3.
4.
Non-secret variables are already stored as environment variables; you do not need to do anything special to access them. You can access them with $ENV:VariableName. Periods are replaced with underscores. So Foo.Bar would be $env:FOO_BAR.
Secret variables should be passed in to the script that requires them.
However, this only applies on the agent. If you're using the PowerShell On Target Machines task to run a script, you need to pass the variables as arguments to the script. There is no way around this, unless you choose to use deployment groups.
Or, better yet, follow a configuration-as-code convention and store application-specific values in source controlled configuration files that your scripts read, so that you are not tightly coupled to your deployment orchestration platform.

Persisting Powershell variables between steps

Am working on VSTS release task for deploying the Web Application along with Database. Unfortunately, we are not creating any Build Definition for creating drop folder. But, my client will provide drop folder for this project, what I need is “I want to copy the files in VM along with creation of System-Timed folder” at release level. For that I created a folder with the help of PowerShell Task.
$FileName = (Get-Date).tostring("dd-MM-yyyy-hh-mm-ss")
$Fname = New-Item -itemType Directory -Path C:\Database -Name ("Test "+ $FileName)
Write-Host "##vso[task.setvariable variable=$Fname;]$Fname"
Write-Output ("##vso[task.setvariable variable=$Fname;]UpdatedValueInScript")
But, I’m not able to use that the above PowerShell Script output variable in next “Copy Files” task.
Note: For creating folder in VM, I followed this link
Your variable name should be static.
The value should change.
Write-Host "##vso[task.setvariable variable=Fname;]$Fname"

How to pass parameters to PowerShell script from TFS build process?

I created a little PowerShell script to change connection string in my web.config.
param([string]$webConfigPath, [string]$connectionStringName, [string]$connectionStringValue)
# get the full path of the web config file
$webConfigFile = [IO.Path]::Combine($webConfigPath, 'Web.config')
# load the XML
$webConfig = [xml](cat $webConfigFile)
#change the appropriate config
$webConfig.configuration.connectionStrings.add | foreach {
if($_.name -eq $connectionStringName){
$_.connectionString = $connectionStringValue
}
}
#save the file
$webConfig.Save($webConfigFile)
I added it to my build process. How to pass the build's variables to the script?
(I use the new script based build process, so I only have a builtin "Arguments" field for the parameter)
You can put all parameters in a single line into Arguments files like this:
-webConfigPath "c:\web.config" -connectionStringName "My connection string"