''kubectl patch' works on Linux Bash but not in Windows Powershell ISE
The following command works fine on Ubuntu bash:
kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template": {"metadata": {"labels": {"date": "test"}}}}}'
The same command does not work in Windows Powershell Console (ISE).
The error is:
kubectl : Error from server (BadRequest): invalid character 's' looking for beginning of object key string
At line:1 char:1
+ kubectl patch deployment wapi-backend-d1 --patch '{"spec": {"template ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Error from serv...ject key string:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
The powershell console version is:
PS > $PSVersionTable
Name Value
---- -----
PSVersion 5.1.14409.1005
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1005
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
I have tried the command with a different patched value too as I saw somebody write that patch may fail if it is already applied.
The path /spec/template/metadata/labels/date indeed exists in the deployment's yaml, so that isn't a problem either.
I presume that it might have something to do with kubectl working differently in Powershell in relation to quotes, but could not find a way to make it work.
I have tried
kubectl patch deployment wapi-backend-d1 --patch "{\"spec\": {\"template\": {\"metadata\": {\"labels\": {\"date\": \"test123\"}}}}}"
But that results in
Error from server (NotFound): deployments.extensions "spec\\: {\\template\\: {\\metadata\\: {\\labels\\: {\\date\\: \\test123\\}}}}}" not found
What should be the command on Powershell?
Solution 1:[1]
You've found the right solution in your own answer, but let me try to break it down conceptually:
Embedding " (double quotes) in string arguments passed to external programs:
(a) First - sensibly and unavoidably - you need to satisfy PowerShell's syntax requirements with respect to embedding
"chars. in quoted strings.(b) Then - and this step shouldn't be necessary - you need to
\-escape embedded"chars. that you want external programs to see.- This is a longstanding, irksome bug present up to at least PowerShell 7.2, which may get fixed in 7.3 - see this answer.
Re (a), you have the following options:
'...'-quoting (single-quoting), inside of which you can use"as-is:'{ "spec": "none" }'- Everything inside
'...'is taken literally - no expansion (interpolation) takes place.
"..."-quoting (double-quoting), inside of which you can use`"or""to embed"chars:"{ `"spec`": `"none`" }"-`is PowerShell's general escape char."{ ""spec"": ""none"" }"-"-specific escaping (doubling)- The content of
"..."is subject to expansion (interpolation), meaning that you can reference variables ($var) or subexpressions ($(1 + 2)) inside such strings, which PowerShell replaces with their values - see this answer for more about PowerShell's expandable strings.
If you're passing such a string to other PowerShell commands (cmdlets, functions, or scripts), no further action is needed; e.g.:
PS> Write-Output '3" of rain'
3" of rain
Re (b) - i.e. to pass such strings to external programs - you additionally need to \-escape the embedded " chars.:
Applying manual escaping to the examples above:
'{ \"spec\": \"none\" }'"{ \`"spec\`": \`"none\`" }""{ \""spec\"": \""none\"" }"
Applying the escaping programmatically to a preexisting string:
Replace verbatim
"with verbatim\", as well as any preexisting, immediately preceding\with\\:$str = '3" of rain'; $escapedStr = $str -replace '([\\]*)"', '$1$1\"'That is, for an external program to ultimately see value
3" of rainverbatim, you must pass literal value3\" of rainfrom PowerShell. This\-escaping is something that PowerShell, as a shell, should do automatically behind the scenes, but currently doesn't.
There's an additional bug in Windows PowerShell - since fixed in PowerShell Core - that mishandles strings with unbalanced embedded
"chars. if a"is part of the first word:- E.g., the above techniques do NOT work with literal values such as
3" of rain; that is, escaping this as'3\" of rain'does not work as expected - instead, you must use the following monstrosity:`"3\`" of rain`", which is technically a series of separate, unquoted arguments, which means that (a) multiple spaces between the words of the strings aren't supported (they are collapsed to a single space) and (b) PowerShell metacharacters such as& < > $ & | @ {must be individually`-escaped. - Note that the bug surfaces only if the
"is part of the first word in the value, and only if that first word is not preceded by whitespace (though arguments with leading whitespace are rarely useful); e.g.,'3 \" of rain'would again work, because the unbalanced"is not part of the first word.
- E.g., the above techniques do NOT work with literal values such as
Example:
The following uses choice.exe as an example external program, because it can be repurposed (via options /d Y /t 0) to merely echo the prompt string it is given, which shows how it received the string passed from PowerShell:
& {
# Note: For preview versions of v7.2, deactivate the experimental
# feature that fixes the problem, so as to show the original problem.
$PSNativeCommandArgumentPassing = 'Legacy'
# Use manual \-escaping to pass what should be received as
# verbatim { "spec": "none" } to an external program.
choice /m '{ \"spec\": \"none\" }' /d Y /t 0
}
The above outputs { "spec": "none" } [Y,N]?Y, showing that the manually escaped " chars. were received as verbatim " chars. by the external program.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
