1

I have a powershell script, that take my variable and deliver it to the my helm upgrade command

param
(   
    [Parameter(Mandatory = $false)]
    $HELM_SET
)
    helm upgrade --install myrelease -n dev my_service.tgz $HELM_SET 

My HELM_SET var contains:
--set config.vali=x --set config.spring=v1

But helm said after upgrade: Error: unknown flag: --set config.vali helm.go:88: [debug] unknown flag: --set config.vali

if i'm add "--set" into helm upgrade --install myrelease -n dev my_service.tgz --set $HELM_SET and my HELM_SET var now contains: config.vali=x --set config.spring=v1

after upgrade i receive that my config:vali var is x --set config.spring=v1

Can someone explain me what i'm doing wrong?

  • How are you executing this script? Is it a function or just ps1 file with a `param(...)` block? If it's a external script, are you executing it from powershell or from cmd? Do you run it like this: `.\script.ps1 --set config.vali=x --set config.spring=v1` ? – Santiago Squarzon Nov 24 '21 at 23:17

1 Answers1

1

If you're passing $HELM_SET as a single string encoding multiple arguments, you cannot pass it as-is to a command.

Instead, you'll need to parse this string into an array of individual arguments.

In the simplest case, using the unary form of the -split operator, which splits the string into an array of tokens by whitespace:

helm upgrade --install myrelease -n dev my_service.tgz (-split $HELM_SET)

However, if your arguments include quoted strings (e.g. --set config.spring="v 1"), more work is needed, because the quoted strings must be recognize as such, so as not to break them into multiple tokens by their embedded whitespace:

# Note: Use of Invoke-Expression is safe here, but should generally be avoided.
$passThruArgs = (Invoke-Expression ('Write-Output -- ' + $HELM_SET -replace '\$', "`0")) -replace "`0", '$$'

helm upgrade --install myrelease -n dev my_service.tgz $passThruArgs

See this answer for an explanation of this technique.


If you control the invocation of your script, a simpler solution is available:

As Santiago Squarzon points out, you can use the ValueFromRemainingArguments property of a parameter declaration to collect all arguments (that aren't bound to other parameters):

param
(   
    [Parameter(ValueFromRemainingArguments)]
    $__passThruArgs # Choose an exotic name that won't be used in the actual arguments
)

helm upgrade --install myrelease -n dev my_service.tgz $__passThruArgs

Instead of passing the pass-through arguments as a single string, you would then pass them as individual arguments:

./yourScript.ps1 --set config.vali=x --set config.spring=v1
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I'm wondering, wouldn't `param([parameter(ValueFromRemainingArguments)][string]$HELM_SET)` work in this case? – Santiago Squarzon Nov 25 '21 at 00:18
  • With a param block like above and then as an example `bash -c $HELM_SET` if I call the script like `.\script.ps1 sudo apt update && sudo apt upgrade` it works just fine without the need for `-split` or passing the argument as a string using quotes. – Santiago Squarzon Nov 25 '21 at 00:28
  • 1
    Excellent point re `ValueFromRemainingArguments`, @SantiagoSquarzon - please see my update. As for `bash -c`: you're passing a single string to _another_ scripting engine, and _it_ then interprets that string as source code. It is equivalent to calling `eval` on a string from within `bash` / calling `Invoke-Expression` on a string from within PowerShell. – mklement0 Nov 25 '21 at 00:59
  • 1
    Makes sense, it also explains why I must type constraint the argument to `[string]` using this method for `bash -c` but I couldn't think of a binary to test this on. Thanks. – Santiago Squarzon Nov 25 '21 at 01:06