HOWTO · PowerShell

Cómo finalizar un script en Windows PowerShell

Aprende cuándo usar exit, return, throw, break, continue o Stop-Process para detener el ámbito correcto y devolver un código de salida fiable en PowerShell.

En esta página

Finalizar un script de PowerShell no es una única operación. La instrucción adecuada depende de si se debe detener todo el proceso del script, solo la función actual, una iteración o un proceso distinto del sistema operativo.

Objetivo Instrucción
Finalizar el script principal y comunicar un estado exit <código>
Salir de una función, un script o un bloque de script return
Comunicar un fallo que el llamador pueda capturar throw
Salir de un bucle o switch break
Pasar al siguiente elemento del bucle o switch continue
Terminar otro proceso local Stop-Process

Finalizar un script de PowerShell con exit

exit termina un script o una instancia de PowerShell. Un entero opcional se convierte en el código de salida del proceso: por convención, 0 indica éxito y un valor distinto de cero indica fallo. Documenta cada código de error para que las tareas programadas, los trabajos de CI y los programas que llaman al script puedan reaccionar correctamente.

Guarda este script de entrada como Check-Config.ps1:

param([Parameter(Mandatory)][string]$Path)

if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
    Write-Error "Configuration file not found: $Path"
    exit 2
}

Write-Output 'Configuration file found.'
exit 0

Ejecútalo como proceso secundario desde otra sesión de PowerShell y consulta el estado:

powershell.exe -NoProfile -File .\Check-Config.ps1 -Path .\missing.json
$LASTEXITCODE

El último comando muestra 2. En PowerShell 7, usa pwsh en lugar de powershell.exe. PowerShell expone el estado del proceso secundario mediante $LASTEXITCODE; un llamador de cmd.exe lo obtiene de %ERRORLEVEL%.

Reserva exit para el límite del script principal. Si una función reutilizable llama a exit, puede cerrar una sesión interactiva, el ejecutor de pruebas u otro host. Es preferible que las funciones devuelvan datos o lancen errores y que solo el script de entrada convierta el resultado en un código de salida.

Salir del ámbito actual con return

return sale de la función, el script o el bloque de script actual. No establece por sí solo un código de salida del proceso.

function Get-ConfigText {
    param([string]$Path)

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        return $null
    }

    Get-Content -LiteralPath $Path -Raw
}

En una función normal de PowerShell, todo valor no capturado del flujo de éxito forma parte de la salida, no solo la expresión posterior a return. Para los diagnósticos, utiliza Write-Verbose u otro flujo apropiado en lugar de emitir cadenas adicionales con Write-Output.

Detenerse con un error capturable mediante throw

throw crea de forma predeterminada un error que termina el script y desenrolla la pila de llamadas hasta que un bloque catch o una instrucción trap lo controla. Úsalo cuando una función no pueda producir un resultado válido y el llamador deba decidir cómo recuperarse.

function Get-RequiredConfig {
    param([string]$Path)

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        throw "Configuration file not found: $Path"
    }

    Get-Content -LiteralPath $Path -Raw
}

try {
    $config = Get-RequiredConfig -Path '.\settings.json'
}
catch {
    Write-Error $_
    exit 2
}

El patrón separa responsabilidades: la función explica el fallo con throw, mientras que el script de entrada lo captura y elige el código público. No todos los errores de cmdlets llegan a catch; añade -ErrorAction Stop a un error no terminante cuando necesites controlarlo allí.

Usar break y continue solo en bloques de control

break sale del bucle o switch más cercano. continue omite el resto de la iteración actual e inicia la siguiente.

foreach ($name in 'alpha', '', 'beta', 'stop', 'omega') {
    if ([string]::IsNullOrWhiteSpace($name)) {
        continue
    }
    if ($name -eq 'stop') {
        break
    }
    Write-Output $name
}

Salida:

alpha
beta

No son comandos generales para finalizar scripts. Fuera de un bucle, switch o trap, PowerShell puede buscar una construcción contenedora en la pila de llamadas y terminar el espacio de ejecución actual si no encuentra ninguna.

Terminar otro proceso con Stop-Process

Stop-Process actúa sobre un proceso distinto del equipo local; no significa “detener este script”. Previsualiza una coincidencia amplia con -WhatIf:

Get-Process -Name notepad -ErrorAction SilentlyContinue |
    Stop-Process -WhatIf

Quita -WhatIf solo después de confirmar los objetivos. Es preferible utilizar un objeto de proceso conocido o un PID cuando un nombre pueda coincidir con varios procesos. Detener un proceso de otro usuario también puede exigir una sesión de PowerShell elevada.

Conservar los códigos de salida de programas nativos

$? indica si el último comando de PowerShell tuvo éxito, mientras que $LASTEXITCODE contiene el código de salida del último programa nativo. Guarda el valor de inmediato porque otro comando nativo puede sobrescribirlo.

git status --porcelain
$gitCode = $LASTEXITCODE

if ($gitCode -ne 0) {
    Write-Error "git failed with exit code $gitCode"
    exit $gitCode
}

Conservar la limpieza y distinguir la cancelación

Conserva la limpieza en finally, no después de una línea que pueda terminar el procesamiento. Según la documentación de palabras clave de PowerShell, finally se ejecuta si try tiene éxito, si un error llega a catch, si se llama a exit o si Ctrl+C interrumpe el script. Es el lugar indicado para liberar un flujo, un bloqueo o un archivo temporal.

$stream = $null

try {
    $stream = [System.IO.File]::OpenRead($Path)
    # Process the stream.
}
finally {
    if ($null -ne $stream) {
        $stream.Dispose()
    }
}

Deja que el código reutilizable haga throw o return hasta el script de entrada, en lugar de llamar a exit en medio del trabajo. Así el script de entrada puede limpiar, escribir un diagnóstico y elegir el estado del proceso en un lugar visible. Ctrl+C, un trabajo detenido y una entrada no válida son eventos distintos: decide y documenta si cada uno es cancelación, error de validación u otro estado al que un llamador o planificador deba responder. No los reduzcas silenciosamente a un fallo genérico. Detener otro proceso es diferente; prefiere el cierre normal de la aplicación. Stop-Process -Force puede impedir la limpieza y solo debe usarse cuando esa consecuencia se entienda.

Mantener scripts secundarios y hosts en el ámbito previsto

El operador de llamada ejecuta un script secundario en su propio ámbito de script; dot-sourcing lo ejecuta en el ámbito actual e importa sus funciones y variables. Usa dot-sourcing solo cuando se pretenda importar definiciones.

# Run the child in its own script scope.
& .\Child.ps1

# Import definitions into the current scope.
. .\Functions.ps1

Un exit en código reutilizable es más fuerte que return: puede cerrar la sesión interactiva, el ejecutor de pruebas u otro host que lo invocó. Un proceso secundario iniciado con powershell.exe -File o pwsh -File termina y devuelve el control al llamador; una consola interactiva puede cerrar su sesión. Los runspaces incrustados y los editores pueden comportarse de otro modo. Prueba la línea de producción, incluidos -File frente a -Command, perfiles, comillas, salida y código de salida por separado.

Recomendación

Usa exit <código> solo en el límite deliberado del script superior, return para el ámbito actual y throw para un fallo que el llamador pueda controlar. Usa break y continue donde su bucle o switch sea visible, y Stop-Process solo para un proceso local independiente. La lógica en funciones que devuelven datos o lanzan errores sigue siendo reutilizable; un script de entrada pequeño puede traducir el resultado a un estado estable para una shell, programador de tareas, CI o programa envoltorio.