Powershell - Using a variable inside a variable - azure

I am trying to leverage Powershell with Azure CLI commands to create variables in an Azure DevOps variable group.
This is typically done using this command:
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value "valueforthevariable"
Since this command is run in a powershell task in my AzureDevOps pipeline, the value comes from a previous step in the pipeline
In short lets assume that the name of the variable (coming from the previous step) is vmStorageAccountName then the following command works perfectly:
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value $(StepsOutputs.vmStorageAccountName)
StepsOutputs being the name of the previouspipeline step.
However since I am getting multiple outputs from the previous step I don't want to manually modify the value name multiple times.
So I have a list of 3 outputs, for example:
$outputs = 'vmstorageAccountname', 'VnetName', 'Rgname'
I tried the following classic loop:
foreach ($output in $outputs) {
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value "$("StepsOutputs.$output")"
But when doing that it takes StepsOutputs.vmstorageAccountname string (or any of the other outputs) as the value for the variable to be created in the variable group. When what I was expecting was to get the vmstorageaccountname itself as we do when not using the loop.
So I guess there is something wrong in the way I am filling the value argument in the command, using a variable inside a variable. I have trying many ways of writing the value arugment but none of them worked. Again if I am not using a loop and the $output variable, this works fine.
To summarize, what I would like is to first have StepsOutputs.$output translated to something like StepOutputs.vmstorageaccountname and then the value should be filled using $(StepOutputs.vmstorageaccountname)
I hope that is clear.
Thank you for your help.

Glad that #user2154222 for solved the issue. Thank you #mclayton for your suggestions that helped to fix the issue. Posting this on behalf of your discussion so that it will be beneficial for other community members.
Using single quotes fix your issue
# with single quotes
# without using additional string while passing value
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value '$($StepsOutputs.vmStorageAccountName)'
Adding some more information to fix the issue:
If you are adding some additional string in your pipeline --value, you have to keep (double quotes) "". or just pass the variable value.
# without quotes
# without using additional string while passing value
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value $($StepsOutputs.vmStorageAccountName)
#using Double Quotes
# using additional string as TESTAPP-$($StepsOutputs.vmStorageAccountName)
az pipelines variable-group variable create --group-id "variablegroupid" --name "nameofthevariabletoadd" --value "TESTAPP-$($StepsOutputs.vmStorageAccountName)"

Related

How to get the id of a VM in azure where power state is running and a specific tag is null?

So I am trying to get the ID of all VMs across all subscriptions and regions, where a specific tag is null. For this I am using the following command
az vm list -d --query '[?!not_null(tags.run)]|[].id'
Please note: I want to get the ids only if the tag doesn't exist
Here notice I need to use single quotes to cover the query as I am using the '!' operator to inverse the not_null() function. If I were to use double quotes bash will throw an event not found error.
So now the problem arises when I also want to add a condition to check the current state of the VM and return id only if it is running and tag doesn't exist.
az vm list -d --query '[?!not_null(tags.run)] | [?powerState=="VM running"].id'
Here I have to wrap VM running in double quotes and this gives me an empty output as the string is not being matched because the query expects single quotes like so -
"[?powerState=='VM running'].id"
Could someone help me with a workaround for this?
Use raw string literals for VM running string. You just have to surround your string with a back tick and a double quote.
az vm list -d --query '[?!not_null(tags.run)]|[?powerState==`"VM running"`].id'

Assign Azure Powershell variable to DevOps Pipeline variable

How can I assigned the $NewIP variable precalculated in this step to a DevOps pipeline variable called $pipeline_ip?
You should use logging command if you want to assign powershell variable to Azure DevOps variable
echo "##vso[task.setvariable variable=pipeline_ip;]$NewIP"
Update after clarification:
If you use syntax like:
$NewIP = $(pipeline_ip)
Then $(pipeline_ip) would be replaced with the value before script will be executed.
And if you use syntax like
$NewIP = $env:PIPELINE_IP
then you will refer to environment variable and since all DevOps variables are mapped (except secret variables - here you need to express this excplicitly) it would also work.
However, these are two ways of doing that.
You can use two methods:
$NewIP = $(pipeline_ip) Macro syntax variables
$NewIP = $env:PIPELINE_IP Set variables in pipeline

How can assign the value of a sensitive output variable to an environment variable?

I am automating my terraform script in a GitHub Workflow
In my terraform script, I have a sensitive output variable like this:
output "db_password" {
value = aws_db_instance.db.password
description = "The password for logging in to the database."
sensitive = true
}
I am deploying (terraform apply) the script in a GitHub action workflow.
After a successful deployment, I need to store the password in a secured storage (Azure KeyVault) . I have a bash command to do that.
I need to have the value of the db_password in an environment variable.
How can I assign the value of a sensitive output variable to an environment variable?
Is there a better way of doing this?
I suggest to use terraform output after terraform apply. And then you can store the output to a Bash/shell variable or a file without it being printed out.
e.g.
terraform apply # as before
MY_SECRET=$(terraform output db_password)
azureInterface keyvault store $MYSECRET # a totally made-up line, no clue about Azure
The drawback is that it might:
show up in the console output for the last command
is visible in ps as command line argument
So a revised solution is to store in a temporary file
CREDENTIALS=$(mktemp -t tmp.XXXXXXXXXX)
terraform output db_password >$CREDENTIALS
# and now use the $CREDENTIALS file as input to Azure
rm -rf $CREDENTIALS

How to find length of result array in Azure CLI via JMESPath?

I am trying to "explore" json results from an Azure CLI command using the --query switch (e.g. az functionapp list --query <something>), and to get started I'd like the length of the resulting array.
The Azure CLI help says nothing specific, and points to jmespath.org which does indeed show that a length function exists, however it seems to require an argument. I have no name for the argument, which is the root/outermost array returned by the list command.
It seems from jmespath.org that length(something) is what I want, but I don't know what to put in for the "something" part. What do I put here? Or am I going about this all wrong??
As we know az functionapp list returns a json where the root node is an array. In order to get the length of this array we can use the following syntax:
az functionapp list --query "[] | length(#)"

How to unpack or fetch a value of a nested variable stored in Azure DevOps Build Piplines' Variables group?

Is it possible to use variable inside a variable in Powershell script with Azure Pipelines variables?
SCENARIO
Two variables are set in Azure Pipelines Variable group - DeploymentCredentials
a. DeployUATApiPassword = "123456"
b. DeployPRODApiPassword = "789654"
Another variable is set in the Variables section of the pipeline as DeploymentEnvironment
At runtime, the value of the DeploymentEnvironment variable is set as either UAT or PROD
Based on the enviornment, I want to fetch the password which is stored as a variable, defined in the variables group. At runtime, it should work something like...
# setting the value of the variable to UAT
Write-Host "##vso[task.setvariable variable=DeploymentEnvironment]UAT"
Now DevelopmentEnvironment variable has the value UAT, In another step, I want to fetch the Password for the UAT deployment environment, which is only known at runtime.
# I want to get the Password
# The following works! but not useful for me, UAT is hard-coded!!
$deployPwd = $(DeployUATApiPassword) # works! but not useful for me, UAT is hard-coded!!
# I want to get the Password
# the following doesn't work, I only know the environment at runtime
# Replaces the inner variable to `DeployUATApiPassword`
# Raises an error, DeployUATApiPassword : The term 'DeployUATApiPassword' is not recognized as the name of a cmdlet...
$deployPwd = $(Deploy$(DeploymentEnvironment)ApiPassword)
# All the following didn't work either, but no error...
Write-Host $('Deploy$(DeploymentEnvironment)ApiPassword') # Output: DeployUATApiPassword
Write-Host $($("Deploy$(DeploymentEnvironment)ApiPassword")) # Output: DeployUATApiPassword
Write-Host { 'Deploy$(DeploymentEnvironment)ApiPassword' } # Output: 'DeployUATApiPassword'
Write-Host { Deploy$(DeploymentEnvironment)ApiPassword } # Output: DeployUATApiPassword
Write-Host { $(Deploy$(DeploymentEnvironment)ApiPassword) } # Output: $(DeployUATApiPassword)
Similarly, I tried to fetch the pwd in several ways, nothing worked.
For instance, one of the ways was to create another variable DeployApiPassword and I did set the value of the variable to Deploy$(DeploymentEnvironment)ApiPassword. No luck in this either...
$deployPwd = $(DeployApiPassword) # Output: DeployUATApiPassword
DESIRED OUTPUT
I want to fetch the password from one of the variables which is set in a variables group. The password variable name contains the deployment environment. Deployment environment is only set at runtime.
# I know something is wrong with the following, but that's how I want to run.
$deployPwd = $(Deploy$(DeploymentEnvironment)ApiPassword)
Write-Host $deployPwd # output: *** (of course, the pwd is hidden, but at least it fetches)
Variables set in Azure Pipelines Variable group would be used as environment variables in PowerShell task. So, basically, you need to get the value as :
$environment = $env:DeploymentEnvironment
$deployPwd = $env:DeployUATApiPassword
At the same time, as your want to dynamically get the password based on the environment, you may try the following:
$environment= $env:DeploymentEnvironment
Write-Host "Deployment Environment is " $environment
$realName = $("Deploy${environment}ApiPassword")
$pwd = [Environment]::GetEnvironmentVariable($realName)
#I used UAT password, check it here
Write-Host $pwd.Equals("123456")
Output:
I noticed that the value returned by 'Deploy$(DeploymentEnvironment)ApiPassword' is a string type, however $() accepts a variable not a string.
In the secret variables official document, it says the secret cannot be referenced directly like normal variable. You have to manually explicitly map them in using the Environment section.
You will need to use if statement. And in the Environment Variables sections
Map the secret variables to variables UATpassword and PRODpassword and Then refer to them in the scripts using $env:UATpassword
From below log, we can see the password is retrieved in the script.

Resources