Gestión de errores y depuración
Introducción a la gestión de errores y a la depuración
En vuestra vida de desarrollador de scripts, tarde o temprano deberá enfrentarse a errores o más precisamente a la gestión de los errores dentro de sus scripts. ¿Qué da más rabia que un script que se cuelga en plena ejecución? Cuando esto ocurre, es preferible y mucho más elegante interceptar los errores para mostrar un bonito mensaje personalizado en vez de dejar que PowerShell muestre sus propios mensajes.
Por otra parte, puede ser interesante tratar de anticipar los errores para actuar en consecuencia. Por ejemplo, si intenta suprimir una jerarquía completa de archivos y por alguna razón cualquiera esta contiene un archivo sobre el cual no dispone de permisos adecuados, entonces se generará un error.
Gracias a lo que va a aprender en este capítulo, podrá decidir cómo debe comportarse PowerShell frente a los errores. ¿Deberá interrumpir la ejecución del script o continuar? Y si continua ¿deberá o no mostrar un mensaje de error? Si sí, ¿qué tipo de mensaje? ¿El mensaje configurado por defecto o un mensaje que habrá definido usted mismo?
La otra parte de la gestión de los errores tiene que ver con la depuración. Cuando un script cuenta con algunos cientos de líneas de código, la depuración puede resultar...
La gestión de los errores
Para abordar correctamente este tema, primero tenemos que diferenciar dos tipos de errores: los errores críticos («Terminating errors» es el término inglés correspondiente) y los errores no críticos («Non-Terminating errors» en inglés).
Los primeros son considerados como graves, y cuando ocurren se interrumpe la ejecución del comando o del script. Los errores críticos se encuentran en general en errores sintácticos, en una división por cero, etc.
Los segundos, los errores no críticos, son más bien considerados como avisos; la mayor parte de los errores son, generalmente, de este tipo. En este caso, la ejecución del script continúa y - salvo indicación contraria - los errores se muestran por pantalla. Podemos encontrarnos este tipo de errores, por ejemplo, al suprimir un archivo si los permisos de acceso son insuficientes o si intentamos mover un archivo que no existe.
Veremos que el comportamiento por defecto, que consiste en continuar la ejecución del script al encontrarse con un error no crítico, se puede modificar. En algunos casos, es preferible parar el desarrollo de un script en vez de dejar que continúe por el peligro de generar errores en cascada que podrían poner en peligro en el mejor de los casos algunos archivos, en el peor nuestro sistema.
Empecemos por interesarnos en los errores...
Los errores no críticos
Debe saber que PowerShell permite definir su comportamiento frente a los errores de varias maneras:
-
Globalmente: es decir para todo el script o para la extensión en ejecución (consulte el capítulo Variables y tipos de datos) gracias a la variable $ErrorActionPreference.
-
Selectivamente: es decir que para cada comando el comportamiento puede ser diferente. Esto se hace gracias al uso de un parámetro que es común a todos los comandos. Este parámetro se llama ErrorAction.
1. Variable de opciones: $ErrorActionPreference
Interesémonos ahora en la « variable de opciones » (así es como llamamos a las variables que almacenan las preferencias de los usuarios) $ErrorActionPreference.
Puede tomar los siguientes valores:
Valor |
Descripción |
SilentlyContinue |
El script se ejecuta sin mostrar errores aunque los encuentre. |
Continue |
El script continua si encuentra un error y lo muestra (valor por defecto). |
Stop |
El script se interrumpe si encuentra un error. En este caso todos los errores toman el carácter crítico. |
Inquire |
Cuando ocurre un error, un prompt solicita al usuario qué debe hacer (continuar, continuar en modo silencioso, parar o suspender). |
Ignore |
Mismo comportamiento que SilentlyContinue salvo que en caso de error este no se almacena en la variable automática $Error. |
Como por defecto $ErrorActionPreference contiene el valor Continue, los errores no críticos no bloquean la ejecución; PowerShell simplemente los almacena y los muestra por pantalla.
Cuando $ErrorActionPreference toma el valor Stop, todos los errores encontrados se vuelven errores críticos. Así un error no crítico que surja durante la ejecución de un script interrumpirá este último al igual que lo hace un error crítico. Para modificar el valor de $ErrorActionPreference, puede hacer lo siguiente $ErrorActionPreference = ’Stop’ (¡no olvide las comillas simples!) o Set-Variable -Name ErrorActionPreference -value ’Stop’.
Ejemplo
Aplicación del comando Get-ChildItem en una carpeta inexistente.
PS > $ErrorActionPreference
Continue
PS > Get-ChildItem 'C:\NoExiste'
Get-ChildItem : Cannot find path 'C:\NoExiste' because it does not
exist.
...
Ahora, modifiquemos la variable $ErrorActionPreference con el valor...
Los errores críticos
Vayamos ahora a la caza de los errores críticos, llamados habitualmente «excepciones» por los desarrolladores. Por lo tanto es así como los llamaremos para distinguirlos de los errores no críticos.
Gracias a lo que descubriremos en esta sección, tendremos todavía más control sobre nuestros scripts. Así, en lugar de detener repentinamente un script a causa de una excepción, podremos actuar en consecuencia y tomar las medidas (correctivas o alternativas) que se imponen. En efecto, a menudo resulta indispensable saber si todo se ejecuta normalmente. Pero para esto debemos intentar prever los errores antes de que se produzcan...
1. Intercepción de errores críticos con Try-Catch-Finally
Como decíamos antes, cuando un error crítico ocurre, la ejecución se interrumpe bruscamente. Para evitar tener que gestionar los errores comando a comando, es posible utilizar bloques de ejecución Try, Catch y Finally. Estas instrucciones son bien conocidas, pues están presentes en muchos lenguajes de programación.
El bloque Try contiene el código que puede provocar la excepción. Se ejecuta hasta que ocurra una excepción (por ejemplo: división por cero) o hasta su éxito total. Si se produce un error crítico durante la ejecución de instrucciones, PowerShell pasa el objeto de error del bloque Try al bloque Catch.
La sintaxis del bloque Try es la siguiente:
Try {<bloque de instrucciones>}
La cláusula Catch contiene el bloque de ejecución asociado opcionalmente al tipo de error que se ha de interceptar. Cuando se utiliza Catch sin precisar ningún tipo, se intercepta cualquier excepción. La sintaxis del bloque Catch es la siguiente:
Catch [<tipo de error a interceptar>] {<bloque de instrucciones>}
Opcionalmente, se utiliza Finally seguido de un bloque de script. Este último se ejecuta cada vez que se ejecuta el script, aunque tenga lugar o no un error.
La sintaxis del bloque Finally es la siguiente:
Finally {<bloque...
La depuración
En lo relativo a la depuración, PowerShell está dotado de ricas funcionalidades en comparación con su primo hermano VBScript. Es tan cierto que incluso integra la noción de breakpoint y de ejecución paso a paso tanto en modo consola como de manera gráfica.
Hay mil y una formas de depurar un programa; podría parecerse a un arte, pues resulta algo complejo y, por consiguiente, consume tiempo. A menudo, las técnicas difieren de una persona a otra. Sin embargo, las bases son comunes... Una técnica clásica consiste en intercalar en un script mensajes para mostrar el contenido de las variables o mensajes de aviso de paso para tratar de detectar el o los bugs. Veremos que con PowerShell es posible hacerlo todavía mejor (en lugar de definir Write-Host de depuración sin ton ni son) para no «contaminar» nuestro código.
Mostraremos también en este apartado cómo realizar una ejecución paso a paso, a menudo indispensable para encontrar el origen de nuestros errores.
Por último, para evitar perder tiempo depurando, lo mejor es evitar crear bugs. Qué fácil resulta decirlo, ¿verdad? Pero verá que, esforzándose en respetar algunas buenas prácticas, tales como declarar variables y asignarles un tipo, ahorrará un tiempo precioso. Hablaremos de esto también.
1. Mostrar información en tiempo de ejecución
PowerShell está dotado de varios flujos de mensajes que no están activos por defecto. Estos tipos de mensajes pueden resultar muy útiles cuando se está depurando (pero no solo aquí), pues es posible habilitarlos bajo demanda. Podríamos dejar estos comandos en nuestro código, pues no hacen nada hasta que se activan.
En efecto, en otros lenguajes diferentes a PowerShell, cuando se realiza la depuración mediante visualización (de mensajes o variables), nos vemos obligados a volver sobre el código una vez que ha terminado la sesión de depuración para comentar cada línea. Esto ya no será necesario con los comandos que le vamos a presentar.
He aquí los distintos flujos a nuestra disposición, así como los comandos asociados para utilizarlos:
Flujo |
Número de flujo |
Comandos |
Variable de preferencia asociada |
Warning |
3 |
Write-Warning |
$WarningPreference... |