术语“else”不被识别为cmdlet的名称

11

我们遇到了PowerShell中If / Else结构的问题。我们的脚本在旧版Windows(直到Windows Server 2012 R2)上运行良好,但在新版上无法正常工作。

为了简化事情,让我们从PowerShell帮助文件(Get-Help about_If)中举一个例子:

if ($a -gt 2)
{
    Write-Host "The value $a is greater than 2."
}
else
{
    Write-Host "The value $a is less than or equal to 2, is not created or is not initialized."
}

在基于$PSVersionTable.PSVersion为5.1.14409.1018的Windows Server 2012 R2上,结果如预期:
The value  is less than or equal to 2, is not created or is not initialized.

然而,像PowerShell 5.1.14393.2879(Windows Server 2016)或5.1.17763.503(Windows Server 2019)这样的较新版本似乎不理解相同的语法:
else : The term 'else' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

请注意,即使是这些较新的PowerShell版本,它们的If / Then示例也完全相同,因此官方上不应该有任何变化。

是的,我知道我可以很容易地将条件重新编写为:

if ($a -gt 2) {
    Write-Host "The value $a is greater than 2."
} else {
    Write-Host "The value $a is less than or equal to 2, is not created or is not initialized."
}

但是我们有很多脚本,如果有一种方式让PowerShell也能理解其他格式,我真的希望避免重复修复和测试所有脚本。这种行为在PowerShell语言规范中是否已经官方记录或者应该被视为错误?

我们目前在基于Web的文档中提供的示例使用另一种格式,但是在更新版本中同样无法工作(出现相同的错误):

if ($a -gt 2) {
    Write-Host "The value $a is greater than 2."
}
else {
    Write-Host ("The value $a is less than or equal to 2," + " is not created or is not initialized.")
}

我找到了一个页面讨论类似的问题,但它并不完全符合我们的情况。

非常烦人。感谢您提前的帮助。

更新1:如果我将脚本保存为 .ps1 文件并执行该文件,则似乎可以解决问题。我的问题只出现在从编辑器中复制/粘贴代码块(在我的情况下是记事本)。

更新2: $PSVersionTable 结果:

Name                           Value
----                           -----
PSVersion                      5.1.17763.503
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.503
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

将记事本中的条件复制粘贴到PowerShell控制台中,我在新版中遇到了这个错误(在Windows Server 2012 R2中没有出现错误):

if ($a -gt 2)
>> {
>>     Write-Host "The value $a is greater than 2."
>> }
PS C:\Scripts> else
else : The term 'else' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ else
+ ~~~~
    + CategoryInfo          : ObjectNotFound: (else:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

更新三:和往常一样,细节决定成败。由于在 WS2012R2(及更早版本)中,标准的粘贴键组合 Ctrl+V 不起作用,会出现 ^V 的情况,因此我使用了右键将内容粘贴到控制台中。所以我习惯于通过点击鼠标右键(并在 WS2012R2 上从上下文菜单中选择“粘贴”)将脚本粘贴到控制台中。显然,粘贴功能已经被实现了不同的方式,在右键单击时逐行解释内容,在使用 Ctrl+V 粘贴时则被解释为整个代码块。很好,又学到了新知识。感谢大家的支持和建议!


3
你的问题可能有所遗漏。使用任何版本的PowerShell都无法重现。括号的位置并不重要。听起来好像有人完全省略了括号,这是非法语法。 - Maximilian Burszley
2
如果你在提示符下运行它,它将无法工作,但它应该在脚本中工作。 - js2010
1
@MathiasR.Jessen:当作为文件运行脚本时,它可以工作。只有当我打开文件并复制/粘贴包含条件的脚本块时才会出现问题。 - pholpar
1
@pholpar 我明白了,感谢澄清。非常好奇,我已经尝试在Windows 2016和Windows 10 (1703和1803)上重现这个问题,除非我手动逐行或逐块复制粘贴,否则我完全无法重现你描述的行为。 - Mathias R. Jessen
2
@MathiasR.Jessen:实际上,如果PowerShell逐行处理粘贴的内容,那么这种行为是完全可以理解的。可能是操作系统之间剪贴板处理行为的变化吗?我的意思是,WS2012R2“知道”在If语句的闭合}之后仍有一些额外的内容要处理,而新的操作系统不再知道了吗?奇怪。 - pholpar
显示剩余9条评论
5个回答

2

Powershell似乎将else块视为单独的语句,而不是附加到if语句中。 修改了我的代码,使用相同行中的if和else的结尾。

if (condition) {
 } else {
   #else code
}

2
这在命令提示符下的任何版本中都是正确的,但在脚本中运行时应该可以正常工作。我已经在Server 2016上使用脚本进行了确认,即使在else之前有一个空行,并且在unicode、utf8或ansi格式下也可以正常工作。
在命令提示符下,通过点击右键粘贴进行演示。使用control v来粘贴是有效的。
好的,如果我在ISE中使用control v进行粘贴,它实际上可以正常工作,没有错误。
PS C:\Users\js> if (0) { 'ran if' }

PS C:\Users\js> else { 'ran else' }

else : The term 'else' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify
that the path is correct and try again.
At line:1 char:1
+ else { 'else' }
+ ~~~~
    + CategoryInfo          : ObjectNotFound: (else:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

你能详细说明一下conhost/prompt的设置吗?即使没有PSReadLine,我也无法重现这种行为。 - Mathias R. Jessen
@js2010,你确定你正确地粘贴了代码吗?看起来你先粘贴了 if 语句后按了回车,然后才粘贴了 else 部分 -> PS C:\users\me> else - Moerwald
@Moerwald 我一次性粘贴了整个东西。 - js2010
@js2010:你最终能否在Windows Server 2012 R2(或更高版本)上测试它,通过复制粘贴整个代码块来确认它在那种情况下是否有效?谢谢! - pholpar
@js2010,你能检查一下为什么多行命令前缀从>>变成了PS C:\users\me>吗?也许有额外的CRLF。 - Moerwald
显示剩余8条评论

2

由于评论区空间不足,我将我的测试结果作为答案发布(希望社区允许)。

在 Windows Server 2019(版本1809 OS Build 17763.107)的 PowerShell 控制台中进行了测试。

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.17763.1
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.1
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

在PowerShell提示符下运行示例:
> if ($a -gt 2)
>> {
>>     Write-Host "The value $a is greater than 2."
>> }
>> else
>> {
>>     Write-Host "The value $a is less than or equal to 2, is not created or is not initialized."
>> }
The value  is less than or equal to 2, is not created or is not initialized.

代码正在运行。

更新1

还在Windows Server 2016 (版本1607,OS Build 14393.2969)中进行了测试:

PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.14393.2969
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14393.2969
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

在PowerShell提示符上运行示例:
PS C:\> if ($a -gt 2)
>> {
>>     Write-Host "The value $a is greater than 2."
>> }
>> else
>> {
>>     Write-Host "The value $a is less than or equal to 2, is not created or is not initialized."
>> }
The value  is less than or equal to 2, is not created or is not initialized.

更新2

问题出在你将代码粘贴到PowerShell控制台的方式上。如果你使用Ctr+V(这是较新版本的标准PowerShell控制台宿主程序中添加的),那么代码将会作为整个块进行粘贴:

PS C:\> if ($a -gt 2)
>> {
>>     Write-Host "The value $a is greater than 2."
>> }
>> else
>> {
>>     Write-Host "The value $a is less than or equal to 2, is not created or is not initialized."
>> }

但是,如果你通过右键 - 编辑 - 粘贴将代码粘贴到PowerShell控制台中,似乎if块和else块会被粘贴到操作中,并且在if块后面似乎会插入一个CRLF。因此,if语句得到计算并且*之后*else块被粘贴到控制台中,这当然会触发错误:

PS C:\> if ($a -gt 2)
>> {
>>     Write-Host "The value $a is greater than 2."
>> }
PS C:\> else
else : The term 'else' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ else
+ ~~~~
    + CategoryInfo          : ObjectNotFound: (else:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS C:\> {
>>     Write-Host "The value $a is less than or equal to 2, is not created or is not initialized."
>> }

这个问题也可以从新提示符PS C:\>elseelse的范围内看到。

此问题与“标准”PowerShell控制台主机有关(与PowerShell引擎无关)。如果您在PowerShell ISE中执行复制操作(通过鼠标或快捷键),则不会出现此问题。

希望能对您有所帮助。


请查看 更新2 ,了解我的确切版本和结果。 - pholpar
1
从 OP 处复制了整个 if else 代码块。切换到 RDP 会话,聚焦 Powershell 控制台,按下 Ctrl+V,然后按下 Enter 键。没有使用 Shift + Enter 或记事本。 - Moerwald
明天我会尝试使用记事本变体。 - Moerwald
请使用右键对其进行测试,如果它确实是罪魁祸首,请将结果附加为答案,以便我可以接受。非常感谢! - pholpar
1
@pholpar 使用鼠标粘贴会触发问题。这也是我在你的回答中评论“@js2010,你确定你正确地粘贴了代码吗?它似乎你先粘贴了if语句并按下了回车键,然后再粘贴else部分-> PS C:\users\me> else”。在else语句处出现了新提示符。 - Moerwald
显示剩余2条评论

0

我有同样的问题。

有趣的是,如果你打开 posh 并运行以下命令以不加载你的配置文件:

start-process powershell.exe -Args -noprofile

然后将其粘贴到您的if -> then中,在新窗口中以旧方式格式化,那么它就可以正常工作了...

PS C:\WINDOWS\system32> $this = "blah"
>> $that = "blah2"
>>
>> if ($this) {
>>     $that
>> }
>> else {
>>     $that
>> }
blah2

PS C:\WINDOWS\system32> $psversiontable

Name                           Value
----                           -----
PSVersion                      5.1.19041.1682
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.1682
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

-1

我发现 Ctrl+V 可以使用,而在地址栏上右键单击 > 编辑 > 粘贴则不行


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接