PowerShell Running a function in a Script block using Start-Process does strange things with double quotes

I have a PowerShell script that edits the registry, so it needs to be run as admin. To do this, I start a new PowerShell process from my PowerShell script run and pass part of the registry key path using a script block with a function in it. When I use double quotes inside this function, PowerShell tries to interpret them as commands, not a string. If I use single quotes, then everything works fine.

I created a small truncated powershell script model that reproduces the problem. Here is a snippet:

$ScriptBlock = { function Test { $status = "This is a string" Write-Output $status } } Start-Process -FilePath PowerShell -ArgumentList "-NoExit -NoProfile -ExecutionPolicy Bypass -Command & {$ScriptBlock Test}" 

So, in the new PowerShell process, it will first determine the code in the script block, and then call the Test method and produce this error:

This: the term 'This' is not recognized as a cmdlet name, function, script file, or operating program. Check the spelling of the name, or if the path was included, make sure the path is correct and try again.

Therefore, it tries to treat the string as a combat, as if I just typed This is a string myself on a new line in the script.

If I changed the line

 $status = "This is a string" 

to

 $status = 'This is a string' 

The script works as expected and simply prints the string This is a string .

Another weird problem I noticed is that if I don't use a variable and just use:

 Write-Output "This is a string" 

then it displays each word on a separate line as follows:

it

is an

a

line

but if I use single quotes as follows:

 Write-Output 'This is a string' 

then it displays the whole sentence on one line, as expected.

Does anyone know why PowerShell behaves strangely in these situations?

Answer

So, as TessellatingHeckler mentions, the solution does carry over everything that is double quoted in double double quotes, single quotes, or you can use parentheses.

So, in my example, you would change:

 $status = "This is a string" 

:

 $status = """This is a string""" 

or that:

 $status = '"This is a string"' 

or that:

 $status = {"This is a string"} 

If you want to evaluate the variable in your string, though (for example, see the value of the variable), you need to go with the double double quote method:

 $status = """This is a string that evaluates $someVariable""" 

Not sure if this is a design error, but at least we have a workaround as it fixes both of the problems described above.

+6
source share
1 answer

If I change your script to

 -Command $ScriptBlock 

Run it and open a new shell window, then run

 gci function:test | fl 

to see the definition of the function in a new window, the code is displayed

 $status = This is a string 

with the same test in the single quote version it shows

 $status = 'This is a string' 

So, this plays double quotes. Escape with double quotes

 $status = """This is a string""" 

and they go through OK. In addition, although the script blocks are compiled code, it seems to me that they are embedded in the text if you expand them into a string:

 > $s = { "hello" } > "---$s---" ---"hello"--- 

So, I think you are faced with the following citation problem: PowerShell strips out double quotes from command line arguments and Droj's answer in particular, saying: β€œThe strange thing about sending parameters to external programs is that there is an additional level of quotation evaluation. I don’t know whether this is a mistake, but I assume that it will not be changed, because the behavior will be the same if you use Start- Process and pass arguments. "

PowerShell expands the script block as a string in your command, then these single quotes around the string are reinterpreted as quoted parameters and are deleted somewhere in the call. This is either a known issue, or a mistake, or by design, depending on how you read this related article to put together.

+3
source

All Articles