[Environment]::SetEnvironmentVariable Docker on Windows - windows

In my dockerfile I have the line
RUN [Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\oracle\instantclient_19_10", "Machine")
I get this returned, even though when I run the above command in PowerShell everything "just works"
At line:1 char:114
+ ... = 'SilentlyContinue'; [Environment]::SetEnvironmentVariable(Path, $e ...
+ ~
Missing ')' in method call.
At line:1 char:114
+ ... SilentlyContinue'; [Environment]::SetEnvironmentVariable(Path, $env:P ...
+ ~~~~
Unexpected token 'Path' in expression or statement.
At line:1 char:118
+ ... ilentlyContinue'; [Environment]::SetEnvironmentVariable(Path, $env:Pa ...
+ ~
Missing argument in parameter list.
At line:1 char:162
+ ... entVariable(Path, $env:Path + ;C:\oracle\instantclient_19_10, Machine ...
+ ~
Missing argument in parameter list.
At line:1 char:171
+ ... ntVariable(Path, $env:Path + ;C:\oracle\instantclient_19_10, Machine)
+ ~
Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordEx
ception
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall

The error message implies two things:
PowerShell is configured as your default shell in your dockerfile (by default it is cmd.exe)
However, the " characters were stripped from your PowerShell command, which broke it.
Therefore, escape the " character as \":
RUN [Environment]::SetEnvironmentVariable(\"Path\", $env:Path + \";C:\oracle\instantclient_19_10\", \"Machine"\)
Alternatively, you can simply use '-quoting in this case:
RUN [Environment]::SetEnvironmentVariable('Path', $env:Path + ';C:\oracle\instantclient_19_10', 'Machine')
As for why escaping " as \" is needed:
Presumably, what follows RUN is copied as-is to the powershell.exe -Command command line that is used behind the scenes.
During PowerShell's command-line parsing, unescaped " characters are removed before the resulting code is interpreted as PowerShell code. Thus, " characters that must be retained as part of the PowerShell code must be \"-escaped.
See this answer for a detailed explanation.

Note: This answer isn't quite correct, check out the accepted answer https://stackoverflow.com/a/74142485/3684640 for the correct reason for why this is happening
This is an unfortunate clash with Docker's two forms of run commands referenced here https://docs.docker.com/engine/reference/builder/#run.
There's shell form:
RUN (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
And there's exec form
RUN ["executable", "param1", "param2"] (exec form)
In Powershell with the command you're trying to use "[Environment]" is at the beginning which makes Docker think we are in exec form.
A potential fix that works is
RUN ["powershell.exe", "[Environment]::SetEnvironmentVariable(\"Path\", $env:Path + \";C:\\oracle\\instantclient_19_10\", \"Machine\")"]
Which works by using exec form instead of shell form, since this is in json syntax we have to escape all the necessary characters as well.

Related

Running a command on all files in PowerShell command prompt [duplicate]

In GNU/Linux I would do:
PROGPATH=/long/and/complicated/path/to/some/bin
$PROGPATH/program args...
but in Powershell if I try this:
$PROGPATH=\long\and\complicated\path\to\some\bin
$PROGPATH\program args...
I get:
At script.ps1:2 char:...
+ $PROGPATH\program args ...
+ ~~~~~~~~
Unexpected token '\program' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
So how do I do this simple thing I know how to do in bash, in Powershell?
js2010's helpful answer shows the correct solution:
Because your command name/path contains a variable reference ($PROGPATH/...), you must invoke it with &.
The same applies if a grouping expression, (...) is used, or a subexpression, $(...) is involved.
Additionally, the same applies if a command name/path is quoted ('...' or "...")[1], as is required if the path contains spaces, for instance.
To put it differently: Direct invocation is only supported if the command name/path is a verbatim, unquoted string[1]; in all other cases, & must be used.
As for why:
&, the call operator is necessary to force interpretation of a statement as a command, i.e. to have it parsed in argument mode (see below), so as to result in command execution rather than expression evaluation.
PowerShell has two fundamental parsing modes:
argument mode, which works like a traditional shell, where the first token is a command name/path, such as a cmdlet or an external program, with subsequent tokens representing the arguments, which only require quoting if they contain shell metacharacters (chars. with special meaning to PowerShell, such as spaces to separate tokens).
expression mode, which works like expressions in programming languages.
PowerShell decides based on a statement's first token what parsing mode to apply:
If, among other things, the first token starts with a variable reference or is a quoted string, PowerShell parses in expression mode.
In expression mode, \ starts a new token, and unrecognized token \program results in the syntax error you saw.
(If you had used /, it would have been interpreted as the division operator, and program wouldn't be a valid divisor operand.)
[1] Note that if your executable path is a literal string (doesn't contain variable references of expressions) you may alternatively `-escape individual characters (spaces) in lieu of enclosing entire string in '...' or "...", in which case & is then not necessary; e.g.:
C:\Program` Files\Notepad++\notepad++.exe
With a literal string you can even employ partial single- or double-quoting as long as the first token is unquoted; e.g.:
C:\"Program Files"\Notepad++\notepad++.exe
Use the call operator "&". https://ss64.com/ps/call.html
Related: Executing a command stored in a variable from PowerShell
$progpath = 'c:\windows\system32'
& $progpath\notepad somefile.txt
Something with a space:
& 'C:\Program Files\internet explorer\iexplore' yahoo.com
Other options, adding to the path:
$env:path += ';C:\Program Files\internet explorer'
iexplore yahoo.com
And backquoting the spaces:
C:\Program` Files\internet` explorer\iexplore yahoo.com

Escape double quotes in powershell -Command

Due to some limitations, I have to execute the Power Shell command from Windows Command Prompt
powershell -Command "(gc C:\my_configuration.conf) -replace 'INSERT_URL', \`"https://mytestserver/WW48.2'22/testing.bin\`" | Out-File C:\my_configuration.conf"
However, I am constantly getting the ParserError like below
The string is missing the terminator: '.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
How should I properly wrap the URL string with double quotes? Thanks for answering.
Remove the ` before ", and your command should work; that is, when calling powershell.exe from cmd.exe / outside PowerShell, use \" , not \`" (or `") in order to escape " chars.:
powershell -Command "(gc C:\my_configuration.conf) -replace 'INSERT_URL', \"https://mytestserver/WW48.2'22/testing.bin\" | Out-File C:\my_configuration.conf"
While you do need to escape the " characters embedded in your overall "..." command string, escaping them as \" is sufficient - no need to also use `, the backtick, PowerShell's usual escape character.
The PowerShell CLI (powershell.exe) expects \-escaping of ", so as to better align with most CLIs, even though inside a PowerShell session you need to use `" or (inside "..." only) "".[1]
You'd only need both \ and ` - in the form `\", note that ` comes first - if your embedded "..." itself contained " chars; a contrived example:
:: OK: Prints '3" of snow.'
powershell.exe -c " Write-Output \"3`\" of snow.\" "
As iRon notes, an alternative solution is to use embedded '...' quoting (single-quoting) instead.
Since your URL itself contains a ' char., that character must then be escaped as '':
:: Note the use of '...' around https://... and the inner ' escaped as ''
powershell -Command "(gc C:\my_configuration.conf) -replace 'INSERT_URL', 'https://mytestserver/WW48.2''22/testing.bin' | Out-File C:\my_configuration.conf"
[1] In PowerShell (Core) 7+, whose CLI is pwsh.exe, you may alternatively use "" inside overall "..." on the command line too, which is actually the more robust choice when calling from cmd.exe. When calling powershell.exefromcmd.exe, the robust choice is "^""(sic) - see [this answer](https://stackoverflow.com/a/49060341/45375). However, the PowerShell CLI recognizes"in _both_ editions, and"also works for"chars. _not_ inside overall"..."`.
Try using this syntax, always works
"%windir%\System32\WindowsPowerShell\v1.0\powershell.exe" -Command "& { <# PUT ANYTHING HERE #> }"
You won't need to worry about escaping anything.
Your code:
"%windir%\System32\WindowsPowerShell\v1.0\powershell.exe" -Command "& { (gc C:\my_configuration.conf) -replace 'INSERT_URL', "https://mytestserver/WW48.2%2722/testing.bin" | Out-File 'C:\my_configuration.conf' }"
EDIT1: Check here for URL special characters. the single quote (') can be handled by its replacement (%27) in your hard-coded string. (I changed it above in the 2nd code sample)

aws cli command in PowerShell gives Missing argument in parameter list

What specific syntax needs to be changed in the aws s3api put-object-tagging --bucket bucketName --key fileName.tar.gz --tagging TagSet={Key=public,Value=yes} command to prevent the error shown below when the command is run in PowerShell?
Note that the aws s3api put-object-tagging --bucket bucketName --key fileName.tar.gz --tagging TagSet={Key=public,Value=yes} command syntax works perfectly when run in windows cmd on the very same computer.
Here is the PowerShell log including the command and the error message on the same computer where this command works in windows cmd:
PS C:\Users\userName> aws s3api put-object-tagging --bucket bucketName --key fileName.tar.gz --tagging TagSet={Key=public,Value=yes}
At line:1 char:129
+ ... --key fileName.tar.gz --tagging TagSet={Key=public,Value=ye ...
+ ~
Missing argument in parameter list.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingArgument
PS C:\Users\userName>
Also note that I am new to PowerShell. I just sometimes now need to translate short scripts from other languages into PowerShell.
Update:
The answer below addresses your question as asked, based on your (seemingly incorrect) claim that the first command mentioned in your question worked as-is from cmd.exe. The points made below generally apply to the syntax of arguments passed to commands in PowerShell.
Based on a later comment, you state that what solved your problem was to pass a JSON string to the aws CLI's --tagging parameter:
You state that '{\"TagSet\": [{\"Key\":\"public\",\"Value\":\"yes\"}]}' worked for you (which represents the following verbatim JSON string: {"TagSet": [{"Key":"public","Value":"yes"}]).
Here too it is the quoting ('...') that makes the argument work, as discussed in the bottom section.
As an aside: This strange need to manually \-escape " characters embedded in an argument passed to external programs is indeed an - unfortunate - requirement in PowerShell up to at least v7.2.x, due to a long-standing bug. It may get fixed in a future version, which may require opt-in: see this answer.
However, apart from the PowerShell syntax problem that is the subject of your question, it looks like your original command simply used incorrect aws shorthand syntax (a shorter alternative to passing JSON): according to the docs for the put-object-tagging subcommand, the following should work - in addition to the required quoting ('...') for PowerShell's sake, note the [...] around {...} which were missing from your own original command: 'TagSet=[{Key=public,Value=yes}]'
Replace:
TagSet={Key=public,Value=yes}
with:
'TagSet={Key=public,Value=yes}'
That is, quote your argument, which prevents PowerShell from interpreting {...} as a script block, which is what caused your problem.
Note the use of a '...', i.e a single-quoted verbatim string, which is the best choice if an argument contains no embedded variable references or subexpression (for the latter, you need string interpolation in the form of "...", i.e., a double-quoted expandable string).
PowerShell differs from other shells in two notable respects:
its escape character is ` (the so-called backtick), not \ (as in POSIX-compatible shells such as Bash) or ^ (as in cmd.exe)
it has more metacharacters than other shells, such as {, }, and #
See this answer for more information.
As for the specific error message you saw:
The content of a script block ({ ... }) is parsed as PowerShell code, and the content in your case, Key=public,Value=yes, is parsed as a command, whose syntax happens to be invalid:
Key=public is interpreted as a command name
,Value=yes is parsed as its argument, which - due to the , - is parsed as an array, but a literal array passed as an argument must not start with ,, which is what the error message is trying to say: it's missing an array element before ,
You can more easily provoke this error by submitting the following on the command line:
foo , bar # -> Error "Missing argument in parameter list."

Cannot run powershell command via command prompt

I'm attempting to check the RelayForAuth setting for my Windows SMTP Server using the below commands. Powershell appears to display the correct result 'False' but when running the same command via command prompt, it generates an error:
Powershell Example:
([ADSI]"IIS://localhost/smtpsvc/1".RelayForAuth -like "*0*")
Output:
False
Command Prompt Example:
powershell -command "([ADSI]"IIS://localhost/smtpsvc/1".RelayForAuth -like "*0*")"
Output:
At line:1 char:8
+ ([ADSI]IIS://localhost/smtpsvc/1.RelayForAuth -like *0*)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token 'IIS://localhost/smtpsvc/1.RelayForAuth' in expression or
statement.
At line:1 char:8
+ ([ADSI]IIS://localhost/smtpsvc/1.RelayForAuth -like *0*)
+ ~
Missing closing ')' in expression.
At line:1 char:56
+ ([ADSI]IIS://localhost/smtpsvc/1.RelayForAuth -like *0*)
+ ~
Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [],
ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Since you're nesting (embedding) " chars. - to be passed verbatim to PowerShell - inside the syntactic outer double-quoting ("..."), you must escape those nested " chars.
Even though PowerShell-internally ` serves as the escape character, calling the PowerShell CLI (powershell.exe / pwsh) from the outside (cmd.exe) requires \-escaping of ":
# Embedded " chars. must be \-escaped
powershell -command "([ADSI]\"IIS://localhost/smtpsvc/1\").RelayForAuth -like \"*0*\""
Note that you can avoid the need for this escaping if you single-quote the strings inside the overall "..." string.
While this works fine in your case, given that your strings have only verbatim content, note that this is generally only an option if no string interpolation is required:
# Embedded strings use '...' -> no escaping needed.
powershell -command "([ADSI]'IIS://localhost/smtpsvc/1').RelayForAuth -like '*0*'"
Caveat: Using single-quoting to enclose the overall command ('...') does not work as expected from cmd.exe: the latter doesn't recognize these as quoting, and PowerShell simply interprets the string as using its syntax for a verbatim string, and therefore simply prints the contents of the string.
For more information, see this answer.

curl formatting in powershell

I have a curl which works perfectly fine on linux system. I am just remotely triggering a Jenkins job with some parameters.
However the same command in Windows errors out.
curl.exe -k --user abc:xyz -X POST https://myjenkins.com/job/abc/buildWithParameters??token=deploy\&release_version=2.3.1.0-5-auto2\&docker_registry=10.0.0.12:8083\&vcmts_build=vcmts_pi07
Following is the error:
At line:1 char:260
+ ... ??token=deploy\&release_version=2.3.1.0-5-auto2\&docker_registry=96.118.23.36:80 ...
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
quotation marks ("&") to pass it as part of a string.
At line:1 char:293
+ ... .3.1.0-5-auto2\&docker_registry=10.0.0.12:8083\&vcmts_build=vcmts_pi07
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
quotation marks ("&") to pass it as part of a string.
At line:1 char:328
+ ... 0.0.12:8083\&vcmts_build=vcmts_pi07
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
quotation marks ("&") to pass it as part of a string.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : AmpersandNotAllowed
What is the formatting change should i do to avoid this issue?
Wrap your arguments in single quotes, which are not expanded like double-quoted strings.
curl -k --user 'abc:xyz' -X POST 'https://myjenkins.com/job/abc/buildWithParameters?token=deploy&release_version=2.3.1.0-5-auto2&docker_registry=10.0.0.12:8083&vcmts_build=vcmts_pi07'

Resources