Unable to run az pipeline commands within Azure DevOps Task - azure-devops

Trying to dynamically retrieve all the variables from a variable group via Azure DevOps task in a YAML Pipeline. Originally tried leveraging the AzureCLI#2 task with the following code to retrieve the variableGroupID which would be used to get the variables inside of it:
$variableGroupId = $(az pipelines variable-group list --org $(System.CollectionUri) --project $(System.TeamProject) --query "[?name=='{{ parameters.variableGroupName }}'].id" -o tsv)
This command works locally but not when executing on a MS hosted agent like this:
parameters:
variableGroupName: ''
steps:
- task: AzureCLI#2
displayName: Azure CLI
inputs:
azureSubscription: ${{ parameters.azureSubscriptionName }}
scriptType: pscore
scriptLocation: inlineScript
inlineScript: |
az upgrade
$variableGroupId = $(az pipelines variable-group list --org $(System.CollectionUri) --project $(System.TeamProject) --query "[?name=='{{ parameters.variableGroupName }}'].id" -o tsv)
write-Host $variableGroupId
$variables = $(az pipelines variable-group variable list --group-id $variableGroupId --org $(System.CollectionUri) --project $(System.TeamProject) -o yaml)
write-Host $variables
This fails with the error:
Before you can run Azure DevOps commands, you need to run the login command (az login if using AAD/MSA identity else az devops login if using PAT token) to setup credentials. Please see https://aka.ms/azure-devops-cli-auth for more information
I have opened up an issue
In the meantime, I tried to run the commands to install the necessary pieces via scripts
strategy:
runOnce:
deploy:
steps:
- task: AzureRmWebAppDeployment#3
inputs:
azureSubscription: Example - Dev
WebAppName: wapp-Example-dev-eus
Package: $(Pipeline.Workspace)/drop/Web.Example.zip
TakeAppOfflineFlag: True
- task: UsePythonVersion#0
inputs:
versionSpec: '3.x'
architecture: 'x64'
- task: CmdLine#2
displayName: 'Upgrade pip'
inputs:
script: python -m pip install --upgrade pip
- task: CmdLine#2
displayName: 'upgrade azure cli'
inputs:
script: pip install --pre azure-cli --extra-index-url https://azurecliprod.blob.core.windows.net/edge
- task: CmdLine#2
displayName: 'Show Azure CLI version'
inputs:
script: az --version
- task: CmdLine#2
displayName: 'Install Azure DevOps Extension'
inputs:
script: az extension add -n azure-devops
- task: CmdLine#2
env:
AZURE_DEVOPS_CLI_PAT: $(patCredential)
displayName: 'Login Azure DevOps Extension'
inputs:
script: echo ${AZURE_DEVOPS_CLI_PAT} | az devops login
- task: CmdLine#2
displayName: 'Show List of Variables'
inputs:
script: |
$variableGroupId = $(az pipelines variable-group list --org $(System.CollectionUri) --project $(System.TeamProject) --query "[?name=='{{ parameters.variableGroupName }}'].id" -o tsv)
write-Host $variableGroupId
$variables = $(az pipelines variable-group variable list --group-id $variableGroupId --org $(System.CollectionUri) --project $(System.TeamProject) -o yaml)
write-Host $variables
However, when using both latest Ubuntu agents and those designated in the doc get an error:
WARNING: Failed to store PAT using keyring; falling back to file storage.
WARNING: You can clear the stored credential by running az devops logout.
WARNING: Refer https://aka.ms/azure-devops-cli-auth to know more on sign in with PAT.
I have opened up an issue with the documentation team as at the very least the provided steps do not work. Any assistance would be appreciated!

I was getting the same error, and was able to get mine working by adding:
echo $(System.AccessToken) | az devops login
to the top of my inline script. Here's what it looks like:
variables:
variableGroupName: 'my-variable-group'
...
- task: AzureCLI#2
displayName: 'Set environment variables'
inputs:
azureSubscription: '$(azureSubscription)'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
echo $(System.AccessToken) | az devops login
$groupId = (az pipelines variable-group list `
--organization $(System.CollectionUri) `
--project $(System.TeamProject) `
--group-name $(variableGroupName) | ConvertFrom-Json).id
...

You can use the REST API instead of Azure CLI to get the information. It can be used with the standard tools already present on the Microsoft Hosted agents. It requires only vanilla powershell or powershell core, meaning to works on both windows and linux agents. The below example was successfully tested on windows-latest/windows-2019 and ubuntu-latest/ubuntu-20.04
The approach is the same as with Azure CLI.
List all available groups filtered by name to retrieve the variable group in question
Get all variables in the variable group using the variable group id from step
In fact, the pipeline also has an out of the box PAT token available with read access to variable groups. It is stored in the variable System.AccessToken. Using that instead of a manually managed one will further simplify things.
The script below is executed in a pwsh step, which is the built in Powershell task in Powershell core mode
- pwsh: |
# Construct PAT authentication header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "user",$env:SYSTEM_ACCESSTOKEN)))
$headers = #{Authorization=("Basic {0}" -f $base64AuthInfo)}
# Retrieve variable group id. Filter the result by setting the groupName query parameter
$variableGroupId = $(Invoke-RestMethod -Headers $headers "$(System.CollectionUri)$(System.TeamProject)/_apis/distributedtask/variablegroups?groupName=${{ parameters.variableGroupName }}&api-version=6.0-preview.2").value[0].id
# Retrieve variables in variable group with id $variableGroupId
$variables = $(Invoke-RestMethod -Headers $headers "$(System.CollectionUri)$(System.TeamProject)/_apis/distributedtask/variablegroups/${variableGroupId}?api-version=6.0-preview.2").variables
#Print variables as json (for demo purpose)
$variables | ConvertTo-Json
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
displayName: 'Retrieve variables'
Testing the above pipeline in a project on a variable group with two variables yields the following output:
{
"Variable 1": {
"value": "Value 1"
},
"Variable 2": {
"value": "Value 2"
}
}

Related

How to get Secret URI instead of actual secret using AzureCLI#2 Task, to set in Configuration Settings and Ubuntu Agent

Currently trying to get the Azure Key Reference from Key Vault using a DevOps Task.
I have it working for PowerShell but I was moved over to a different agent and now we are using PSCore for the script type. In doing so the previous way no longer works.
How do I do the following with PSCore as a scriptType?
- task: AzureCLI#2
displayName: 'Get KeyVault Secret URIs'
inputs:
azureSubscription: '$(Sub_Dev)'
scriptType: 'ps'
failOnStandardError: true
scriptLocation: 'inlineScript'
inlineScript: |
$Dev_keyVaultName= "$(AppService_Dev)"
$secretNames=(
"ServiceBusConnectionStringKey")
$outputVars=(
"ServiceBusConnectionStringKey")
$x=0
while ($x -lt $secretNames.count)
{
$uri=$(az keyvault secret show --vault-name $Dev_keyVaultName --name $secretNames.get($x) --query id --output tsv)
$secretname = $outputVars.get($x)
echo "##vso[task.setvariable variable=$secretname;]#Microsoft.KeyVault(SecretUri=$uri)"
$x++
}
This will loop through all the specified Keys that I send it and return the Reference to the Key, so that I can store the Reference in the Config instead of the actual Secret.
Using the Next section it will return the actual Secret, but I need the reference?
- task: AzureCLI#2
displayName: 'Get KeyVault Secret URIs'
inputs:
azureSubscription: '$(Sub_Dev)'
scriptType: 'pscore'
failOnStandardError: true
scriptLocation: 'inlineScript'
inlineScript: |
$Dev_keyVaultName= "$(AppService_Dev)"
$(sbConnstring)=$(az keyvault secret show --name "ServiceBusConnectionStringKey" --vault-name $Dev_keyVaultName)

Inconsistent Azure Pipeline. Error: AKV10032: Invalid issuer

We are facing some issues with all the pipeline a specific Azure DevOps project. When we are running it getting below error.
All these projects are calling KeyVault from the code to get the secret during build (we are using Build Cake extension) , it is failing now in pipeline. All these pipelines were working previously, even the pipelines working previously (not modified) also not working under same project.
{"error":{"code":"Unauthorized","message":"AKV10032: Invalid issuer. Expected one of https://sts.windows.net/xxxxxxxxxxxxx/, https://sts.windows.net/xxxxxxxxxxxxx/, https://sts.windows.net/xxxxxxxxxxxxx/, found https://sts.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/."}}
`- task: AzureCLI#2
displayName: 'Cake Build with Azure CLI and Dotnet'
inputs:
scriptType: bash
scriptLocation: inlineScript
azureSubscription: 'Found-TEST'
addSpnToEnvironment: true
inlineScript: |
az account set -s "XXXX-XXXXX-XXXXXX-"
az account list
dotnet run --project ${{parameters.project}}`
Steps/fixes we have followed
Updated PAT Checked Service connection – it is correct
Tried to access KeyVault from pipeline. Working.
Tested the code locally to get the secret – Working
We have set the subscription properly before calling dotnet project
There are few related open issues on github:
[BUG] Since 2 days our pipeline can not get secrets from the keyvault because not the defined TenantId is used #5908
[BUG] Since 2 days our pipeline can not get secrets from the keyvault because not the defined TenantId is used #29902
As a workaround for the moment, you could set the AAD Tenant Id as environment variable (powershell sample):
- task: AzureCLI#2
displayName: 'Cake Build with Azure CLI and Dotnet'
inputs:
scriptType: pscore
scriptLocation: inlineScript
azureSubscription: 'Found-TEST'
addSpnToEnvironment: true
inlineScript: |
az account set -s "XXXX-XXXXX-XXXXXX-"
az account list
$env:AZURE_TENANT_ID = "$($env:tenantId)";
dotnet run --project ${{parameters.project}}

AzureStaticWebApp#0 not recognizing deployment token from variable

Hi have the following code that deploys an artifact to an Azure Static Web App:
...
variables:
- name: staticWebAppDeploymentToken
...
# This steps reads the deployment token of the static web app and assigns it on a variable
- task: AzureCLI#2
displayName: 'Retrieve static web app deployment token'
inputs:
azureSubscription: xxxx
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
output=$(az staticwebapp secrets list --name xxxx-xxxx-$(environment) | jq .properties.apiKey)
echo "##vso[task.setvariable variable=staticWebAppDeploymentToken;]$output"
- task: AzureStaticWebApp#0
inputs:
output_location: '/'
cwd: '$(Pipeline.Workspace)/artifact'
skip_app_build: true
azure_static_web_apps_api_token: $(staticWebAppDeploymentToken)
I get the error:
I've set the System.Debug variable to true, and I see the value is set in the variable. I've also printed the variable and the value is there.
I can't understand what I'm doing wrong. What is the correct way to set a variable in bash and use it on another non-bash step?
I've tried hardcoding the value and also passing it as a parameter from the library, and that works, but that is not what I want.
Test the same script to get the token and pass it to Azure Static web APP task, I can reproduce the same issue.
The root cause of this issue is that when you set the variable in Azure CLI task with the command, the pipeline variable will contain "". For example: "tokenvalue".
The expected deployment token in Azure Static web APP task, it will not contain double quotes.
To solve this issue, you need to add a step in Azure CLI task to remove the double quotes.
Here is an example:
steps:
- task: AzureCLI#2
displayName: 'Azure CLI '
inputs:
azureSubscription: xx
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
output=$(az staticwebapp secrets list --name kevin0824 | jq .properties.apiKey)
var2=`sed -e 's/^"//' -e 's/"$//' <<<"$output"`
echo $var2
echo "##vso[task.setvariable variable=staticWebAppDeploymentToken; isOutput=true]$var2"
- task: AzureStaticWebApp#0
displayName: 'Static Web App: '
inputs:
app_location: /
api_location: api
skip_app_build: false
skip_api_build: false
is_static_export: false
verbose: false
azure_static_web_apps_api_token: '$(staticWebAppDeploymentToken)'

Use variable from AWSCLI in azure pipelines for script

I have a build process where I need to use a token, received through the AWSCLI. So far I have connected aws to my azure pipelines but I am having trouble setting up my yaml.
I want to fetch the relevant token to use it later as a variable in my script.
As you can see in my yaml I am running a powershell script with codeartifact and I am saving the value to my myOutputVar. The powershell script does not throw an error.
However, later when I run the building script that variable is not present resulting in ECHO is off.
How can I ensure the value received in the task can be used later in the script/build part?
trigger:
- azure-pipelines
pool:
vmImage: windows-latest
steps:
- task: NodeTool#0
inputs:
versionSpec: '10.x'
displayName: 'Install Node.js'
- task: AWSPowerShellModuleScript#1
inputs:
awsCredentials: 'AWS Connection'
regionName: 'eu-central-1'
scriptType: 'inline'
inlineScript: '##vso[task.setvariable variable=myOutputVar;]aws codeartifact get-authorization-token --domain somedomain --domain-owner 444.... --query authorizationToken --output text; '
- script: |
echo %myOutputVar%
npm ci
npm run build
displayName: 'npm install and build'
Your inline script can be multiple lines, and since this is PowerShell you can do something like:
inlineScript: |
$authToken = aws codeartifact get-authorization-token `
--domain somedomain `
--domain-owner 444.... `
--query authorizationToken `
--output text
Write-Host "##vso[task.setvariable variable=myOutputVar;]$authToken"

Loop through variables in variable group in Azure Pipelines

In an azure-pipelines.yml file, how do I enumerate all variables defined in a "Variable Group" created in the UI?
I'd like to do this so I can write these variables to a .env file in the pipeline build stage.
There is no difference at pipeline level between variables set in pipeline and those from variable group. But you can use Azure DevOps CLI to achieve your goal.
Please check az pipelines variable-group variable list.
And this is the way how you can call CLI from pipeline - Azure DevOps CLI in Azure Pipeline YAML
Example for LINUX
steps:
# Updating the python version available on the linux agent
- task: UsePythonVersion#0
inputs:
versionSpec: '3.x'
architecture: 'x64'
# Updating pip to latest
- script: python -m pip install --upgrade pip
displayName: 'Upgrade pip'
# Updating to latest Azure CLI version.
- script: pip install --pre azure-cli --extra-index-url https://azurecliprod.blob.core.windows.net/edge
displayName: 'upgrade azure cli'
- script: az --version
displayName: 'Show Azure CLI version'
- script: az extension add -n azure-devops
displayName: 'Install Azure DevOps Extension'
- script: echo ${AZURE_DEVOPS_CLI_PAT} | az devops login
env:
AZURE_DEVOPS_CLI_PAT: $(System.AccessToken)
displayName: 'Login Azure DevOps Extension'
- script: az devops configure --defaults organization=https://dev.azure.com/{OrganizationName} project="Movie Search Web App" --use-git-aliases true
displayName: 'Set default Azure DevOps organization and project'
- script: |
az pipelines variable-group variable list --group-id 45
displayName: 'Show variable group variables'
We could use REST API and power shell script to loop the variable group
Create PAT token, save it to pipeline variable and set it to secret, then add task power shell and enter below script
Power shell script:
$connectionToken="$(pat)"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$URL = "https://dev.azure.com/{Org name}/{Project name}/_apis/distributedtask/variablegroups?groupIds={Variable group ID}&api-version=6.0-preview.2"
$Result = Invoke-RestMethod -Uri $URL -Headers #{authorization = "Basic $base64AuthInfo"} -Method Get
$Variable = $Result.value.variables | ConvertTo-Json -Depth 100
Write-Host $Variable
Result:
You can use Variable Group Formatter extension. In outputFormat you can specify desired format like CLI or JSON
- task: VariableGroupFormatter#0
name: variableGroup
displayName: "Format variables"
inputs:
variableGroupID: '6'
outputFormat: 'JSON'
- script: echo $(variableGroup.formattedVariables)
Result:
Example