Powershell: LastExitCode not honored after being manually written to

Created on 26 Jun 2019  路  6Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Compile the following with dotnet build
```c#
using System;

namespace exitcodes
{
class Program
{
static int Main(string[] args)
{
var returnValue = args.Length == 1 ? int.Parse(args[0]) : 0;

        Console.WriteLine($"I shall return {returnValue}");

        return returnValue;
    }
}

}


Write the following script 
```powershell
dotnet run 1
Write-Host "LastExitCode=$LastExitCode"

$LastExitCode=0

dotnet run 1
Write-Host "LastExitCode=$LastExitCode"

Run the script:

.\exitcode.ps1

Expected behavior

I shall return 1
LastExitCode=1
I shall return 1
LastExitCode=1

Actual behavior

I shall return 1
LastExitCode=1
I shall return 1
LastExitCode=0

Environment data

Name                           Value
----                           -----
PSVersion                      6.2.1
PSEdition                      Core
GitCommitId                    6.2.1
OS                             Microsoft Windows 10.0.18362 
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥        
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Issue-Question Resolution-Answered

Most helpful comment

Yeah, in PowerShell I've always referred to it as copy on write. In PowerShell's dynamic scoping approach (as opposed to lexical scoping) it's about the only way to maintain your sanity. :-) For example, I write a script that you use. Where you invoke my scirpt, you have a variable named $mypath. Down in my script, I also have a variable called $mypath. If my modifications to that variable affected your version of $mypath - you'd be pulling your hair trying to figure out how/who changed your variable's value. :-)

All 6 comments

Modify the last line of your script to this:

Write-Host "LastExitCode=$LastExitCode, `$global:LastExitCode=$global:LastExitCode"

When you assigned 0 to $LastExitCode a few lines above this one, you made a local copy of $LastExitCode. You are not changing the value of the globally scoped $LastExitCode. After that, when you access $LastExitCode with no scope modifier, PowerShell looks in the local scope first, then in the next scope up until it reaches the global scope.

You can avoid this issue by always using the global scope modifier e.g. $global:LastExitCode to access this variable.

Thanks! Is there a powershell strictness level that disallows implicit sneaky super scope overriding without an explicit override keyword?

In general, modifying a variable that originates in a different scope will result in it being copied (kinda like F#'s "masking" behaviour with variables) to the local scope if you're not specifying the scope to modify it at, IIRC.

Thanks for the info. Wish there was a way to turn off automatic variable copying, but at least I understand what's going on now :)

Yeah, in PowerShell I've always referred to it as copy on write. In PowerShell's dynamic scoping approach (as opposed to lexical scoping) it's about the only way to maintain your sanity. :-) For example, I write a script that you use. Where you invoke my scirpt, you have a variable named $mypath. Down in my script, I also have a variable called $mypath. If my modifications to that variable affected your version of $mypath - you'd be pulling your hair trying to figure out how/who changed your variable's value. :-)

Yea, dynamic scoping is not my kind of strudel :)

Was this page helpful?
0 / 5 - 0 ratings