Actually it is much more difficult than you think. Highlighting nested quotes in strings passed from cmd to PowerShell is a major headache. What makes this especially difficult is that you need to make a replacement for the variable extended by cmd in the quoted argument passed to powershell.exe in the single-track argument passed to the PowerShell script parameter. AFAIK cmd does not have any built-in functions for even basic string replacements, so you need PowerShell to replace for you.
If the argument to the -data strong> parameter (the one contained in the cmd x variable) does not have to be single, the simplest thing for do is the double quote, so the single quote in the x value does not need to be run at all. I say "simple", but even that is a little complicated. As Vasily Sirakis pointed out, ^ usually an escape character in cmd, but in order to avoid double quotes in a string (double-), you should use \ . So you can write your command command as follows:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name \"%x%\" -data '%y%'"
This passes the following PowerShell command:
G:\test.ps1 -name "value of x, which may contain 's" -data 'value of y'
If, however, x can also contain characters that are special characters in PowerShell interpolated strings ( " , $ ` ), then it gets LOT harder. The problem is that % x is a cmd variable that extends to cmd before how PowerShell has the ability to touch it.If you specify one quote in the command that you pass powershell.exe and it contains one quote, then you give the PowerShell session a string that ends earlier, so PowerShell is not able to perform any operations on Itโs obvious that this doesnโt work This is because, before replacing anything, the -replace operator must provide the correct line:
'foo'bar' -replace "'", "''"
On the other hand, if you specify it twice, then PowerShell interpolates the string before it performs any replacements on it, so if it contains any special characters, they are interpreted before they can be escaped by the replacement. I searched high and low for other ways to quote inline string strings (something equivalent to perl q // in which nothing needs to be escaped, but a separator of your choice), but doesn't seem to be anything.
So, the only remaining solution is to use a string here, which requires a multi-line argument. This is difficult in a batch file, but it can be done:
setlocal EnableDelayedExpansion set LF=^ set pscommand=G:\test.ps1 -name @'!LF!!x!!LF!'@ -data '!y!' C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass "!pscommand!"
It is assumed that x and y were installed earlier in the batch file. If your application can only send the single-line command to the cmd command, you need to add this to the batch file by adding the following two lines at the beginning:
set x=%~1 set y=%~2
Then call the batch file as follows:
path\test.bat "%x%" "%y%"
~ removes quotation marks associated with command line arguments. You need quotes to include spaces in variables, but quotes are also added to the value of the variable. The package is so dumb.
Two blank lines are required following set LF=^ .
This applies to single quotes, which also interpret all other characters in the x value literally, with one exception: double quotes. Unfortunately, if double quotes can be part of the value, as indicated in the comment, I donโt think the problem can be overcome without using a third-party utility. The reason is that, as mentioned above, the package does not have its own way of doing line replacements, and the value of x extends to cmd before PowerShell ever sees it.
WHO WHO ... GOOD QUESTION !!
UPDATE:
In fact, it turns out that you can perform static string replacements in cmd. Duncan added an answer that shows how to do this. This is a bit confusing, so I will go into detail about what happens in the Duncan solution.
The idea is that %var:hot=cold% expands to the value of the var variable, with all occurrences of hot being replaced by cold :
D:\Scratch\soscratch>set var=You're such a hot shot! D:\Scratch\soscratch>echo %var% You're such a hot shot! D:\Scratch\soscratch>echo %var:hot=cold% You're such a cold scold!
So, in the command (modified from Duncan's answer to align with the OP example, for clarity):
powershell G:\test.ps1 -name '%x:'=''%' -data '%y:'=''%'
all occurrences of ' in the variables x and y are replaced by '' , and the command expands to
powershell G:\test.ps1 -name 'a''b' -data 'c''d'
Let break the key element of this, '%x:'=''%' :
- The two
' at the beginning and at the end are explicit external quotes passed to PowerShell to quote the argument, that is, the same single quotes that the OP had around %x :'='' is a string replacement indicating that ' should be replaced with ''%x:'=''% expands to the value of the variable x with the replacement ' by '' , which is equal to a''b- So the whole thing expands to
'a''b'
This solution avoids single quotes in the variable value is much simpler than my workaround above. However, the OP indicated in the update that the variable might also contain double quotes, and so far this solution still does not pass double quotes to x in PowerShell - those that are still removed with cmd before PowerShell receives the command.
The good news is that with the cmd string replacement method this becomes irresistible. Run the following cmd commands after the initial x value has already been set:
Replace ' with '' to avoid single quotes for PowerShell:
set x=%x:'=''%
Replace " with \" to avoid double quotes for cmd:
set x=%x:"=\"%
The order of these two assignments does not matter.
Now, the PowerShell script can be called using the syntax that OP used in the first place (the path to powershell.exe was deleted so that it matches all on the same line):
powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x' -data '%y'"
Again, if the application can send only a single-line command in cmd, these three commands can be placed in a batch file, and the application can call the batch file and pass the variables as shown above (the first bullet in my original answer).
It is interesting to note that if replacing " by \" is performed in string mode, and not using a separate set command, you will not escape " in string, even if they are inside a string with two quotes, for example:
powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x:"=\"' -data '%y'"
... not :
powershell.exe -ExecutionPolicy Bypass "G:\test.ps1 -name '%x:\"=\\"' -data '%y'"