Azure pipeline runtime evaluated variable passed a parameter - azure-devops

I have an AzurePowerShell script (powershell/gettenants.ps1) which sets the value of the tenants variable.
The following bash task successfully echos the new value BUT the following template recieves the default value (set at the top of the script). Note Im using expression syntax when specifying the template parameter value.
Any ideas what im doing wrong?
variables:
tenants: "default value"
- stage: Build_Shared_Update
jobs:
- job: Get_all_Tenants_Info
pool:
vmImage: 'windows-latest'
steps:
- checkout: self
fetchDepth: 1
- task: AzurePowerShell#4
inputs:
azureSubscription: 'Product Subscription(Guid)'
targetType: 'filePath'
scriptPath: powershell/gettenants.ps1
errorActionPreference: 'stop'
azurePowerShellVersion: 'latestVersion'
- task: Bash#3
inputs:
targetType: 'inline'
script: echo $(tenants)
- template: pipeline-templates/shared-infrastructure-plan.yml # Template reference
parameters:
tenants: ${{variables.tenants}}
Inside the template the parameter is referenced like this:
-out=sharedplan -var=list_of_tenants=${{parameters.tenants}}

when using ${{ }} syntax that variable is being replace at the compile time.
Read more here:
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#understand-variable-syntax

The variables werent in scope!
Its worth noting that "much to learn" also identified this :)

Related

azure devops , displayname with variable

- job: Display_Version
displayName: Update version $(Number_Version)
steps:
....
I am trying to display a variable which is the variables of the pipeline, and it does not display it ...
Can anyone explain to me why?
To use the pipeline-level variable in the displayName of a job or a stage, you should use the expression '${{ variables.varName }}'. Because the displayName of jobs and stages are set at compile time.
The expression '${{ variables.varName }}' is called template expression which can be used to get the value of variable at compile time, before runtime starts.
The macro syntax '$(varName)' can get the variable value during runtime before a task runs. So, you can use it in the displayName and the input of a task.
For more details, you can see this document.
Below is an example as reference.
azure-pipelines.yml
variables:
Number_Version: 1.1.0
jobs:
- job: Display_Version
displayName: 'Job Name - Update version ${{ variables.Number_Version }}'
pool:
vmImage: ubuntu-latest
steps:
- task: Bash#3
displayName: 'Task Name - Update version $(Number_Version)'
inputs:
targetType: inline
script: echo "Input of task - Update version $(Number_Version)"
Result

How to use variable group as a runtime parameter in azure devops yml

I would like to pass the variable group as a runtime parameter so that whenever I run the pipeline, it should allow me to provide the input variable group name, and based on the input value for the variable group during runtime my pipeline should proceed.
I want to achieve this when we click on the run button, then there's a variable section also. So, I want you to accept the variable group names from there.
Pipeline.yml:
stages:
- stage: VMBackupandValidate
displayName: 'VM Backup and Validate using RSV'
jobs:
- job: VMBackupValidate
displayName: 'Azure VM Backup'
steps:
- task: AzurePowerShell#5
inputs:
azureSubscription: $(azure_sc)
ScriptType: 'FilePath'
ScriptPath: 'pipelines/automation/scripts/vmbackup.ps1'
ScriptArguments: '-ResourceGroupName $(ResourceGroupName) -Storagetype $(Storagetype) -SourceVMname $(SourceVMname) -RSVaultname $(RSVaultname) -Location $(Location) -WorkLoadType $(WorkLoadType) -Policyname $(Policyname) -Verbose'
azurePowerShellVersion: 'LatestVersion'
pwsh: true
Based on comments communication with OP.
I suggest using a parameter with a default value. It will ask you for input if want other values, before you hit run then make a condition to select the right variable based on input.
Here is a minified sample of the pipeline:
parameters:
- name: environment
displayName: Deploy Environment
type: string
default: TEST
values:
- TEST
- PROD
trigger:
- 'none'
variables:
- name: environment
${{ if contains(parameters.environment, 'TEST') }}:
value: TEST
${{ if contains(parameters.environment, 'PROD') }}:
value: PROD
stages:
- stage: TEST
displayName: Build
condition: ${{ eq(variables.environment, 'TEST') }}
jobs:
- job:
pool:
vmImage: 'ubuntu-20.04'
steps:
- script: |
echo ${{ variables.environment}}
displayName: 'Print environment info'
You can extend the logic, or replace it with other values and consume it in code later. You can create multiple stages with conditions as well as shown.
Lets say you have two variable groups with names prod and test. You could use the below pipeline:
trigger:
- main
parameters:
- name: environment
displayName: Where to deploy?
type: string
default: test
values:
- prod
- test
pool:
vmImage: ubuntu-latest
variables:
- group: ${{parameters.environment}}
steps:
- script: |
echo $(ENV)
echo $(VERSION)
displayName: Step 1 - print version and environment
- script: pwd ENV ${{parameters.environment}}
displayName: Step 2 - print parameter
You should define ENV, VERSION values on both variable groups.
Your stage should stay as is. In your case you will delete the steps I provided and use only the first part of the pipeline
Adding a reference article.
https://blog.geralexgr.com/azure/deploy-between-different-environments-with-variable-groups-azure-devops?msclkid=002b01eab02f11ec8dffa95dc3a34094

Azure DevOps yaml: use a powershell task output parameter to generate a loop in dependent job

I have the following yaml as used in an Azure DevOps pipeline (this is not the full pipeline - it's just a portion of yaml that is in a template):
jobs:
- job: CheckExcludedWorkspaces
displayName: Check Excluded Workspaces
pool:
name: DefaultWindows
steps:
- task: PowerShell#2
name: GetWorkspaces
displayName: Check Excluded Workspaces
inputs:
filePath: "$(System.DefaultWorkingDirectory)/pipelines_v2/powershell/checkExcludedWorkspaces.ps1"
targetType: FilePath
errorActionPreference: 'stop'
arguments: -environmentFolder "$(rootFolderPrefix)\${{parameters.environmentFolder}}" -excludeFolderList "${{parameters.tagOutList}}"
pwsh: false
# - ${{ each folder in dependencies.CheckExcludedWorkspaces.outputs['GetWorkspaces.WorkspaceList'] }}:
- job: NewJob
dependsOn: CheckExcludedWorkspaces
variables:
testVar: $[ dependencies.CheckExcludedWorkspaces.outputs['GetWorkspaces.WorkspaceList'] ]
pool:
name: DefaultWindows
steps:
- powershell: |
Write-Host "Test var = $(testVar)"
displayName: Test workspaces output
this works correctly in that the second job retrieves a variable from a powershell task in the previous job and outputs that variable value. The task in the second job outputs a list of apps using variable testVar. The output contains:
app1,app2,app3,app4 etc
I would like to take this the next stage which is I would like to create a loop of jobs that repeated runs for this application list. Something like:
jobs:
- job: CheckExcludedWorkspaces
displayName: Check Excluded Workspaces
pool:
name: DefaultWindows
steps:
- task: PowerShell#2
name: GetWorkspaces
displayName: Check Excluded Workspaces
inputs:
filePath: "$(System.DefaultWorkingDirectory)/pipelines_v2/powershell/checkExcludedWorkspaces.ps1"
targetType: FilePath
errorActionPreference: 'stop'
arguments: -environmentFolder "$(rootFolderPrefix)\${{parameters.environmentFolder}}" -excludeFolderList "${{parameters.tagOutList}}"
pwsh: false
- ${{ each folder in dependencies.CheckExcludedWorkspaces.outputs['GetWorkspaces.WorkspaceList'] }}:
- job: NewJob
dependsOn: CheckExcludedWorkspaces
variables:
testVar: $[ dependencies.CheckExcludedWorkspaces.outputs['GetWorkspaces.WorkspaceList'] ]
pool:
name: DefaultWindows
steps:
- powershell: |
Write-Host "Test var = ${{folder}}"
displayName: Test workspaces output
This code gives me an error:
Unrecognized value: 'dependencies'. Located at position 1 within expression: dependencies.CheckExcludedWorkspaces.outputs['GetWorkspaces.WorkspaceList']
Is there a way i can use a powershell task output variable, to create a list of jobs in a dependent job? The problem is that i don't know at design time what the list of applications will be (the pipeline should ideally find this out when it runs). The list of applications is based on the list of folders that are created within a repository - which changes over time..
In current situation, we cannot use the 'each' key word for the variables. The 'each' keyword is used for the Obj type, but the variable is String.
For more details, you can refer the doc: Each keyword

Azure pipeline set displayname of task based on condition

In the build pipeline I have a job with a powershell script setting the applicatiuon name based on a variable like this:
$applicationName = If ('$(configuration)' -eq 'Release') { 'Appname' } Else { 'Appname-Test' }
Write-Host "##vso[task.setvariable variable=applicationName]$applicationName"
I try to set the display name of the PublishBuildArtifacts#1 variable to the variable like this:
- task: PublishBuildArtifacts#1
displayName: $[variables.applicationName] # runtime variable
But this literally displays $[variables.applicationName] instead of the variable value. How can I change the displayname of a task based on a variable?
You can just use the variable in this way: $(variableName). for example:
pool:
vmImage: 'windows-latest'
variables:
test: "SomeValue"
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: 'Write-Host "Hello World"'
displayName: "The variable $(test)"
The result is:
It doesn't appear that this is currently possible. In both issues I found, they described this as a feature request.
https://github.com/MicrosoftDocs/azure-devops-docs/issues/2327
https://github.com/microsoft/azure-pipelines-yaml/issues/45
I assume ${{..}} is the way to go. You know the configuration at compile time, so you can create the app name at compile time.
variables:
${{ if eq(variables.configuration, 'Release') }}:
applicationName: 'Appname'
${{ if ne(variables.configuration, 'Release') }}:
applicationName: 'Appname-Test'
- task: PublishBuildArtifacts#1
displayName: ${{ variables.applicationName }}

Azure WebApp Deployment task not recognizing variable

When running the following task in a pipeline
- task: AzureRmWebAppDeployment#3
displayName: 'Azure App Service Deploy: Web App'
inputs:
azureSubscription: ${{ parameters.azureSubscription }}
WebAppName: $[dependencies.preDeploy.outputs['webAppName']]
Package: '$(Pipeline.Workspace)/**/PackageTmp'
WebAppUri: WebAppUrl
UseWebDeploy: true
AdditionalArguments: '-useChecksum'
RenameFilesFlag: true
enableXmlVariableSubstitution: true
it complains about the variable I am assigning to the WebAppName
##[error]Error: Failed to get resource ID for resource type 'Microsoft.Web/Sites' and resource name '$[dependencies.preDeploy.outputs['webAppName']]'. Error: {"error":{"code":"InvalidFilterInQueryString","message":"Invalid $filter 'resourceType EQ 'Microsoft.Web/Sites' AND name EQ '$[dependencies.preDeploy.outputs['webAppName']]'' specified in the query string."}} (CODE: 400)
Why is the variable not being replaced with its actual value?
Your variable needs to be addressed by its reference name, which is usually the step name the variable came from.
If you want to make a variable available to future jobs, you must mark it as an output variable using isOutput=true. Then you can map it into future jobs using $[] syntax and including the step name which set the variable.
More reading about Multi-job Variables
See myVarFromJobA: $[ dependencies.A.outputs['setvarStep.myOutputVar'] ]
in the below example.
jobs:
# Set an output variable from job A
- job: A
pool:
vmImage: 'vs2017-win2016'
steps:
- powershell: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the value"
name: setvarStep
- script: echo $(setvarStep.myOutputVar)
name: echovar
# Map the variable into job B
- job: B
dependsOn: A
pool:
vmImage: 'ubuntu-16.04'
variables:
myVarFromJobA: $[ dependencies.A.outputs['setvarStep.myOutputVar'] ] # map in the variable
# remember, expressions require single quotes
steps:
- script: echo $(myVarFromJobA)
name: echovar