Terminar un script en PowerShell

394

He estado buscando una forma de terminar un script de PowerShell (PS1) cuando se produce un error irrecuperable dentro de una función. Por ejemplo:

function foo() {
    # Do stuff that causes an error
    $host.Exit()
}

Por supuesto que no existe tal cosa $host.Exit(). Lo hay $host.SetShouldExit(), pero en realidad esto cierra la ventana de la consola, que no es lo que quiero. Lo que necesito es algo equivalente a Python sys.exit()que simplemente detendrá la ejecución del script actual sin más adiós.

Editar: Sí, es solo exit. Duh

kprobst
fuente
8
Si desea evitar cerrar la ventana de PowerShell o ISE en mi caso; use "return" en su lugar. Simplemente finaliza el contexto actual en ejecución. "Chico nuevo" explica a fondo todas las opciones con fines educativos; es posible que desee considerar cambiar su respuesta aceptada (actualmente tiene más votos positivos de todos modos) para futuros usuarios de StackOverflow. También te permitirá depurar el script.
ZaxLofful
¿Responde esto a tu pregunta? ¿Qué es exactamente "salir" en PowerShell?
Mark Schultheiss

Respuestas:

389

Deberías usar la exitpalabra clave .

Michael Bray
fuente
15
Mierda, si no estuviera tan atrapado tratando de descubrir cómo hacer estas cosas de forma inteligente, probablemente lo habría intentado para empezar y habría descubierto que funciona :) Gracias.
kprobst
118
¿Cómo es esta la respuesta aceptada? Específicamente, "cierra la ventana de la consola", que el autor de la pregunta dijo "que no es lo que quiero".
claudekennilol 13/03/2013
3
@claudekennilol Solo el que pregunta puede aceptar una respuesta. O se perdieron el hecho de que se supone que la salida cierra la ventana, o cambiaron de opinión y lo consideraron aceptable para su propósito.
Iszi
3
No cierra la ventana de la consola en v3 o v4, que uso. Bueno, lo hará si ejecuta el script desde el explorador, pero no importa cómo termine el script, lo hará. Si se ejecuta desde una ventana de comandos de PowerShell, no cierra la ventana.
Joshua Nurczyk
14
La respuesta de New Guy es mucho más exhaustiva y los servidores se marcan como aceptados.
Jim Aho
585

Me doy cuenta de que esta es una publicación antigua, pero me encuentro volviendo mucho a este hilo, ya que es uno de los principales resultados de búsqueda al buscar este tema. Sin embargo, siempre me dejo más confundido que cuando vine debido a la información conflictiva. En última instancia, siempre tengo que realizar mis propias pruebas para resolverlo. Así que esta vez publicaré mis hallazgos.

TL; DR La mayoría de las personas querrán usar Exitpara terminar un script en ejecución. Sin embargo, si su script simplemente declara funciones para usarlas posteriormente en un shell, entonces querrá usarlas Returnen las definiciones de dichas funciones.

Salida vs retorno vs descanso

  • Salir: Esto "saldrá" del contexto actual. Si llama a este comando desde un script, saldrá del script. Si llama a este comando desde el shell, saldrá del shell.

    Si una función llama al comando Salir, saldrá del contexto en el que se esté ejecutando. Entonces, si esa función solo se llama desde un script en ejecución, saldrá de ese script. Sin embargo, si su script simplemente declara la función para que pueda usarse desde el shell actual y ejecuta esa función desde el shell, saldrá del shell porque el shell es el contexto en el que Exitse ejecuta la función que contiene el comando.

    Nota: De forma predeterminada, si hace clic con el botón derecho en un script para ejecutarlo en PowerShell, una vez que el script se haya ejecutado, PowerShell se cerrará automáticamente. Esto no tiene nada que ver con el Exitcomando o cualquier otra cosa en su secuencia de comandos. Es solo un comportamiento predeterminado de PowerShell para los scripts que se ejecutan utilizando este método específico de ejecutar un script. Lo mismo es cierto para los archivos por lotes y la ventana de línea de comandos.

  • Regresar: Esto volverá al punto de llamada anterior. Si llama a este comando desde un script (fuera de las funciones), volverá al shell. Si llama a este comando desde el shell, volverá al shell (que es el punto de llamada anterior para un solo comando ejecutado desde el shell). Si llama a este comando desde una función, volverá a donde se llamó la función.

    La ejecución de cualquier comando después del punto de llamada al que se devuelve continuará desde ese punto. Si se llama a un script desde el shell y contiene el Returncomando fuera de cualquier función, cuando regrese al shell no hay más comandos para ejecutar, por lo que un Returnuso de esta manera es esencialmente el mismo que Exit.

  • Descanso: Esto saldrá de los bucles y cambiará los casos. Si llama a este comando mientras no está en un bucle o caso de cambio, saldrá del guión. Si llama Breakdentro de un bucle que está anidado dentro de un bucle, solo saldrá del bucle en el que se llamó.

    También hay una característica interesante de Breakdónde puede prefijar un bucle con una etiqueta y luego puede salir de ese bucle etiquetado incluso si el Breakcomando se llama dentro de varios grupos anidados dentro de ese bucle etiquetado.

    While ($true) {
        # Code here will run
    
        :myLabel While ($true) {
            # Code here will run
    
            While ($true) {
                # Code here will run
    
                While ($true) {
                    # Code here will run
                    Break myLabel
                    # Code here will not run
                }
    
                # Code here will not run
            }
    
            # Code here will not run
        }
    
        # Code here will run
    }
Chico nuevo
fuente
39
También vale la pena señalar que Exitpuede tomar un código de retorno como parámetro (el valor predeterminado es 0), por ejemplo Exit 3.
aucuparia
2
Estoy de acuerdo, esta es una respuesta mucho mejor. "Descanso" puede tener consecuencias no deseadas.
iagomartinez
No estoy seguro de que su comentario sobre "Salir" sea completamente correcto, aunque en general esta es una gran respuesta. La salida parece estar causando que el ISE se cierre de una manera que nada más parece estar haciendo. Simplemente salir del contexto (por ejemplo, completar el script) no hace esto.
Bill K
1
@BillK De hecho. He actualizado la respuesta. Cuando escribí esto por primera vez, recuerdo que no encontré ninguna documentación oficial sobre Exit. Luego hice una Get-Command Exity Get-Alias Exitsin resultados. Luego miré para ver si era una palabra clave y no encontré documentación oficial al respecto. Mirándolo ahora, sin embargo, no sé cómo llegué a esa conclusión. Claramente es una palabra clave ( technet.microsoft.com/en-us/library/hh847744.aspx ). Quizás porque Exit es una de las únicas palabras clave que no tiene su propio tema about_ help y, por lo tanto, la lista de temas en la barra lateral izquierda no lo incluyó.
New Guy
66
¿Qué hay de tirar?
JDC
80

Exittambién saldrá de PowerShell. Si desea "romper" solo la función o script actual, use Break:)

If ($Breakout -eq $true)
{
     Write-Host "Break Out!"
     Break
}
ElseIf ($Breakout -eq $false)
{
     Write-Host "No Breakout for you!"
}
Else
{
    Write-Host "Breakout wasn't defined..."
}
EverydayNerd
fuente
55
No lo use breakcuando quiera simplemente salir de la función actual ... ¡los scripts de llamada también pueden verse afectados!
DannyMeister
49

Write-Error es para errores que no terminan y throw es para errores que terminan

El cmdlet Write-Error declara un error que no termina. Por defecto, los errores se envían en la secuencia de errores al programa host para que se muestre, junto con la salida.

Los errores que no terminan escriben un error en la secuencia de error, pero no detienen el procesamiento del comando. Si se declara un error que no termina en un elemento de una colección de elementos de entrada, el comando continúa procesando los otros elementos de la colección.

Para declarar un error de terminación, use la palabra clave Throw. Para obtener más información, consulte about_Throw ( http://go.microsoft.com/fwlink/?LinkID=145153 ).

Greg Bray
fuente
44
Esta parece ser la forma más correcta de terminar una actividad con un error. Delega a la persona que llama para que trate de manejar el error, lo cual es mucho mejor que simplemente intentar terminar abruptamente.
Paul Turner
Para mí, al menos en las funciones del módulo, arroja salidas pero no establece un código de salida. Esto se ejecutó a través de CLI, por ejemplo powershell -command "& module-function ...". Necesitaba convertir esas funciones para lanzar un try-catch de envoltura y salir de esa captura de envoltura para realmente generar un código de salida de error.
Josh
2
No se olvide $PSCmdlet.ThrowTerminatingError()de aquellos casos en los que throw simplemente no puede hacer el trabajo (problema conocido sin errores de terminación throw)
Djarid
33

Termina este proceso y le da al sistema operativo subyacente el código de salida especificado.

https://msdn.microsoft.com/en-us/library/system.environment.exit%28v=vs.110%29.aspx

[Environment]::Exit(1)

Esto le permitirá salir con un código de salida específico, que puede obtener de la persona que llama.

gabriwinter
fuente
3
En PowerShell, simplemente puede usar la salida integrada para esto, por ejemplo Exit 1.
Jonas
3
La salida incorporada no siempre funcionará como espera. Pruebe esto en powershell: "Exit 5"> test1.ps1 powershell.exe. \ Test1.ps1 $ lastexitcode "[Entorno] :: Exit (5)"> test2.ps1 powershell.exe. \ Test2.ps1 $ lastexitcode
gabriwinter
1
[Environment]::Exit(1)tiene el efecto secundario de salir de mi ventana de PowerShell cuando lo invoco en un script, donde exitparece que usarlo no lo hace.
Josh Desmond
25

Creo que estás buscando en Returnlugar de Break. La ruptura generalmente se usa para bucles y solo se rompe desde el bloque de código más interno. Use Volver para salir de una función o script.

Robar
fuente
77
Esto no es correcto: el OP pide específicamente salir de un script desde una función . Returnsimplemente regresará de la función, no del script. ( Returnen el nivel superior de un guión terminará el guión, pero esa no era la pregunta).
Michael Sorens
1
¿fue esta 'respuesta' realmente comentarios sobre la respuesta EverydayNerd?
tkokasih
22

Lanzar una excepción será bueno, especialmente si desea aclarar la razón del error:

throw "Error Message"

Esto generará un error de terminación.

Amr Bahaa
fuente
3
No creo que esto agregue más que la respuesta de Greg Bray casi un año antes stackoverflow.com/a/20556550/695671
Jason S
12

Puede ser mejor usar "trap". Una captura de PowerShell especifica un bloque de código para ejecutarse cuando se produce una terminación o un error. Tipo

Get-Help about_trap

para aprender más sobre la declaración de trampa.

fpschultze
fuente
10

Casualmente descubrí que (por ejemplo , simplemente , donde la etiqueta no existe ) parece salir del guión completo (incluso desde una función) y mantiene vivo al host. De esta manera, podría crear una función que rompa el script desde cualquier lugar (por ejemplo, un bucle recursivo) sin conocer el alcance actual (y crear etiquetas):Break <UnknownLabel>Break ScriptScript

Function Quit($Text) {
    Write-Host "Quiting because: " $Text
    Break Script
} 
hierro
fuente
1
Su respuesta es verdadera, pero tenga en cuenta que esto puede causar problemas a las personas que llaman de su secuencia de comandos si no están de acuerdo con su deseo de salir de la secuencia de comandos completa: stackoverflow.com/questions/45746588/…
DannyMeister
5

Usé esto para volver a ejecutar un programa. No sé si ayudaría, pero es una declaración simple si solo requiere dos entradas diferentes. Funcionó en PowerShell para mí.

$rerun = Read-Host "Rerun report (y/n)?"

if($rerun -eq "y") { Show-MemoryReport }
if($rerun -eq "n") { Exit }

No sé si esto ayuda, pero creo que sería similar a la finalización de un programa después de haberlo ejecutado. Sin embargo, en este caso, cada entrada definida requiere una salida listada y categorizada. También puede hacer que la salida llame una nueva línea de solicitud y finalice el programa de esa manera.

Michael Meli
fuente