/
/

Guía completa de gestión de errores en PowerShell

por Team Ninja
PowerShell Error Handling Guide blog banner image

Resumen instantáneo

Este post ofrece una lista completa de comandos CMD básicos y una inmersión profunda en los comandos de Windows, con más de 70 comandos cmd esenciales tanto para principiantes como para usuarios avanzados. Explica comandos prácticos del símbolo del sistema para la gestión de archivos, la navegación por directorios, la solución de problemas de red, las operaciones de disco y la automatización con ejemplos reales para mejorar la productividad. Tanto si estás aprendiendo los comandos básicos de cmd como si ya dominas las herramientas avanzadas de la CLI de Windows, esta guía te ayudará a utilizar el Símbolo del sistema de forma más eficaz.

PowerShell es la línea de comandos y el lenguaje de scripting principal de los sistemas operativos Windows. Permite ejecutar programas y realizar tareas de gestión del sistema desde el terminal, y lo usan ampliamente los administradores de sistemas y los desarrolladores para automatizar sus flujos de trabajo.

La gestión de errores es una parte fundamental de cualquier script y automatización. Si algo va mal, tus scripts de PowerShell no deberían simplemente fallar: deberían detectar que se ha producido un error y actuar en consecuencia, ya sea reintentando la tarea o avisándote de que algo no ha funcionado para que puedas encontrar la causa y corregirla.

Esta guía te ofrece una visión detallada de la gestión de errores en PowerShell: tipos de errores, técnicas de gestión, ejemplos de cómo implementarla en tus scripts y buenas prácticas para lanzar, capturar, registrar y responder a los errores.

Si quieres un resumen rápido, mira esta guía en vídeo: Guía completa de gestión de errores en PowerShell.

Tipos de errores en PowerShell

Existen dos tipos de errores que debes tratar de forma distinta para que tus scripts de PowerShell sean fiables.

Los errores de terminación detienen la ejecución del comando o del script en cuanto se producen. Normalmente se trata de excepciones y pueden gestionarse con bloques try/catch (lo explicamos más adelante en este artículo). Entre sus causas están los errores de sintaxis (cuando escribes mal un comando o pasas parámetros no válidos) y los errores internos de la aplicación o del comando que estás ejecutando.

Los errores sin terminación no detienen la ejecución del comando ni del script: tu script de PowerShell sigue funcionando después de que se produzcan. Por lo general, muestran un mensaje de error y la ejecución continúa, así que hay que tratarlos de otra manera que los errores de terminación para que no provoquen un mal funcionamiento del script si más adelante se necesita el resultado esperado. Los errores sin terminación pueden deberse a tiempos de espera de red, archivos que no existen o problemas de permisos que, aunque no sean una excepción crítica ni un error de ejecución en sí, darán lugar a un comportamiento imprevisto si no se gestionan.

Conceptos básicos de la gestión de errores en PowerShell (try, catch, finally y $ErrorActionPreference)

Los errores de terminación y las excepciones se lanzan (se produce el error) y se capturan (se ejecuta código para gestionar el error). Los errores no capturados detienen la ejecución de tu script de PowerShell. Si encapsulas tu código en bloques try , catch y finally, podrás controlar este tipo de errores.

Si el código que se ejecuta dentro de un bloque try lanza un error, se ejecutará el bloque de código del catch correspondiente para gestionarlo (lo que permite continuar la ejecución si procede). Las tareas de limpieza que quieras ejecutar tanto si se produce un error como si no pueden añadirse a un bloque finally. Más abajo en esta página lo verás con un ejemplo de código completo.

La gestión de errores sin terminación funciona de otro modo, ya que no se lanza ningún error que detenga la ejecución y, por tanto, no se puede capturar. En su lugar, el error se guarda en la variable $Error, una matriz de errores a la que puedes acceder en cualquier punto de tus scripts de PowerShell para comprobar si una instrucción anterior generó un error sin terminación, como en este ejemplo:

Get-ChildItem -Path "C:fake_path"

if ($Error) {

Write-Host "Error occurred: $($Error[0])" # Display the most recent error as a string

$Error.Clear() # Clear the error

}

Arriba, el comando de PowerShell Get-ChildItem genera un error sin terminación si la ruta del sistema de archivos que se le pasa no existe (en este caso, C:fake_path). El error queda registrado en la variable $Error, que después se comprueba y se gestiona.

Si quieres asignar la salida de error de un comando concreto a una variable personalizada, puedes usar el parámetro -ErrorVariable (ten en cuenta que en este caso la variable de error no es una matriz):

Get-ChildItem -Path "C:fake_path" -ErrorVariable customError

if ($customError) {

Write-Host "Error occurred: $customError" # Display the error as a string

}

También puedes convertir los errores sin terminación en errores de terminación y gestionarlos con bloques try/catch. Puedes hacerlo para todos los errores sin terminación que se produzcan en el script estableciendo la variable global $ErrorActionPreference en Stop:

$ErrorActionPreference = "Stop"

O, si solo quieres hacerlo para los errores de un único comando, puedes usar el parámetro -ErrorAction:

Get-ChildItem -Path "C:fake_path" -ErrorAction Stop

Cómo implementar bloques try/catch/finally en PowerShell

A continuación tienes un script de PowerShell de ejemplo que muestra la sintaxis y la estructura de los bloques try/catch/finally, cómo usar varios bloques catch para distintos tipos de excepciones y cómo emplear un bloque finally para limpiar y gestionar los errores restantes. Primero, un único error gestionado con un bloque try/catch:

try {

# Attempt a file operation that fails

Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop

} catch {

Write-Host "Exception caught: $($_.Exception.Message)"

}

También puedes gestionar varios tipos de errores posibles en un solo bloque try, con un bloque catch propio para cada uno:

try {

# Each of the below commands will throw a terminating error of a different type

Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop # Attempt a file operation that fails to throw a ItemNotFoundException

$null.fakeFunction() # Attempt to run a non-existent method on a null object to throw a RuntimeException

$divideZero = 1/0 # Divide by zero to throw an exception that won't be specifically caught

} catch [System.Management.Automation.ItemNotFoundException] { # Catch the specific error thrown by Get-Content

Write-Host "Item not found exception caught: $($_.Exception.Message)"

} catch [System.Management.Automation.RuntimeException] { # Catch the specific error thrown by $null.fakeFunction

Write-Host "Runtime exception caught: $($_.Exception.Message)"

} catch { # Catch all other errors

# General catch block for any other exceptions

Write-Host "General exception caught: $($_.Exception.Message)"

} finally { # The finally block is always executed whether an exception was thrown or not.

Write-Host "Executing the finally block."

$Error.Clear() # This could, for example, be used to clean up non-terminating errors.

}

La finalidad de cada instrucción se explica en el propio código para que veas en su contexto completo cómo funcionan juntas las instrucciones try, catch y finally. Ten en cuenta que, si se producen varios errores de terminación en el mismo bloque try, solo se capturará y gestionará el primero y, a continuación, se ejecutará el bloque finally. Una vez corregido ese error, los siguientes se capturarán en la siguiente ejecución del script.

Técnicas avanzadas de gestión de errores y ejemplos

También es posible anidar bloques try/catch para que los errores vayan «subiendo» a través de ellos. Así puedes gestionar errores concretos en los bloques try/catch internos y tratar en los bloques externos cualquier error no capturado o relanzado, incluidos los que se produzcan dentro de tus bloques catch internos. Por ejemplo, podrías usar bloques anidados para gestionar errores específicos y después un único bloque externo para capturar y registrar todos los errores, en lugar de repetir el código de registro en cada catch interno.

try { # Beginning of the outer catch block

try { # Beginning of the inner catch block

# Include potentially error-causing code here

Get-Content -Path "C:fake_pathfake_file.txt" -ErrorAction Stop

} catch [System.Management.Automation.ItemNotFoundException] { # Catch statement for the inner catch block that specifically handles ItemNotFoundException

Write-Host "Inner try block file not found exception caught: $($_.Exception.Message)"

} catch { # Catch statement for the inner catch block that handles all other exceptions

Write-Host "Inner try block exception caught: $($_.Exception.Message)"

throw # Re-throw the exception so that it will bubble up to the outer try/catch block

}

} catch { # Catch statement for the outer catch block

Write-Host "Outer try block exception caught: $($_.Exception.Message)" # Handle all errors re-thrown in the inner catch blocks here for clean up, logging, and alerting tasks

}

Fíjate en que, en el ejemplo anterior, la excepción ItemNotFoundException no se relanza, así que no subirá hasta el bloque catch externo.

A medida que amplíes tus scripts de PowerShell para cubrir tus propios casos de uso, probablemente querrás poder crear tus propias excepciones personalizadas y registros de error de PowerShell:

try {

$customException = New-Object Exception "This is a custom error!" # Create and throw a custom error

# Create a custom Error Record

$customErrorRecord = New-Object System.Management.Automation.ErrorRecord (

$customException,

"CustomErrorID",

[System.Management.Automation.ErrorCategory]::NotSpecified, # Sets the ErrorRecord category to NotSpecified

$null # Specify no specific target object for this error

)

throw $customErrorRecord

} catch {

# Catch and handle the custom error record

Write-Host "Error Message: $($_.Exception.Message)"

Write-Host "Error ID: $($_.FullyQualifiedErrorId)"

}

Arriba puedes ver que no se especifica ningún objeto de destino (está establecido en $null). En su lugar podrías indicar una ruta de archivo u otra referencia y añadir más detalle al texto de la excepción para que el error personalizado resulte más informativo.

Buenas prácticas de gestión de errores en PowerShell

Hay varias buenas prácticas que conviene seguir al escribir tus scripts de PowerShell para que la gestión de errores sea realmente eficaz:

  • Escribe mensajes de error claros y predecibles: tus mensajes deben ser descriptivos e incluir suficiente información de la excepción o del objeto ErrorRecord para identificar la causa concreta del error.
  • Asegúrate de que tus scripts puedan seguir ejecutándose (o salir de forma controlada) cuando se produzca un error: si tus scripts están ejecutando otras tareas, quizá te interese gestionar el error y dejar que continúen. Los errores que impidan continuar deberían hacer que el script salga con un código de salida, y el resultado de cualquier error debería registrarse y notificarse.
  • Pon a prueba con regularidad tu sistema de gestión de errores y de informes: tus automatizaciones en PowerShell no sirven de nada si fallan sin que te enteres. Prueba tus scripts periódicamente provocando errores a propósito para comprobar que la gestión funciona, que los detalles se registran y que recibes el aviso.

La gestión de errores es una función importante del scripting en PowerShell y resulta muy útil mientras desarrollas tus habilidades de scripting y automatización. Implementarla correctamente —lanzando bien los errores, usando bloques try/catch/finally y aprovechando $ErrorActionPreference— te ayudará a aprender la sintaxis de PowerShell, te dará mejor visibilidad sobre los problemas que encuentren tus scripts y te permitirá gestionarlos mejor.

Quizá también te interese…

¿Listo para simplificar los aspectos más complejos de las TI?