11

We have an issue with the If / Else structure in PowerShell. Our scripts that work on former Windows versions (up to Windows Server 2012 R2), do not work on the newer versions.

To simplify things, let's take an example from the PowerShell help (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."
}

On Windows Server 2012 R2 (PowerShell version based on $PSVersionTable.PSVersion is 5.1.14409.1018) the result is, as expected:

The value  is less than or equal to 2, is not created or is not initialized.

However, newer PowerShell Versions, like 5.1.14393.2879 (Windows Server 2016) or 5.1.17763.503 (Windows Server 2019) seem not to understand the same syntax:

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.

Note, that event these newer PowerShell versions have the very same example for If / Then, so officially nothing should have been changed.

Yes, I know I could easily re-write the condition as:

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."
}

But we have a lot of scripts, and I really would like to avoid to revisit, and fix and test all of them, if there is a way to have PowerShell to understand the other format either. Is this behavior documented officially in the PowerShell language specification, or should we consider it to be a bug?

The example we currently have in the web-based documentation, has another format, but it does not work either (same error) with the newer versions:

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.")
}

I've found a page discussing a similar issue, but it does not match exactly our case.

Very annoying. Thanks for your help in advance.

Update 1: If I save the script into a .ps1 file, and execute the file, then it seems to work. I have only the problem, if I copy / paste the code block from the editor (Notepad in my case).

Update 2: $PSVersionTable results:

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

By copy-pasting the condition from Notepad into the PowerShell console I have this error in the newer versions (I had no error with 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

Update 3: As always, the devil is in the details. I've pasted the content into the console by using the right mouse button, since in WS2012R2 (and older) the standard key combination for pasting Ctrl+V did not work, and resulted in a ^V. So I got used to pasting the script into the console by clicking the right mouse button (and on WS2012R2 selecting Paste from the context menu). Apparently, the paste funtionality has been implemented differently, and the content is interpeted line-by-line for the right-click, but interpreted as a block when pasted using Ctrl+V. Nice. Have learned something new again. Thank you all for your support, and for the ideas!

pholpar
  • 1,725
  • 2
  • 14
  • 23
  • 3
    Something has to be missing from your question. Unable to repro with any version of powershell. The position of the brackets *does not matter*. It sounds like someone *omitted* the brackets entirely which is illegal syntax. – Maximilian Burszley Aug 13 '19 at 13:36
  • What PowerShell host are you using? PowerShell ISE, PowerShell, VSCode, ... – Moerwald Aug 13 '19 at 13:39
  • If you open a new editor, re-write the `if/else` statement manually (no copy-pasting) and then save that with ASCII or UTF-8 encoding and execute it - does the issue still occur? – Mathias R. Jessen Aug 13 '19 at 13:40
  • @TheIncorrigible1: Yes, agree brackets _should not_ matter. But they _do_ in my case. It might be a setting in PowerShell I don't know. – pholpar Aug 13 '19 at 13:40
  • 2
    If you run that at the prompt it won't work, but it should work in a script. – js2010 Aug 13 '19 at 13:41
  • @js2010 It will work if you use shift+enter for a line-continuation – Maximilian Burszley Aug 13 '19 at 13:41
  • @Moerwald: It is PowerShell, not the IDE nor VSCode – pholpar Aug 13 '19 at 13:42
  • @pholpar So you're typing it in the console? Of course it won't work! The statement ends with the if unless you use shift+enter to do a line continuation. It will not affect scripts. – Maximilian Burszley Aug 13 '19 at 13:43
  • @js2010: "If you run that at the prompt it won't work, but it should work in a script" Thanks, I found it just now, and actually it solves my problem. – pholpar Aug 13 '19 at 13:51
  • @TheIncorrigible1: "So you're typing it in the console?" No, I don't, I use copy and paste. It was working with the fomer PowerShell version (that seems to interpret the pasted code as a single block), but does not with the new ones. – pholpar Aug 13 '19 at 13:51
  • 1
    @MathiasR.Jessen: When running the script as file, then it works. I have the problem only if I open the file, and copy / paste the script block containg the condition. – pholpar Aug 13 '19 at 13:55
  • 1
    @pholpar I see, thanks for the clarification. Super curious, I've tried to repro this on Windows 2016 and Windows 10 (1703 and 1803), and I'm completely unable to reproduce the behavior you describe unless I manually copy-paste every single line or block 1-by-1. – Mathias R. Jessen Aug 13 '19 at 13:57
  • 2
    @MathiasR.Jessen: actually, if PowerShell processes the pasted content line-by-line, then this behavior is completly understandable. Might it be a change in the behavior of the clipboard-handling between the operating Systems? I mean, WS2012R2 "knew" that there is yet some addional content to process after the closing } of the If statement, and the newer op. systems do not know any more? Strange. – pholpar Aug 13 '19 at 14:19
  • This is a good question, even if it wasn't clearly stated in the beginning. – js2010 Aug 13 '19 at 14:21

5 Answers5

2

This is true in any version when run at the command prompt, but when run in a script it should work fine. I've confirmed this in Server 2016, with a script, even with a blank line before else, and in unicode, utf8, or ansi format.

Demo at the command prompt, pasting by clicking right mouse button. Using control v to paste works.

Ok, if I paste with control v in the ISE, it actually works without error.

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
js2010
  • 23,033
  • 6
  • 64
  • 66
  • Can you detail the conhost/prompt settings? I'm unable to repro this behavior even without `PSReadLine` – Mathias R. Jessen Aug 13 '19 at 13:54
  • It definitely works on Windows Server 2012 (PowerShell version 5.1.14409.1018) PowerShell command prompt if I paste the code from Notepad. It does not however in the newer version. Shoud be either an issue with my settings in the different environments, or something has been changed in the PS-host implementation itself. – pholpar Aug 13 '19 at 14:00
  • @MathiasR.Jessen It seems self-evident to me in Windows 10. I edited in a demo. – js2010 Aug 13 '19 at 14:03
  • This is exactly what I had found. In script form, { can be on a different line, but when running it manually, it needs to be on the same line so PowerShell knows to expect more code. https://stackoverflow.com/questions/56366747/powershell-multiple-catch-issue – UnhandledExcepSean Aug 13 '19 at 14:05
  • @js2010, are you sure you pasted the code correctly? It seems you pasted the `if` statement pressed enter, and afterwards you pasted the `else`part -> `PS C:\users\me> else` – Moerwald Aug 13 '19 at 14:06
  • @Moerwald I pasted the whole thing in one shot. – js2010 Aug 13 '19 at 14:10
  • @js2010: Can you eventually test it on Windows Server 2012 R2 (or later?) to confirm that it works in that case by copy pasting the whole code block? Thanks! – pholpar Aug 13 '19 at 14:12
  • @js2010, can you check why the multiline command prefix change from `>>` to `PS C:\users\me>`? Maybe there is an additional CRLF. – Moerwald Aug 13 '19 at 14:15
  • @Moerwald That's just the end of the statement. I don't know why this is so complicated. – js2010 Aug 13 '19 at 14:16
  • Server 2016 behaves the same way @pholpar – js2010 Aug 13 '19 at 14:17
  • @js2010: Sorry, I meant, could you eventually test it on Windows Server 2012 R2 (or **former**)? – pholpar Aug 13 '19 at 14:31
  • @pholpar It's fine on 2012 in a script, but I have PS 5 there. – js2010 Aug 13 '19 at 14:41
  • @js2010 When running as part of a .ps1 script, I have no problem with any of the operating systems. But when pasting the code from Notepad, it works only on WS2012R2, but not on WS2016 or WS2019. – pholpar Aug 13 '19 at 14:52
2

I'm posting my test outcome as an answer since there is not enough space in the comment section (hope it's ok for the community).

Tested in PowerShell console on Windows Server 2019 (Version 1809 OS Build 17763.107).

> $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

Ran example on PowerShell prompt:

> 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.

Code is working.

UPDATE 1

Also tested in Windows Server 2016 (Version 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

Ran example on PowerShell prompt:

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.

UPDATE 2

The problem is situated in how you paste the code to your PowerShell console. If you use Ctr+V (which was added in newer versions of the standard PowerShell console host) the code is pasted as the whole block:

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."
>> }

But if you're pasting the code via right click - edit - paste to the PowerShell console it seems that the, if block and else block, are pasted in the operations, and it seems that there is a CRLF "injected" after the if block. So the if gets computed and * afterward* the else block is pasted to the console, which of course triggers the error:

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."
>> }

The problem can also be seen since there is a new prompt PS C:\> at the else and also at the scope of the else.

This problem is related to the "standard" PowerShell console host (is not PowerShell engine related). If you perform the copy operations (via mouse or shortcut) in the PowerShell ISE the problem doesn't occur.

Hope that helps.

Moerwald
  • 10,448
  • 9
  • 43
  • 83
  • See **Update 2** regarding my exact version and the results – pholpar Aug 13 '19 at 14:08
  • Have you entered the code via copy / paste into the console or have you pressed Shift + Enter after the closing } of the If branch to indicate line continuation. If you used Shift + Enter, could you try to copy / paste the whole block from Notepad? Then - I assume - it won't work with WS2016 and WS2019. This method works however with WS2012R2. – pholpar Aug 13 '19 at 14:40
  • 1
    Took whole `if else ` block from OP. Switched to RDP session, focused Powershell console, pressed `Ctrl+V`, afterwards pressed `enter`. No `Shift + Enter` or Notepad involved. – Moerwald Aug 13 '19 at 14:59
  • I'll try the Notepad variant tomorrow. – Moerwald Aug 13 '19 at 15:00
  • Oh, my goodness! `Ctrl+V` is the key, literally! As always, the devil is in the details. I didn't even know, that you can paste content into the PS console using this key combination. In WS2012R2 (and older) it did not work, and results in a `^V`. I got used to pasting the script into the console by clicking the right mouse button (and on WS2012R2 selecting Paste from the menu). Apparently, it has been implemented differently, and the content is interpeted line-by-line in this case. Pasting the content using `Ctrl+V` make the console to interpret the whole content as a block. – pholpar Aug 13 '19 at 15:34
  • could you please test it using the right mouse button, and if it is really the culprit, please append the result as an answer, that I can accept. Thanks a lot! – pholpar Aug 13 '19 at 15:37
  • 1
    @pholpar using the mouse to paste the triggers the problem. That's was also the reason of my comment in your answer `@js2010, are you sure you pasted the code correctly? It seems you pasted the if statement pressed enter, and afterwards you pasted the elsepart -> PS C:\users\me> else`. There was a new prompt at the `else` statement. – Moerwald Aug 14 '19 at 05:03
2

Powershell seems to consider the else block as separate statement, not attached to if. Modified my code to use the end of the if and else in the same line.

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

I have the same issue

Interesting that if you open posh and run the following to not load your profile:

start-process powershell.exe -Args -noprofile

and then paste in your if -> then, in the new window and formatted the old way, then it works fine...

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

I have found Ctrl+V works & Right Mouse Button Click on the Address Bar > Edit > Paste does not