在一个脚本块中使用Start-Process执行一个函数会用双引号做一些奇怪的事情



我有一个编辑注册表的PowerShell脚本,所以它需要以管理员身份运行。为此,我从正在运行的PowerShell脚本启动了一个新的PowerShell进程,并使用带有函数的脚本块传递部分注册表键路径。当我在该函数中使用双引号时,PowerShell试图将它们解释为命令,而不是字符串。如果我使用单引号,那么一切都很好。

我创建了一个简单的示例powershell脚本,它再现了这个问题。下面是代码片段:

$ScriptBlock = {
    function Test
    {
        $status = "This is a string"
        Write-Output $status
    }
}
Start-Process -FilePath PowerShell -ArgumentList "-NoExit -NoProfile -ExecutionPolicy Bypass -Command & {$ScriptBlock Test}"
因此,在新的PowerShell进程中,它将首先在脚本块中定义代码,然后调用Test方法,并产生以下错误:

This:术语'This'不被识别为cmlet的名称,函数、脚本文件或可操作程序。检查单词的拼写名称,或者如果包含路径,则验证路径是否正确再试一次。

所以它试图将字符串视为命令,就好像我刚刚在脚本的新行中单独键入了This is a string

如果我改变

$status = "This is a string"

$status = 'This is a string'

脚本按预期工作,只是输出字符串This is a string

我注意到的另一个奇怪的问题是,如果我不使用变量,只使用:
Write-Output "This is a string"

则将每个单词输出到单独的一行,如下所示:

字符串

但是如果我使用像这样的单引号:

Write-Output 'This is a string'

则按预期在一行上输出整个句子。

有人知道为什么PowerShell在这些情况下行为奇怪吗?

因此,正如TessellatingHeckler提到的,解决方案是将任何双引号括在双引号,单引号中,或者您可以使用括号。

所以在我的例子中,你可以改成:

$status = "This is a string"

:

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

或:

$status = '"This is a string"'

或:

$status = {"This is a string"}

如果你想计算字符串中的变量(即查看变量的值),那么你必须使用双双引号方法:

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

仍然不确定这是一个Bug还是故意的,但至少我们有一个解决方案,因为这修复了我上面描述的两个问题。

如果我把你的脚本改成

-Command $ScriptBlock

运行它,让它打开一个新的shell窗口,然后运行

gci function:test | fl 

在新窗口中查看函数定义,所示代码为

$status = This is a string

用相同的测试在单引号版本上显示

$status = 'This is a string'

失去了双引号。用双引号转义

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

,他们顺利通过。此外,尽管scriptblock是编译过的代码,但在我看来,如果将它们展开为字符串,它们就像嵌入文本一样:

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

所以我认为你遇到了这种引用问题:PowerShell从命令行参数中去掉双引号,特别是Droj的答案,说"向外部程序发送参数的奇怪之处在于有额外的引用评估级别。"我不知道这是不是一个bug,但我猜它不会被改变,因为当你使用Start-Process并传入参数时,行为是一样的。

PowerShell将脚本块作为字符串扩展到您的命令中,然后字符串周围的单引号被重新解释为引用参数,并在调用的某个地方删除。这是一个已知的问题,或者是一个错误,或者是一个设计,这取决于你如何阅读链接连接的文章。

相关内容

  • 没有找到相关文章

最新更新