Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
¿Qué es el manejo de errores? . . . . . . . . . . . . . . . . 3
¿Cómo está organizado este libro? . . . . . . . . . . . . . 3
Epílogo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
El gran libro de manejo
de errores en PowerShell
Escrito por Dave Wyatt
Diseño de portada por Nathan Vonnahme
ErrorRecords y Exceptions
En .NET Framework, sobre el que se construye PowerShell, el
reporte de errores se realiza en gran medida lanzando excepciones.
Las excepciones son objetos .NET que tienen como tipo base
System.Exception⁵. Estos objetos de excepción contienen suficiente
información para comunicar todos los detalles del error a una
aplicación de .NET Framework (el tipo de error que ocurrió, un
seguimiento de pila de llamadas del método que condujo al error,
etc.) que por sí solo no es suficiente información para proporcionar
a un script de PowerShell. Por eso, PowerShell tiene su propio
seguimiento de la pila de scripts y de llamadas de función de las
que .NET Framework no sabe nada. También es importante saber
qué objetos generaron errores, ya que una única sentencia o tubería
(pipeline) es capaz de producir múltiples errores.
Por estas razones, PowerShell expone el objeto ErrorRecord. Erro-
rRecord contienen una excepción .NET, junto con varias otras
piezas de información específica de PowerShell. Por ejemplo, la
figura 1.1 muestra cómo acceder a las propiedades TargetObject,
CategoryInfo e InvocationInfo de un objeto ErrorRecord; que pro-
⁵http://msdn.microsoft.com/en-us/library/system.exception(v=vs.110).aspx
Fundamentos para el manejo de errores en PowerShell 6
image003.png
Figura 1.1: Algunas de las propiedades más útiles del objeto Erro-
rRecord.
Terminating versus
Non-Terminating Errors
PowerShell es un lenguaje extremadamente expresivo. Esto signi-
fica que una sola sentencia o pipeline de código PowerShell puede
realizar el trabajo de cientos, o incluso miles de instrucciones crudas
de CPU. Por ejemplo:
Fundamentos para el manejo de errores en PowerShell 7
1 Get-Content .\users.txt |
2 Get-ADUser -Properties mail |
3 Select-Object -Property SamAccountName,mail
La variable $Error
$Error es una variable global automática en PowerShell que siem-
pre contiene un ArrayList de cero o más objetos ErrorRecord. A
medida que se producen nuevos errores, se agregan al principio de
esta lista, por lo que siempre se puede obtener información sobre el
error más reciente utilizando $Error[0]. Los errores Terminating y
Non-Terminating se incluirán en esta lista.
Aparte de acceder a los objetos de la lista con la sintaxis de matriz,
hay otras dos tareas comunes que se realizan con la variable $Error:
Se puede comprobar cuántos errores están actualmente en la lista
utilizando la propiedad $Error.Count y puede eliminar todos los
errores de la lista con el método $Error.Clear(). Por ejemplo:
Controlando el comportamiento de los errores 10
image004.png
ErrorVariable
El parámetro común ErrorVariable proporciona una alternativa
al uso de la colección $Error anterior. A diferencia de $Error,
ErrorVariable sólo contendrá los errores que se produjeron desde
el comando que se está llamando, en lugar de tener potencialmente
errores de otras partes en la sesión PowerShell. Esto también evita
tener que borrar el contenido de $Error (con los problemas que esto
podría ocasionar).
Cuando se utiliza ErrorVariable, si desea anexar a la variable de
error en lugar de sobrescribirla, coloque un signo + delante del
Controlando el comportamiento de los errores 11
image005.png
$MaximumErrorCount
De forma predeterminada, la variable $Error sólo puede contener
un máximo de 256 errores antes de que comience a desechar los ele-
mentos más antiguos de la lista. Puede ajustar este comportamiento
modificando la variable $MaximumErrorCount.
ErrorAction y
$ErrorActionPreference
Hay varias maneras en las que puede controlar el comportamiento
de PowerShell. Las que probablemente utilizará con más frecuencia
Controlando el comportamiento de los errores 12
image006.png
Try/Catch/Finally
Las sentencias Try/ Catch/ Finally, agregadas en PowerShell 2.0,
son la forma preferida de manejar los errores Terminating. No se
pueden utilizar para manejar errores Non-Terminating, a menos
que fuerce esos errores a convertirse en errores Terminating con
ErrorAction o $ErrorActionPreference establecido en Stop.
Para usar Try/Catch/ Finally, comience con la palabra clave “Try”
seguida de un solo bloque de secuencia de comandos de PowerShell.
Después del bloque Try puede haber cualquier número de bloques
Controlando el comportamiento de los errores 14
image007.png
image008.png
Trap
Las sentencias Trap fueron el método para manejar los errores
Terminating en PowerShell 1.0. Al igual que con Try/Catch/Finally,
la instrucción Trap no tiene ningún efecto en los errores Non-
Terminating.
Trap es un poco incómodo de usar, ya que se aplica a todo el ámbito
donde se define (y los ámbitos hijos también), en lugar de tener la
lógica de manejo de errores cerca del código que podría producir
el error como cuando se utiliza Try/Catch/Finally. Para aquellos
de ustedes familiarizados con Visual Basic, Trap es parecido a “On
Error Goto”. Por eso, las sentencias Trap no ven mucho uso en los
scripts de PowerShell modernos, y no los incluí en los scripts de
prueba ni en el análisis de la Sección 3 de este libro.
En aras de mantener la integridad, he aquí un ejemplo de cómo usar
Trap:
Controlando el comportamiento de los errores 17
image009.png
La variable $LASTEXITCODE
Cuando llama a un programa ejecutable externo en lugar de un
Cmdlet, un Script o una función de PowerShell, la variable $LASTE-
XITCODE contiene automáticamente el código de salida de dicho
proceso. La mayoría de los procesos utilizan por convención un
código de salida con valor cero cuando el proceso finaliza con éxito
y un valor diferente a cero si se produce un error, pero esto no está
garantizado. Depende del desarrollador del ejecutable determinar
qué significan sus códigos de salida.
Tenga en cuenta que la variable $LASTEXITCODE sólo se establece
cuando llama a un ejecutable directamente o a través del operador
de llamadas de PowerShell (&) o del Cmdlet Invoke-Expression.
Si utiliza otro método, como Start-Process o WMI para iniciar
el ejecutable, estos tienen sus propias maneras de comunicar su
código de salida, por lo que no se afectará el valor actual de
$LASTEXITCODE.
image010.png
La variable $?
La variable $? es un valor booleano que se establece automática-
mente después de cada instrucción PowerShell o tubería (pipeline)
finaliza la ejecución. Estará establecida en True si el comando
anterior se ha ejecutado correctamente o en False si se produjo
un error. Si el comando anterior era una llamada a un exe nativo,
$? se establecerá en True si la variable $ LASTEXITCODE es
igual a cero, de lo contrario, False. Cuando el comando anterior
era una sentencia de PowerShell, $? Se establecerá en False si
se han producido errores (incluso si ErrorAction se estableció en
SilentlyContinue o Ignore).
Sólo tenga en cuenta que el valor de esta variable se restablece des-
pués de cada instrucción. Debe comprobar su valor inmediatamente
después del comando que le interesa o se sobrescribirá (probable-
mente en True). La Figura 2.8 muestra este comportamiento. La
primera vez $? se establece en False, porque el Get-Item encontró
un error. La segunda vez $? Se comprobó y se estableció en True,
porque el comando anterior finalizo correctamente. En este caso,
el comando anterior fue “$?” cuando se visualizó el valor de la
variable.
image011.png
Resumen
Esto cubre todas las técnicas que puede utilizar para controlar,
interceptar o manejar errores en un script de PowerShell. Resu-
miendo:
Interceptando errores
Non-Terminating
Comencemos hablando de errores Non-Terminating.
$_
$Error
ErrorVariable
Aquí, las cosas empiezan a complicarse. Cuando un error Termi-
nating se produce por un Cmdlet o una función y está utilizando
ErrorVariable, la variable contendrá algunos elementos inesperados
y los resultados son bastante diferentes en las distintas pruebas
realizadas:
image013.png
Conclusiones
Para errores Non-Terminating, puede utilizar $Error o ErrorVaria-
ble sin distinción. Solo debe tener presente en que el orden de los
ErrorRecords se invierte, pero usted puede fácilmente controlar eso
en su código, suponiendo que considere que eso sea un problema.
Sin embargo, tan pronto como los errores Terminating entran en
juego, ErrorVariable tiene un comportamiento muy molesto: a
veces contiene objetos de excepción en lugar de ErrorRecords, y en
otros casos, tiene uno o más objetos duplicados, todos relacionados
con el error Terminating. Si bien es posible codificar alrededor
de estas peculiaridades, realmente no parece que valga la pena el
esfuerzo cuando se puede utilizar fácilmente $_ o $Error[0].
Cuando está llamando a un comando que puede producir un error
Terminating y no maneja ese error dentro una sentencia Try/-
Catch o Trap, el comportamiento de PowerShell es inconsistente,
dependiendo de cómo se generó el error Terminating. Para lograr
Análisis de los resultados de las pruebas de manejo de errores 30
image018.png
Poniéndolo todo junto
Ahora que hemos examinado todas las herramientas de manejo de
errores e identificado algunos posibles escenarios de “engañosos”,
he aquí algunos consejos y ejemplos de cómo abordar el manejo de
errores en sus propios scripts.
image015.png
image016.png
image017.png
Tratamiento de errores
Non-Terminating
Tiendo a clasificar los comandos que pueden producir errores Non-
Terminating (Cmdlets, funciones y secuencias de comandos) de
una de tres maneras: comandos que necesitan procesar un solo
objeto de entrada, comandos que sólo pueden producir errores Non-
Terminating y comandos que podrían producir errores Terminating
o Non-Terminating. Suelo manejar cada una de estas categorías de
las siguientes formas:
Si el comando sólo necesita procesar un único objeto de entrada,
como en la figura 4.4, uso ErrorAction en Stop y manejo los errores
en un bloque Try /Catch. Debido a que el Cmdlet sólo trata con un
único objeto de entrada, el concepto de un error Non-Terminating
no es terriblemente útil de todos modos.
image018.png
image019.png
image020.png