How to terminate a terminal session in a ps1 script - powershell

How can I terminate a terminal/PowerShell window from a .ps1 script? I would like it to work the way exit in command line works, but when I put that in a PowerShell script it only terminates the script.

Environment.Exit() will terminate the whole process:
# replace 0 with a non-0 error code if you want to indicate some sort of failure
[Environment]::Exit(0)

Related

Equivalent of bash "set -o errexit" for windows cmd.exe batch file?

What's the Windows batch file equivalent of set -o errexit in a bash script?
I have a long batch file filled with different programs to run on Windows command line... basically its an unrolled make file with every compiler command that needs to be run to build an exe in a long sequence of commands.
The problem with this method is that I want it to exit the batch command on the first non-zero return code generate by a command in the script.
As far as I know, Windows batch files have a problem where they don't automatically exit on the first error without adding a lot of repetitive boilerplate code between each command to check for a non-zero return code and to exit the script.
What I'm wondering about, is there an option similar to bash's set -o errexit for Windows cmd.exe? or perhaps a technique that works to eliminate too much boilerplate error checking code... like you set it up once and then it automatically exits if a command returns a non-zero return code without adding a bunch of junk to your script to do this for you.
(I would accept PowerShell option as well instead of cmd.exe, except PowerShell isn't very nice with old-unix-style command flags like: -dontbreak -y ... breaking those commands without adding junk to your command line like quotes or escape characters... not really something I want to mess around with either...)
CMD/Batch
As Ken mentioned in the comments, CMD does not have an equivalent to the bash option -e (or the equivalent -o errexit). You'd have to check the exit status of each command, which is stored in the variable %errorlevel% (equivalent to $? in bash). Something like
if %errorlevel% neq 0 then exit /b %errorlevel%
PowerShell
PowerShell already automatically terminates script execution on errors in most cases. However, there are two error classes in PowerShell: terminating and non-terminating. The latter just displays an error without terminating script execution. The behavior can be controlled via the variable $ErrorActionPreference:
$ErrorActionPreference = 'Stop': terminate on all errors (terminating and non-terminating)
$ErrorActionPreference = 'Continue' (default): terminate on terminating errors, continue on non-terminating errors
$ErrorActionPreference = 'SilentlyContinue': don't terminate on any error
PowerShell also allows more fine-grained error handling via try/catch statements:
try {
# run command here
} catch [System.SomeException] {
# handle exception of a specific type
} catch [System.OtherException] {
# handle exception of a different type
} catch {
# handle all other exceptions
} finally {
# cleanup statements that are run regardless of whether or not
# an exception was thrown
}

Dot-sourcing PowerShell script file and return code

Here's some PowerShell code:
test.ps1:
. C:\path\to\test2.ps1
exit 5
test2.ps1:
exit 7
Run test.ps1 from a standard command prompt however you like to run PowerShell scripts, then call:
echo %errorlevel%
The expected result is a return code of 7. This is the first exit command in the PowerShell script. The actual result, however, is a return code of 5. Obviously the included script was terminated but its return code was ignored and the calling script happily continued.
How can I really terminate a script and return a result code no matter how it was called?
Or alternatively, how should I call test2.ps1 so that its return code is passed on to the outside world?
Background: My build script is made with PowerShell and it includes module files for different tasks. One task currently fails and the build server didn't detect the error because my start build script still returned 0.
You should query $lastExitCode that would have nonzero value if the last script/program exited with failure. So, your sample's test1.ps1 should be like this:
. C:\path\to\test2.ps1
if ($lastexitcode -ne 0) { exit $lastexitcode}
exit 5

Detecting PowerShell script is executed with error

I have a PowerShell script:
...
Any-Command -ErrorCode Stop
...
Then I call this script from a bat script:
...
powershell myscript.ps1
...
Now I would like to know in the bat script if the called PowerShell script is stopped on error and not reached the end of the script. How to do it?
One way to do it would be to add a top level trap statement to your script, something like:
trap {
exit 1; # or whatever error code
}
Note: trap may be considered old fashioned (although I like it top-level), the other option would be a try-finally around your whole script.
So when Any-Command exits with an exception, the trap statement is executed and the script exits with error code 1. If you don't add this, Powershell will exit with error code 0 (after all Powershell ran just fine, although the script didn't).
You can then detect the error code in a bat script using something like:
powershell -noprofile -noninteractive -file <<your script>>
IF ERRORLEVEL 1 (echo ERROR) ELSE (echo OK)
pause
This will detect any error code of 1 or higher.
You can also use %ERRORLEVEL% but be wary that this may be overridden as an environment variable.
Note: if you're running your script in a nested runspace, you could consider using $host.SetShouldExit(1) to ensure the root host exits as well.
Just adding to the answer given by Marcus
I noticed that the trap code even hides the actual error. In my case I needed the actual error occurred. Just adding the modified code for the completion.
trap
{
write-error $("Error: " + $_.Exception.Message);
exit 1; # or whatever error code
}
More info at http://huddledmasses.org/trap-exception-in-powershell/

How do you stop a Windows Batch file from exiting early?

I have a windows batch file that looks similar to:
C:\DoStuff.cmd
move output.bak C:\newfolder\output.bak
The problem i have is that DoStuff.cmd executes a java program that once complete exits the batch run back to the command prompt. Line 2 never gets hit.
i have tried the following instead to execute the command in a new window:
start "My program" /WAIT C:\DoStuff.cmd
move output.bak C:\newfolder\output.bak
What happens with the above is that the new command window spawns the cmd file runs and exits back to a waiting command prompt and the window never closes, leaving the first command window waiting and the second doing nothing stuck after finishing step one.
How do i execute the first command without it having control of the batch run somehow?
many thanks in advance
You can use DOS call command:
#echo off
call C:\DoStuff.cmd
echo Exit Code = %ERRORLEVEL%
After getting error code you can proceed for example with:
if "%ERRORLEVEL%" == "1" exit /B 1

How do I exit the command shell after it invokes a Perl script?

If I run a Perl script from a command prompt (c:\windows\system32\cmd.exe), how can I exit the command prompt after the script finishes executing.
I tried system("exit 0") inside the Perl script but that doesn't exit the cmd prompt shell from where the Perl script is running.
I also tried exit; command in the Perl script, but that doesn't work either.
Try to run the Perl script with a command line like this:
perl script.pl & exit
The ampersand will start the second command after the first one has finished. You can also use && to execute the second command only if the first succeeded (error code is 0).
Have you tried cmd.exe /C perl yourscript.pl ?
According to cmd.exe /? /C carries out the command specified by string and then terminates.
If you're starting the command shell just to run the perl script, the answer by Arkaitz Jimenez should work (I voted for it.)
If not, you can create a batch file like runmyscript.bat, with content:
#echo off
perl myscript.pl
exit
The exit will end the shell session (and as a side effect, end the batch script itself.)
You can start the program in a new window using the START Dos command. If you call that with /B then no additional window is created. Then you can call EXIT to close the current window.
Would that do the trick?
You can send a signal to the parent shell from Perl:
kill(9,$PARENT_PID);`
Unfortunately, the getppid() function is not implemented in Perl on windows so you'll have to find out the parent shell PID via some other means. Also, signal #9 might not be the best choice.