Gestión de errores

Revisar si falta algo aquí!!

Usar una variable para almacenar los errores nos permite averiguar para qué elementos ha fallado un determinado comando. Es decir, lanzamos un comando sobre 100 servidores y obtenemos que 3 han fallado. Usando las propiedades almacenadas de los errores almacenadas en la variable podemos obtener para qué elementos ha fallado.

Vamos a ver esto en acción con un ejemplo sencillo.

Lanzamos Get-Process -Id 13, 23, 37, con lo que obtendremos tres errores (todos los indicadores de procesos son pares).

1 PS> Get-Process -id 13, 23, 37 -ErrorVariable $e

Si inspeccionamos el contenido de $e obtenemos información, pero no toda la información; podemos comprobarlo mediante:

1 PS> $e[0] | get-member

En la salida observamos que tenemos un montón de propiedades disponibles. Sin embargo, si lanzamos $e[0] | fl * seguimos obteniendo únicamente parte de todas las propiedades disponibles. Esto es debido a que PowerShell trata de manera especial los errores.

Para forzar a que PowerShell muestre todas las propiedades disponibles, usamos el parámetro -Force:

1 PS> $e[0] | fl * -force

En la salida del comando observamos que tenemos una propiedad llamada TargetObject, de manera que:

1 PS> $e.TargetObject
2 13
3 23
4 37

Es decir, en $eTargetObject se almacenan los objetos sobre los que se ha intentado realizar la acción que ha fallado. Esto nos permite lanzar acciones correctoras sobre únicamente los objetos que han fallado:

1 PS> foreach($t in $e.TargetObject) {$t} # En este caso sólo mostramos los obj\
2 etos

Si queremos modificar el comportamiento de PowerShell con respecto a la información que muestra relativa a los errores, podemos modificar la variable ErrorView:

Si no recordamos exactamente cómo se llama la variable, siempre podemos buscarla en el espacio de nombres de las variables: powershell PS> dir variable:*error*

Por defecto tiene el valor NormalView, pero también tenemos otra vista llamada CategoryView. Esta vista contiene la misma información, pero de una forma más compacta y sin traducir al idioma local, lo que permite buscar el error de forma más sencilla.

Gestión de errores usando Try...Catch

Imaginemos el siguiente escenario: lanzamos una serie de consultas WMI contra una lista de servidores, pero algunos de ellos están offline; la primera consulta WMI fallará, pero después pasaremos a la segunda, que fallará de nuevo, etc. El scriptt se ralentiza porque las consultas fallidas intentan contactar con los servidores caídos de nuevo, y lo mismo sucederá con las siguientes consultas.

La manera más sencilla de solucionar este problema sería, en cuanto se detecta un error, pasar al siguiente servidor de la lista y no seguir probando contra el mismo las siguientes consultas -que sabemos que fallarán.

Para ello, usamos Try ... Catch ... Finally.

1 $computer = 'notonline'
2 Try {
3 	$os = Get-WMIobject -ComputerName $computer -Class win32_operatingSystem `
4 			-ErrorAction Stop -ErrorVariable CurrentError
5 } Catch {
6 	Write-Warning "You hit an offline computer: $Computer."
7 }

La idea del bloque Try...Catch es que la acción en caso de error sea Stop, para que la ejecución se detenga y pase al bloque Catch. Si hemos especificado ErrorAction = SiletlyContinue, la ejecución continua y no se salta al bloque Catch.

Finally se ejecuta siempre en un bloque Try ... Catch y suele usarse para hacer limpieza o rollbacks, etc.

Registrando los errores

Si tenemos varias acciones que pueden fallar por el mismo motivo, especificamos la acción en caso de error en la primera. En el bloque Catch podemos especificar, usando un parámetro tipo switch el guardado del error en un fichero de texto, por ejemplo:

 1 ...
 2 catch {
 3 	Write-Warning "El equipo $computer no responde."
 4     if( $ErroLog ) {
 5     	Get-Date | Out-File $LogFile -Force # Lo sobreescribe si existe
 6         $Computer | Out-File $LogFile -Append
 7         $CurrentError | Out-File $LogFile -Append
 8     }
 9 ...
10 }

Otra opción es, en vez de escribir en un fichero, podemos usar los cmdlets Write-EventLog -LogName Application -Source MiScript -EntrType Information -Message "El script ha sido ejecutado" -EventID 12345.

De hecho, guardando información de cuándo se ha ejecutado el script y otra información útil que pueda consultarse a través del eventlog de la máquina.