0

Im using AzureDevops for my pipelines using Powershell as scripting option.

During the steps i read secrets from Hashicorp Vault and load them as env Vars. that way i can use them by addressing : $(secret1)

These secrets will be inserted into a web.config file at the specific elements, each secret has its own placeholder, secret env var name is matching each elements' name field in the web.config

web.config fragment:

<connectionStrings>
    <add name="ServiceBusConnectionString"
         connectionString=""
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    <add name="Hc24DbConnectionString"
         connectionString=""
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    <add name="CacheStorageConnectionString"
         connectionString=""
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    <add name="AzureStorageConnectionString"
         connectionString=""
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    <add name="EmulatorConnectionString"
         connectionString=""
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    <add name="MongoDbConnectionString"
         connectionString=""
         xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
  </connectionStrings>

the value of "connectionString" would be replaced according to connectionStrings.add.name

Im trying to achieve that with this Powershell logic:

$names = $xmlObject.configuration.connectionStrings.add.name

$($name)
foreach ($name in $names)
{
    Write-Host "name is $name"
    $connectionstring = $xmlObject.configuration.connectionStrings.add | ?{$_.name -eq $name}
    Write-Host "Connection String name is"$connectionstring.connectionString
    Write-host "Name ENV var is :" "`$($name)"
    $xmlObject.Save('Web.$(Release.EnvironmentName).config')
}

Currently im not able to get the value of the secret, but only the name of the variable.

F.E, my Write-Host will get me: Name ENV var is : $(ServiceBusConnectionString)

Any ideas what i may be missing ?

1
  • I'm not quite following either what you're trying to do or what isn't working. When you say you're "not able to get the value of the secret", do you mean that the line that starts with Write-Host "Connection String name is" isn't outputting what you expect? In your example, those are empty so the result would be empty (but maybe that's because you redacted them in your post). And how are you expecting to get the values of the credentials into this script? I don't see anything that's doing that. Commented Oct 4, 2020 at 19:28

2 Answers 2

2

As it is written here

On UNIX systems (macOS and Linux), environment variables have the format $NAME. On Windows, the format is %NAME% for batch and $env:NAME in PowerShell.

System and user-defined variables also get injected as environment variables for your platform. When variables are turned into environment variables, variable names become uppercase, and periods turn into underscores. For example, the variable name any.variable becomes the variable name $ANY_VARIABLE.

You should know also, that for secrets you need to define a mapping

variables:
 GLOBAL_MYSECRET: $(mySecret) # this will not work because the secret variable needs to be mapped as env
 GLOBAL_MY_MAPPED_ENV_VAR: $(nonSecretVariable) # this works because it's not a secret.

steps:

- powershell: |
    Write-Host "Using an input-macro works: $(mySecret)"
    Write-Host "Using the env var directly does not work: $env:MYSECRET"
    Write-Host "Using a global secret var mapped in the pipeline does not work either: $env:GLOBAL_MYSECRET"
    Write-Host "Using a global non-secret var mapped in the pipeline works: $env:GLOBAL_MY_MAPPED_ENV_VAR" 
    Write-Host "Using the mapped env var for this task works and is recommended: $env:MY_MAPPED_ENV_VAR"
  env:
    MY_MAPPED_ENV_VAR: $(mySecret) # the recommended way to map to an env variable

Ao if you need to get env variable dynamically, you should do something like this:

$envVar = ("env:" + $name.ToUpper())
$envValue = Get-ChildItem $envVar | select value

Write-Host $envValue.Value

If I understood you, sth like this should work for you.

$names = $xmlObject.configuration.connectionStrings.add.name

foreach ($name in $names)
{
    Write-Host "name is $name"
    $connectionstring = $xmlObject.configuration.connectionStrings.add | ?{$_.name -eq $name}
    Write-Host "Connection String name is" $connectionstring.connectionString
    
    $envVar = ("env:" + $name.ToUpper())
    $envValue = Get-ChildItem $envVar | select value

    $connectionstring.SetAttribute("connectionString", $envValue.Value)
    
}
$xmlObject.Save('Web.$(Release.EnvironmentName).config')
Sign up to request clarification or add additional context in comments.

10 Comments

The overall problem is not using those secrets. The issue is that my secrets are pulled from Vault. And i want dynamically, to address them, according to the field name that i priorly take from the web.config file. After that i inject them into the web.config.
1. lets say i read from the XML file 3 vars, named a,b,c. I then want to address to env var (which is already loaded in my vars), as $(a) or $(b) or $(c) respectfully. 2. i read XML file with 2 vars, named aa,bb. I then want to address to env var (which is already loaded in my vars), as $(aa) or $(bb) respectfully.
I'm not sure what is the question :(
Prolly bad explanation on my end. I have a script (powershell), that parses XML object and finds fields (can be 3,5,10 doesnt matter), and according to those field's names i want to address the ENV var. Running in a loop, Get var name from XML => $name => wrap it in $($name) => replace $name with var name => $(VARNAME) => insert value into XML. $name=>$($name)=>$(VARNAME)=>use as Env Var. Something like that
@IlyaGurenko please create a new question I feel that it would be difficult to answer for it in a comment :)
|
1

Currently im not able to get the value of the secret, but only the name of the variable.

In my opinion, the behavior you met is more about PS syntax. It's just that PS doesn't support evaluating nested variables using this format "`$($name)".

You're trying to evaluate the $($name) twice: $($name)=>$(ServiceBusConnectionString)=>Return value of ServiceBusConnectionString. However $($var) is not used to give the value of nested variable, that's why we always get $(ServiceBusConnectionString).See similar topic here.

3 Comments

Yes, this is exactly what im trying to do. As the var names can be changed, and i want to handle them dynamically
What's the specific reason for dynamically getting the connection name value? Have you ever considered xml transformation?
Thanks for giving a thorough explanation, it really made some sense. Yet as from the topic it seems i cannot do what ive intended doing. Ty thou

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.