Reputation: 43
When I try the "Exit" function. It does not close the console. It doesn't do anything. How can I change it to make it exit the console?
Write-Host "-------------- MENU ---------------"
Write-Host "Utility Menu"
Write-Host "1 = Help Ipconfig"
Write-Host "2 = Ipconfig"
Write-Host "3 = Notepad"
Write-Host "4 = Calculator"
Write-Host "5 = Exit"
Write-Host "-----------------------------------"
$userinput = Read-Host "Please select a menu item: "
switch ( $userinput )
{
1 {Help Ipconfig}
2 {ipconfig}
3 {start notepad}
4 {start calc.exe}
5 {Exit}
}
Upvotes: 4
Views: 8262
Reputation: 437042
There is helpful information in the existing answers, but I feel that conceptual framing is called for:
exit
[...] It does not close the console.
It is unusual for a script to want to terminate the entire interactive PowerShell session (which is what would lead to the console window closing), and exit
would only do so outside a script - see the bottom section for details.
If exiting the session as a whole from a script or function[1] is really your intent, use [Environment]::Exit(0)
, as suggested by Colyn1337. (0
is the exit code to report on process termination, which by convention signals success; when closing an interactive session, this exit code is likely irrelevant.)
Language keywords for exiting various scopes from PowerShell:
break
is used to exit just a switch
statement or a loop statement (foreach
/ for
, while
, do
); that is, execution continues in the same scope after such a statement - see the conceptual about_Break help topic.
break
or continue
without an enclosing loop or switch
statement, PowerShell looks up the call stack for such a statement and exits the first such statement it finds; if there is none, the current call stack is terminated; that is, at the very least the enclosing script terminates as a whole.
ForEach-Object
call (whose built-in aliases are %
and, somewhat confusingly, foreach
), invariably in a pipeline, is not a loop; to "break" out of a script block passed to ForEach-Object
, i.e. to move on to the next pipeline input object, use return
.return
is used to exit an enclosing script file (if executed directly in the script file's top-level scope) or function or script block ({ ... }
), optionally by first outputting data via an expression or command passed as an argument (e.g. return 'foo'
); see the conceptual about_Return help topic.
return
has no effect on the exit code reported by a script and therefore potentially by a PowerShell process as a whole; only exit
can be used to set the exit code - see below.exit
is used to exit an interactive session or the enclosing script file and to optionally set an exit code:
Outside of a script file, exit
exits an interactive PowerShell session as a whole (closes the console window).
Inside of a script file, exit
always exits that script (only) - even when called from a function inside that script.
return
, which from a function just exits that function, whether called from inside a script or not.exit $exitCode
- where $exitCode
stands for any integer[2] - can be used to set a script / session's exit code; using just exit
is the same as exit 0
:
Since PowerShell's error handling isn't based on exit codes (unlike that of shells such as cmd.exe
and bash
), setting an exit code is primarily of interest for communicating success vs. failure to outside callers.
If you execute a script from the outside via PowerShell's CLI (e.g., pwsh -File script.ps1
), the exit code set via exit $exitCode
will also become the process exit code, which the outside caller - e.g., a CI tool - can then inspect.
exit $exitCode
is reflected in the automatic $LASTEXITCODE
variable, though note that this variable is also set by any call to an external program, to that program's process exit code.See this post for more information about the relevance and use of exit codes in PowerShell.
[1] As postanote's answer shows, exit
from inside a function that has been dot-sourced (loaded directly into) the global scope, exits the whole session too. However, it is better to explicitly signal the unusual intent to exit the entire session via [Environment]::Exit(0)
.
[2] Technically, you can pass any expression or command to exit
(as with return
, though the expression/command's output becomes data there, as-is), but anything that cannot at least be converted to an integer - e.g., exit 'not a number'
- is quietly ignored and is the same as exit 0
. Also note that the range of valid integers varies by platform: Windows supports [int]
values, i.e. signed 32-bit values that include negative numbers. By contrast, Unix-like platforms only support unsigned [byte]
values, i.e. numbers from 0
to 255
(negative numbers are converted to positive ones, and only the lowest byte is considered for larger values ).
Upvotes: 7
Reputation: 1713
The Exit
command is really like a function within the powershell parser. There's some packaging around it and when it executes, Exit
doesn't always mean Exit
. It quite often will be replaced by the parser with a Return
.
To get around that, you can instruct the runtime to terminate with the following code:
[System.Environment]::Exit(0)
The integer in the Exit method is the return code you want the runtime to out as it exits. Typically anything other than 0 will be interpreted as an error.
Upvotes: 5
Reputation: 16076
Continuing from my comment...
Gif of your code and menu selection
Running your code a straight script will do nothing on the exit option. Refactoring your script as a function does work.
# Saved as Start-Menu.ps1
Function Start-Menu {
Clear-Host
Write-Host "-------------- MENU ---------------"
Write-Host "Utility Menu"
Write-Host "1 = Help Ipconfig"
Write-Host "2 = Ipconfig"
Write-Host "3 = Notepad"
Write-Host "4 = Calculator"
Write-Host "5 = Exit"
Write-Host "-----------------------------------"
$userinput = Read-Host "Please select a menu item: "
switch ( $userinput )
{
1 {Help Ipconfig}
2 {ipconfig}
3 {start notepad}
4 {start calc.exe}
5 {Exit}
}
}
Another gif on the action.
Or use what Colyn1337, gave you or this...
switch ( $userinput )
{
1 {Help Ipconfig}
2 {ipconfig}
3 {start notepad}
4 {start calc.exe}
5 {Stop-Process -Id $PID}
}
...(which gets the current process ID of the PowerShell session) and thus no need for the function and just run the script as-is, and note though the namespace is slower to close than the function or $PID approach.
Upvotes: 4
Reputation: 52
Use break instead of exit.
Write-Host "-------------- MENU ---------------"
Write-Host "Utility Menu"
Write-Host "1 = Help Ipconfig"
Write-Host "2 = Ipconfig"
Write-Host "3 = Notepad"
Write-Host "4 = Calculator"
Write-Host "5 = Exit"
Write-Host "-----------------------------------"
$userinput = Read-Host "Please select a menu item: "
switch ( $userinput )
{
1 {Help Ipconfig}
2 {ipconfig}
3 {start notepad}
4 {start calc.exe}
5 {break}
}
Upvotes: 0