Escape double quotes in powershell -Command - windows

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)

Related

[Environment]::SetEnvironmentVariable Docker on 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.

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.

Change line in JS file in a post-build event (Visual Studio)

I have a JS file that has a path field that needs to be updated on deployment. I don't see that post build events allow the replacement of text or a full line by themselves, so I created a batch file to do so. However, I'm getting some odd errors.
Trying to replace the strings using a batch with powershell throws errors with the single quotes being escaped:
powershell -Command "(gc Utility.js) -replace 'var applicationRoot = \'\/WebApplication;\'', 'var applicationRoot = \'\';' | Out-File -encoding ASCII myFile.txt"
Taking out the single quotes to see if it will at least run gives an unidentified error:
powershell -Command "(gc Utility.js) -replace 'var applicationRoot = \/WebApplication;', 'var applicationRoot = ;' | Out-File -encoding ASCII myFile.txt"
I'm calling it as a post build event:
call "$(SolutionDir)Scripts\ChangeJSFile.bat"
Any ideas?
Personally, I'd do this a bit differently.
Assume you have a Powershell script named _PostBuild.ps1 in the root of the project where Utility.js lives. That .ps1 script has the following contents:
param(
[string] $pathToJsFile,
[string] $toReplace = "var applicationRoot = '/WebApplication';",
[string] $replaceWith = 'var applicationRoot = ;'
)
$fileContent = Get-Content -Path $pathToJsFile
$newContent = $fileContent.Replace($toReplace, $replaceWith)
Set-Content -Path $pathToJsFile -Value $newContent
Then, assume that the aforementioned project has a post-build actions such as the below:
Powershell.exe -ExecutionPolicy Bypass -NoProfile -NonInteractive -Command "$(ProjectDir)\_PostBuild.ps1" -pathToJsFile "$(ProjectDir)\Utility.js"
That will allow you to perform a string replace on Utility.js on successful build.
Obviously, you may want to make some edits to the post-build action based on your project structure.
It was a slight nightmare but I think I have a solution for you. Basically the only issue was where you were escaping.
powershell -Command "(gc Utility.js) -replace \"var applicationRoot = '/WebApplication;'\", \"var applicationRoot = ';'\" | Out-File -Encoding ascii myFile.txt"
The problematic part is passing the innermost single quotes literally to PowerShell. Literal quotes inside of quotes of the same type will need some kind of escape. You have that case here since your -replace components are surrounded by single quotes but are intending to match literal single quotes. In those cases, you can simply use two single quotes, which escapes one single quote.
powershell -Command "(gc Utility.js) -replace 'var applicationRoot = ''/WebApplication;''', 'var applicationRoot = '''';' | Out-File -encoding ASCII myFile.txt"

How set preference `$ErrorView = "CategoryView"` before start powershell.exe

How to set preference $ErrorView = "CategoryView" before start powershell.exe ?
powershell.exe -command "$ErrorView = "CategoryView" ; dir wrong.txt" doesnt work.
your code has a serious error in it. you used 4 double quotes instead of two on the outside and a pair of single quotes on the inside. [grin]
this works ...
powershell.exe -command "$ErrorView = 'CategoryView' ; dir wrong.txt; pause"
remove the pause when you are certain things are working as needed. [grin]
To complement Lee Dailey's helpful answer: As Lee points out, your primary problem is that you neglected to escape the " chars. embedded in your overall "..." command.
Assuming that you're calling your command from outside of PowerShell, such as from cmd.exe (Command Prompt):
Using embedded single-quoting ('...') in lieu of the embedded "..." is an option in this case, as shown in Lee's answer, because CategoryView is to be treated as a literal string.
Using ' for the embedded quoting conveniently obviates the need for escaping.
However, in cases where the embedded string contains variable references (e.g., $var) or expressions (e.g, $(Get-Date)), use of a double-quoted string ("...") is a must, because only double-quoted strings are expandable (interpolated). Escaping the embedded " as \" is then a must.
Note that, by contrast, inside PowerShell " chars. must be escaped as `".
# From cmd.exe, for instance.
C:\>powershell.exe -command "$ErrorView = \"CategoryView\"; dir wrong.txt"
If, for some reason, you must invoke another PowerShell instance from within PowerShell, use a script block ({ ... }), which also obviates the need for escaping (and better integrates with the calling session by returning objects from the invocation, not just strings).
# From Powershell.
PS> powershell.exe -command { $ErrorView = "CategoryView" ; dir wrong.txt }

chef powershell command doesn't work

I'm trying to get ACLs and parse into the array reg_perms, the code works fine without the Where-Object{($_.IdentityReference -eq "BUILTIN\Users")
command ='powershell "(Get-Acl \'HKLM:\SOFTWARE\\Microsoft\Windows NT\CurrentVersion\Winlogon\').Access | Where-Object{($_.IdentityReference -eq "BUILTIN\Users")} | Format-List RegistryRights,AccessControlType,IdentityReference"'
data = ::Mixlib::ShellOut.new(command).run_command.stdout.strip.gsub(/\r\n?/, "\n")
reg_perms = data.split("\n\n").each_with_object([]) do |set, arr|
arr << set.split("\n").map do |f|
f.split(':').collect(&:strip)
end.to_h
end
You are using single quotes for your entire string: '. Then when your string is evaled with double quotes the double quotes around the BUILTIN\Users string are not escaped, this mean you need to escape the double quotes around the ""BUILTIN\Users"" the powershell way or use single quotes \'BUILTIN\Users\' and escape them the ruby way.
This should work:
command ='powershell "(Get-Acl \'HKLM:\SOFTWARE\\Microsoft\Windows NT\CurrentVersion\Winlogon\').Access | Where-Object{
($_.IdentityReference -eq \'BUILTIN\Users\')
} | Format-List RegistryRights,AccessControlType,IdentityReference"'
You're trying to embed "BUILTIN\Users" - a double-quoted string - within the overall double-quoted command string you're passing to the PowerShell executable (powershell "..."), which cannot work, because embedding the same type of quotes in a quoted string requires escaping.
PowerShell, when it is called from outside via its CLI (powershell.exe), requires that embedded " chars. be \"-escaped (even though PowerShell-internally, `" or "" are used).[1]
Since you're using single-quoting on the Ruby (Chef) side (command = '...'), escaping the inner embedded " chars. as \" for the sake of PowerShell is sufficient.
Therefore, replace -eq "BUILTIN\Users" with -eq \"BUILTIN\Users\"; i.e.:
command ='powershell "(Get-Acl \'HKLM:\SOFTWARE\\Microsoft\Windows NT\CurrentVersion\Winlogon\').Access | Where-Object{($_.IdentityReference -eq \"BUILTIN\Users\")} | Format-List RegistryRights,AccessControlType,IdentityReference"'
Alternatively - given that the content of your quoted string is a literal, you can use single quotes around BUILTIN\Users in the PowerShell command; in that case, however, because on the Ruby side you're using single quotes for the overall command, you need to escape the embedded ' instances as \' for Ruby's benefit:
Therefore, replace -eq "BUILTIN\Users" with -eq \'BUILTIN\Users\'; i.e.:
command ='powershell "(Get-Acl \'HKLM:\SOFTWARE\\Microsoft\Windows NT\CurrentVersion\Winlogon\').Access | Where-Object{($_.IdentityReference -eq \'BUILTIN\Users\')} | Format-List RegistryRights,AccessControlType,IdentityReference"'
[1] When calling the PowerShell CLI from cmd.exe - be it from the command prompt, a batch file, or via Chef/Ruby - escaping a literal " as "" sometimes , but not always works (try
powershell -Command "'Nat ""King"" Cole'" directly from a cmd.exe command prompt).
Instead, \"-escaping is the safe choice.
`"-escaping, which is the typical PowerShell-internal way to escape " inside "...", never works in this scenario.

Resources