简体   繁体   English

PowerShell使用Start-Process在脚本块中执行函数会使用双引号进行奇怪的操作

[英]PowerShell Executing a function within a Script Block using Start-Process does weird things with double quotes

I have a PowerShell script that edits the registry, so it needs to run as admin. 我有一个编辑注册表的PowerShell脚本,所以它需要以管理员身份运行。 To do this, I start up a new PowerShell process from my running PowerShell script, and pass in part of the registry key path using a Script Block with a function in it. 为此,我从运行的PowerShell脚本启动一个新的PowerShell进程,并使用带有函数的脚本块传递部分注册表键路径。 When I use double quotes within that function, PowerShell tries to interpret them as commands, rather than a string. 当我在该函数中使用双引号时,PowerShell会尝试将它们解释为命令,而不是字符串。 If I use single quotes though, then everything works fine. 如果我使用单引号,那么一切正常。

I've created a little stripped down sample powershell script that reproduces the problem. 我创建了一个简单的样本PowerShell脚本来重现问题。 Here's the 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 define the code in the script block and then call the Test method, and it produces this error: 因此,在新的PowerShell流程中,它将首先在脚本块中定义代码,然后调用Test方法,并产生以下错误:

This : The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. 这:术语“This”不被识别为cmdlet,函数,脚本文件或可操作程序的名称。 Check the spelling of the name, or if a path was included, verify that the path is correct and try again. 检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。

So it's trying to treat the string as a commad, as if I had just typed This is a string by itself on a new line in my script. 所以它试图将字符串视为一个commad,就好像我刚刚输入一样。 This is a string ,它本身就是我脚本中的一个新行。

If I change the line 如果我换行

$status = "This is a string"

to

$status = 'This is a string'

the script works as expected and simply outputs the string This is a string . 该脚本按预期工作,只输出字符串This is a string

Another strange problem I've noticed is that if I don't use a variable and just use: 我注意到的另一个奇怪的问题是,如果我不使用变量,只需使用:

Write-Output "This is a string"

then it outputs each word on a separate line like this: 然后它在一个单独的行上输出每个单词,如下所示:

This 这个

is

a 一个

string

but if I use single quotes like this: 但如果我使用这样的单引号:

Write-Output 'This is a string'

then it outputs the entire sentence on one line as expected. 然后它按预期在一行输出整个句子。

Does anybody know why PowerShell is behaving strangely in these situations? 有人知道为什么PowerShell在这些情况下会表现得很奇怪吗?

Answer 回答

So as TessellatingHeckler mentions, the solution is do wrap anything that is double quoted in double double quotes, single quotes, or you can use brackets. 正如TessellatingHeckler所提到的,解决方案是用双引号,单引号包装任何双引号,或者你可以使用括号。

So in my example, you would change: 所以在我的例子中,你会改变:

$status = "This is a string"

to this: 对此:

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

or this: 或这个:

$status = '"This is a string"'

or this: 或这个:

$status = {"This is a string"}

If you want to evaluate a variable in your string though (ie see the variable's value), then you have to go with the double double quotes method: 如果你想在你的字符串中评估一个变量(即看到变量的值),那么你必须使用双重双引号方法:

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

Still not sure if this is a Bug or By Design, but at least we have a workaround, as this fixes both of the problems I described above. 仍然不确定这是一个Bug还是设计,但至少我们有一个解决方法,因为这解决了我上面描述的两个问题。

If I change your script to be 如果我改变你的脚本

-Command $ScriptBlock

Run it, and have it open a new shell window, then run 运行它,让它打开一个新的shell窗口,然后运行

gci function:test | fl 

to see the function definition in the new window, the code shown is 要在新窗口中查看函数定义,显示的代码是

$status = This is a string

with the same test on the single quote version it shows 它显示的单引号版本具有相同的测试

$status = 'This is a string'

So it's losing the double quotes. 所以它失去了双引号。 Escape them with double quotes 用双引号来逃避它们

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

and they come through OK. 他们来的确定。 Also even though scriptblocks are compiled code, it looks to me like they are embedded as text if you expand them into a string: 即使scriptblocks是编译代码,如果你将它们扩展为字符串,它看起来像是嵌入为文本:

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

So I think you're hitting this kind of quoting problem: PowerShell stripping double quotes from command line arguments and the answer by Droj particularly, saying "The weird thing about sending parameters to external programs is that there is additional level of quote evaluation. I don't know if this is a bug, but I'm guessing it won't be changed, because the behavior is the same when you use Start-Process and pass in arguments.". 所以我认为你正在遇到这种引用问题: PowerShell从命令行参数中剥离双引号,特别是Droj的回答,说“向外部程序发送参数的奇怪之处在于,还有更多级别的引用评估。我不知道这是不是一个bug,但我猜它不会改变,因为当你使用Start-Process并传入参数时,行为是一样的。“

PowerShell is expanding the script block as a string into your command, then those single quotes around the string are being reinterpreted as quoted parameters and removed somewhere in the invoking. PowerShell正在将脚本块作为字符串扩展到您的命令中,然后将字符串周围的单引号重新解释为带引号的参数,并在调用中的某处删除。 Which is either a known problem, or a bug, or by-design, depending on how you read that linked connect article. 哪个是已知问题,或者是错误,或者是设计,这取决于您如何阅读该链接连接文章。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM