Note: This answer was substantially rewritten after new information came to light.
To complement jazzdelightsme's effective solution with some general guidance and background information:
- When calling a batch file from outside - cmd.exe, such as from PowerShell, invoke it as- cmd /c 'file.cmd ... & exit'or - if string interpolation is needed - as
 - cmd /c "file.cmd ... & exit", which then requires escaping embedded- "as- `"[1]. This ensures that it behaves as it would when called from inside- cmd.exewith respect to its exit code (error level), i.e. ensures that the batch file's exit code reliably becomes- cmd.exe's process exit code.
 - 
- This post explains the problem and this - obscure - workaround in detail.
- Note: The simpler workaround based on call-cmd /c call file.cmd ...- works in principle, but has an unwanted side effect when (of necessity double-quoted[2]) arguments with^characters are passed: Due to use ofcall,^characters ("carets", strictly speaking circumflex accents,U+005E) are invariably doubled, so that say, argument"a ^ 2", is seen by the batch file as"a ^^ 2"; it is unclear what the purpose of this behavior is, but it has seemingly always existed - see this answer for details oncmd.exe's parser.
 
- Without the - & exitworkaround, you'll only get the desired behavior if you ensure that all code paths exit in one of the following ways - and missing a code path is an easy mistake to make:
 - 
- exitwith no arguments, which correctly relays the most recently executed command's exit code.
 - 
- Caveat: exitwithout/binstantly exits thecmd.exeinstance as a whole, so it isn't suitable for use inside batch files that may be run interactively or must be callable from other batch files and return control to those batch files.
 
- exit /b <code>or- exit <code>, where- <code>represents the desired exit code, i.e. specifying an explicit exit code, as in jazzdelightsme's solution.
 - 
- Caveat: Exiting a batch file with exit /bwithout an explicit<code>argument does not pass the most recently executed command's exit code through without thecmd /c <batch-file> ... `& exitworkaround - see this answer.
 
 
Additional background information, in the context of your code:
Bizarrely, with an outside invocation of a batch file without & exit (or call), statements such as if, goto, echo, and endlocal, and even REM (but, curiously, not ::) reset the exit code that cmd.exe later reports to 0 - even though inside that cmd.exe session %ERRORLEVEL% is set as it usually is, meaning that such statements have no impact on the current %ERRORLEVEL% value.
Therefore:
- When your batch file is run from inside - cmd.exe, the specific statements that follow the command that sets- %ERRORLEVEL%to- 1(- cmd /c dir aaa), i.e. the- if,- goto,- echoand- endlocalstatements, preserve this value, and- %ERRORLEVEL%ends up with value- 1after exiting the batch file.
 - 
- Bizarrely, the error level is set only after the statement involving the batch file call, so that something like file.cmd || exitdoes not work, because the||operator doesn't recognize thefile.cmdcall as having failed. This is the reason that the workaround uses&rather than||.
 
- When your batch file is run from outside - cmd.exe, and isn't invoked with- cmd /c "<batch-file> ... & exit"(or- cmd /c call <batch-file> ...), the same statements that follow the- %ERRORLEVEL%-setting command suddenly reset the exit code that- cmd.exeitself later reports to- 0, instead of preserving the post-batch-file-execution- %ERRORLEVEL%value.
 
[1] Situationally, you can get away with cmd /c <batch-file> ... `& exit, i.e. without enclosing the arguments to /c in a single, overall string, but that breaks if the batch-file path needs double-quoting and at least one double-quoted pass-through argument is also present.
[2] ^ chars. in unquoted arguments, as usual, are interpreted as cmd.exe's escape character and therefore removed.