Al mirar un script Get-WebFile en PoshCode, http://poshcode.org/3226 , noté este artilugio extraño para mí:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
¿Cuál es la razón de esto en lugar de lo siguiente?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
O mejor:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Según tengo entendido, debe usar Write-Error para errores que no terminan, y Throw para errores de terminación, por lo que me parece que no debe usar Write-Error seguido de Return. ¿Hay una diferencia?
powershell
error-handling
powershell-2.0
Bill Barry
fuente
fuente
return
no no regresar a la llamada en elprocess
bloque de una función (avanzado); en su lugar, pasa al siguiente objeto de entrada en la tubería. De hecho, este es el escenario típico para generar errores sin terminación: si aún es posible procesar más objetos de entrada.Throw
genera un error de terminación de secuencia de comandos , que no es lo mismo que la declaración de errores de terminación activados, por ejemplo, porGet-Item -NoSuchParameter
o1 / 0
.Respuestas:
Write-Error
debe usarse si desea informar al usuario de un error no crítico. Por defecto, todo lo que hace es imprimir un mensaje de error en texto rojo en la consola. No detiene una tubería o un bucle de continuar.Throw
por otro lado produce lo que se llama un error de terminación. Si usa throw, la tubería y / o el bucle actual finalizarán. De hecho, toda la ejecución se terminará a menos que use unatrap
o unatry/catch
estructura para manejar el error de terminación.Hay una cosa a la nota, si se establece
$ErrorActionPreference
a"Stop"
y utilizaWrite-Error
se producirá un error de terminación .En el script al que se vinculó, encontramos esto:
Parece que el autor de esa función quería detener la ejecución de esa función y mostrar un mensaje de error en la pantalla, pero no quería que todo el script dejara de ejecutarse. El autor del script podría haber utilizado,
throw
sin embargo, significaría que tendría que usar untry/catch
al llamar a la función.return
saldrá del ámbito actual que puede ser una función, secuencia de comandos o bloque de secuencia de comandos. Esto se ilustra mejor con el código:Salida para ambos:
Un gotcha aquí está usando
return
conForEach-Object
. No interrumpirá el procesamiento como cabría esperar.Más información:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_ Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_Returnfuente
return
.La principal diferencia entre el cmdlet Write-Error y la palabra clave throw en PowerShell es que el primero simplemente imprime algo de texto en el flujo de error estándar (stderr) , mientras que el segundo termina el procesamiento del comando o función en ejecución, que luego se maneja por PowerShell enviando información sobre el error a la consola.
Puede observar el comportamiento diferente de los dos en los ejemplos que proporcionó:
En este ejemplo, la
return
palabra clave se ha agregado para detener explícitamente la ejecución de la secuencia de comandos después de enviar el mensaje de error a la consola. En el segundo ejemplo, por otro lado, lareturn
palabra clave no es necesaria ya que la terminación se realiza implícitamente porthrow
:fuente
[System.Management.Automation.ErrorRecord]
, instancias, que se recopilan de forma predeterminada en la$Error
colección automática ($Error[0]
contiene el error más reciente). Incluso si solo lo usaWrite-Error
con una cadena , esa cadena se envuelve en una[System.Management.Automation.ErrorRecord]
instancia.Importante : Hay 2 tipos de errores de terminación , que desafortunadamente los temas de ayuda actuales combinan :
errores de terminación de instrucciones , según lo informado por cmdlets en ciertas situaciones no recuperables y por expresiones en las que se produce una excepción .NET / un error de tiempo de ejecución de PS; solo la declaración finaliza y la ejecución del script continúa de manera predeterminada .
guión -terminating errores (más exactamente: espacio de ejecución de terminación ), ya sea como provocadas por
Throw
o por la escalada de uno de los otros tipos de error a través error-acción valor de preferencia variable / parámetroStop
.A menos que sean capturados, terminan el espacio de ejecución actual (hilo); es decir, terminan no solo el script actual, sino también todos sus llamantes, si corresponde).
Para obtener una descripción completa del manejo de errores de PowerShell, consulte este problema de documentación de GitHub .
El resto de esta publicación se centra en los errores que no terminan frente a los que terminan las declaraciones .
Para complementar las respuestas útiles existentes con un enfoque en el núcleo de la pregunta: ¿Cómo elige si desea informar un error de terminación o no terminación de la declaración ?
El Informe de errores de cmdlet contiene pautas útiles; déjame intentar un resumen pragmático :
La idea general detrás de los errores que no terminan es permitir el procesamiento "tolerante a fallas" de grandes conjuntos de entrada : la falla al procesar un subconjunto de los objetos de entrada no debe (por defecto) abortar el proceso en su conjunto , potencialmente de larga duración , lo que le permite inspeccionar los errores y reprocesar solo los objetos fallidos más adelante , como se informa a través de los registros de errores recopilados en la variable automática
$Error
.Informe un error NO TERMINATORIO , si su cmdlet / función avanzada:
$PSCmdlet.WriteError()
para informar un error que no termina (Write-Error
desafortunadamente, no causa$?
que se establezca$False
en el alcance de la persona que llama ; consulte este problema de GitHub ).$?
le indica si el comando más reciente informó al menos un error sin terminación.$?
ser$False
puede significar que cualquier subconjunto (no vacío) de objetos de entrada no se procesó correctamente, posiblemente todo el conjunto.$ErrorActionPreference
y / o el parámetro de cmdlet común-ErrorAction
pueden modificar el comportamiento de los errores sin terminación (solo) en términos de comportamiento de salida de error y si los errores sin terminación deben escalarse a los que terminan la secuencia de comandos .Informe un error de TERMINACIÓN DE DECLARACIÓN en todos los demás casos .
$PSCmdlet.ThrowTerminatingError()
para generar un error de finalización de sentencia.Throw
palabra clave genera un error de terminación de script que aborta todo el script (técnicamente: el hilo actual ).try/catch
controlador o unatrap
declaración (que no se puede usar con errores que no terminan ), pero tenga en cuenta que incluso los errores de terminación de declaración por defecto no impiden que se ejecute el resto del script. Al igual que con los errores que no terminan ,$?
refleja$False
si la declaración anterior activó un error de terminación de la declaración.Lamentablemente, no todos los cmdlets principales de PowerShell cumplen con estas reglas :
Si bien es poco probable que falle,
New-TemporaryFile
(PSv5 +) informaría un error que no termina si falla, a pesar de no aceptar la entrada de la tubería y solo producir un objeto de salida; sin embargo, esto se ha corregido al menos desde PowerShell [Core] 7.0: vea este GitHub cuestión .Resume-Job
La ayuda afirma que pasar un tipo de trabajo no admitido (como un trabajo creado conStart-Job
, que no es compatible, porqueResume-Job
solo se aplica a los trabajos de flujo de trabajo) provoca un error de finalización, pero eso no es cierto a partir de PSv5.1.fuente
Write-Error
permite al consumidor de la función suprimir el mensaje de error con-ErrorAction SilentlyContinue
(alternativamente-ea 0
). Si bienthrow
requiere untry{...} catch {..}
Para usar un intento ... captura con
Write-Error
:fuente
Además de la respuesta de Andy Arismendi :
Si Write-Error finaliza el proceso o no depende de la
$ErrorActionPreference
configuración.Para scripts no triviales,
$ErrorActionPreference = "Stop"
es una configuración recomendada para fallar rápidamente.(de http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Sin embargo, hace que las
Write-Error
llamadas terminen.Para usar Write-Error como un comando que no termina, independientemente de otras configuraciones del entorno, puede usar un parámetro común
-ErrorAction
con valorContinue
:fuente
Si su lectura del código es correcta, entonces está en lo correcto. Deben usarse los errores de terminación
throw
, y si se trata de tipos .NET, también es útil seguir las convenciones de excepción .NET.fuente