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