powershellvariablescurl

powershell variable substitution doesn't work


Sorry if it's a stupid question, but I'm quite new in ps..

Running the curl this way works correctly (mailgun sends an email with attachment):

 curl -s --user 'api:***' `
   https://api.eu.mailgun.net/v3/***.com/messages `
   -F from='Builder <failed-tests@fff-software.com>' `
   -F to=eduard.dubilyer@fff-software.com `
   -F subject='Build failed!!!' `
   -F text='Your build has been failed.' -F attachment='1.txt'

Now trying to add a variable substirution:

 $attstr="-F attachment='1.txt'"
 curl -s --user 'api:***' `
   https://api.eu.mailgun.net/v3/***.com/messages `
   -F from='Builder <failed-tests@fff-software.com>' `
   -F to=eduard.dubilyer@fff-software.com `
   -F subject='Build failed!!!' `
   -F text='Your build has been failed.' $attstr

Looks like the variable is ignored (getting mail w/o attachment)


Solution

  • The command you're actually executing is:

    curl -s --user api:*** `
        https://api.eu.mailgun.net/v3/***.com/messages
        ... etc... `
        -F text='Your build has been failed.' `
        "-F attachment='1.txt'"
    

    Note the double quotes around -F attachment='1.txt' - I don't know how curl interprets that, but it's treating the variable contents as string data rather than as command arguments.

    Splatting

    If you want the individual parts of your string variable to be passed as separate arguments try splatting them as an array instead:

    $cmdargs = @( "-F", "attachment='1.txt'" )
    
    curl -s --user api:*** `
        https://api.eu.mailgun.net/v3/***.com/messages
        ... etc... `
        -F text='Your build has been failed.' `
        @cmdargs
    

    which will execute:

    curl -s --user api:*** `
        https://api.eu.mailgun.net/v3/***.com/messages
        ... etc... `
        -F text='Your build has been failed.' `
        -F attachment='1.txt'
    

    without the surrounding quotes.

    echoargs utility

    A good way to diagnose these sorts of argument-parsing issues is use the echoargs.exe utility with the same arguments as your original command (e.g. curl ...) and see what it outputs to the console...

    PS> $attstr="-F attachment='1.txt'"
    
    PS> c:\src\so\echoargs.exe -s --user 'api:***' `
    >>    https://api.eu.mailgun.net/v3/***.com/messages `
    >>    -F from='Builder <failed-tests@fff-software.com>' `
    >>    -F to=eduard.dubilyer@fff-software.com `
    >>    -F subject='Build failed!!!' `
    >>    -F text='Your build has been failed.' `
    >>    $attstr
    Arg 0 is <-s>
    Arg 1 is <--user>
    Arg 2 is <api:***>
    Arg 3 is <https://api.eu.mailgun.net/v3/***.com/messages>
    Arg 4 is <-F>
    Arg 5 is <from=Builder <failed-tests@fff-software.com>>
    Arg 6 is <-F>
    Arg 7 is <to=eduard.dubilyer@fff-software.com>
    Arg 8 is <-F>
    Arg 9 is <subject=Build failed!!!>
    Arg 10 is <-F>
    Arg 11 is <text=Your build has been failed.>
    Arg 12 is <-F attachment='1.txt'>
    
    Command line:
    "C:\src\so\echoargs.exe" -s --user api:*** https://api.eu.mailgun.net/v3/***.com/messages -F "from=Builder <failed-tests@fff-software.com>" -F to=eduard.dubilyer@fff-software.com -F "subject=Build failed!!!" -F "text=Your build has been failed." "-F attachment='1.txt'"
    

    (scroll to the end of the line to see the double-quoted variable value).

    You can download a pre-built echoargs.exe binary from various locations (make sure you trust the one you use), or the source is available to compile yourself (see this GitHub gist for one version https://gist.github.com/pohatu/80b2b01492b0a22e874e).


    Additional info

    My original answer suggested using curl ... $cmdargs instead of splatting with curl ... @cmdargs - @MathiasR.Jessen is correct to point out that explicitly splatting the variable is the preferred approach.

    An additional comment by @mklement0 says

    array-based splatting is implicitly applied when calling external programs

    so curl ... $cmdargs is logically equivalent to curl ... @cmdargs when $cmdargs is an array, but to make the intent clearer it's probably best to stick to curl ... @cmdargs.