6

我有一个编辑注册表的 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”未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确并重试。

因此,它试图将字符串视为逗号,就好像我刚刚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"""

仍然不确定这是错误还是设计使然,但至少我们有一个解决方法,因为这解决了我上面描述的两个问题。

4

1 回答 1

3

如果我将您的脚本更改为

-Command $ScriptBlock

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

gci function:test | fl 

要在新窗口中查看函数定义,显示的代码是

$status = This is a string

对它显示的单引号版本进行相同的测试

$status = 'This is a string'

所以它失去了双引号。用双引号转义它们

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

他们顺利通过。此外,即使脚本块是编译代码,在我看来,如果将它们展开为字符串,它们就像是嵌入为文本:

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

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

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

于 2014-03-20T22:30:43.190 回答