Quand dois-je utiliser Write-Error vs Throw? Erreurs terminales et non terminales
Regarder un script Get-WebFile sur PoshCode: http://poshcode.org/3226 J'ai remarqué cet étrange engin:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Quelle est la raison de ceci par opposition à:
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
ou même mieux:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
si je comprends bien, vous devriez utiliser Write-Error pour les erreurs non terminantes, et Throw pour les erreurs terminantes, donc il me semble que vous ne devriez pas utiliser Ecrire-erreur suivie d'un retour. Est-il une différence?
6 réponses
Write-Error
doit être utilisé si vous souhaitez informer l'utilisateur d'une erreur non critique. Par défaut, il suffit d'imprimer un message d'erreur en texte rouge sur la console. Cela n'empêche pas un pipeline ou une boucle de continuer. Throw
produit par contre ce qu'on appelle une erreur terminante. Si vous utilisez throw, le pipeline et/ou la boucle de courant sera terminé. En fait, toute exécution sera terminée à moins que vous n'utilisiez une structure trap
ou try/catch
pour gérer la résiliation de l'erreur.
il y a une chose à noter, Si vous mettez $ErrorActionPreference
à "Stop"
et utilisez Write-Error
il va produire une erreur finale .
dans le script que vous avez lié, nous trouvons ceci:
if ($url.Contains("http")) {
$request = [System.Net.HttpWebRequest]::Create($url)
}
else {
$URL_Format_Error = [string]"Connection protocol not specified. Recommended action: Try again using protocol (for example 'http://" + $url + "') instead. Function aborting..."
Write-Error $URL_Format_Error
return
}
Il semble que l'auteur de cette fonction voulais arrêter l'exécution de cette fonction et afficher un message d'erreur à l'écran, mais ne voulait pas le script entier pour arrêter l'exécution. L'auteur du script aurait pu utiliser throw
mais cela voudrait dire que vous auriez à utiliser un try/catch
lors de l'appel de la fonction.
return
sort de la portée actuelle qui peut être un bloc de fonctions, de scripts ou de scripts. Ceci est mieux illustré par le code:
# A foreach loop.
foreach ( $i in (1..10) ) { Write-Host $i ; if ($i -eq 5) { return } }
# A for loop.
for ($i = 1; $i -le 10; $i++) { Write-Host $i ; if ($i -eq 5) { return } }
sortie pour les deux:
1
2
3
4
5
Une chasse aux sorcières ici est d'utiliser return
avec ForEach-Object
. Il ne cassera pas le traitement comme on pourrait s'y attendre.
plus d'informations:
-
$ErrorActionPreference
: http://technet.microsoft.com/en-us/library/dd347731.aspx -
try/catch
: http://technet.microsoft.com/en-us/library/dd315350.aspx -
trap
: http://technet.microsoft.com/en-us/library/dd347548.aspx -
throw
: http://technet.microsoft.com/en-us/library/dd819510.aspx -
return
: http://technet.microsoft.com/en-us/library/dd347592.aspx
la principale différence entre le Write-Error cmdlet et le throw mot-clé dans PowerShell est que le premier tout simplement imprime un peu de texte à la flux d'erreur standard (stderr) , alors que le dernier en fait se termine le traitement de la commande en cours d'exécution ou fonction, qui est puis manipulé par PowerShell en envoyant des informations A propos de l'erreur sur la console.
Vous pouvez observer le comportement différent des deux dans les exemples que vous avez fournie:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
dans cet exemple, le mot-clé return
a été ajouté à explicitement arrêter l'exécution du script après que le message d'erreur a été envoyé à la console. Dans le second exemple, par contre, le mot-clé return
n'est pas nécessaire puisque la terminaison est implicitement faite par throw
:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Important : il y a 2 types d'erreurs de terminaison , que les sujets d'aide actuels malheureusement confondre :
-
énoncé - fin des erreurs , tel que rapporté par les cmdlets dans certaines situations non récupérables et par des expressions dans lesquelles A. Une exception net / un exécution PS l'erreur se produit; seule l'instruction est terminée, et l'exécution du script continue par défaut .
-
script - suppression des erreurs , déclenchées soit par
Throw
, soit par l'escalade de l'un des autres types d'erreurs via l'action error-preference-variable / parameter valueStop
.
À moins d'être pris, ils se terminent le fil courant de l'exécution (c'est-à-dire pas seulement le script courant, mais aussi tous ses appelants, le cas échéant).
pour un aperçu complet du traitement des erreurs de PowerShell, voir ce numéro de documentation GitHub .
le reste de ce post se concentre sur non-terminante vs. déclaration-terminante erreurs.
pour compléter les réponses utiles existantes en mettant l'accent sur le cœur de la question: Comment faire choisir si vous devez déclarer une déclaration - se terminant ou ne se terminant pas erreur ?
Applet de commande de rapport d'Erreur contient les lignes directrices utiles; permettez-moi de tenter une 1519230920" pragmatique "résumé de la 1519240920" :
l'idée générale derrière erreurs non-terminantes est de permettre le traitement "tolérant les défauts" de grands ensembles d'entrée : échec de traiter un sous-ensemble des objets d'entrée ne devrait pas (par défaut) avorter le - potentiellement long-processus en tant qu'ensemble, vous permettant d'inspecter les erreurs et ne traite que le échoué objets plus tard - tel que rapporté par les enregistrements d'erreur recueillis dans variable automatique $Error
.
-
Rapport NON-TERMINAISON erreur, si votre applet de commande / fonction avancée:
- accepte plusieurs objets d'entrée , via les paramètres d'entrée et/ou de valeur du réseau de pipeline, et
- des erreurs se produisent pour des objets d'entrée spécifiques , et
- ces les erreurs N'empêchent pas le traitement D'autres objets d'entrée en principe ( situationnellement , il peut ne rester aucun objet d'entrée et/ou des objets d'entrée antérieurs peuvent déjà avoir été traités avec succès).
- dans les fonctions avancées, utilisez
$PSCmdlet.WriteError()
pour signaler une erreur non-terminante (Write-Error
, malheureusement, ne fait pas que$?
soit défini à$False
dans le caller's portée - voir cette GitHub question ). - Manipulation un non-terminaison d'erreur:
$?
vous indique si la commande la plus récente a rapporté au moins un non-terminaison d'erreur.- ainsi,
$?
étant$False
peut signifier que tout (non vide) sous-ensemble d'objets d'entrée n'a pas été correctement traité, peut-être l'ensemble. - la variable de préférence
$ErrorActionPreference
et / ou le paramètre cmdlet commun-ErrorAction
peut modifier le comportement des erreurs non terminantes (seulement) en termes de comportement de sortie d'erreur et si les erreurs non terminantes doivent être escaladées à script -terminaisons ceux.
- ainsi,
- dans les fonctions avancées, utilisez
-
Report a STATEMENT-TERMINING error in tous les autres cas .
- notamment, si une erreur se produit dans une fonction cmdlet / advanced qui n'accepte qu'un seul ou aucun objet d'entrée et ne produit aucun ou un seul objet de sortie.
- dans les fonctions avancées, vous devez utiliser
$PSCmdlet.ThrowTerminatingError()
pour générer une erreur de terminaison de déclaration. - notez que, par contraste, le mot-clé
Throw
génère un script - erreur de terminaison qui annule le script entier . - Manipulation une déclaration de terminaison de l'erreur: Un
try/catch
du gestionnaire ou dutrap
déclaration peut être utilisé ( ne peut pas non-terminaison erreurs), mais note que même les déclaration terminaison d'erreurs par défaut n'empêche pas le reste de la script d'exécution. Comme pour les erreurs non terminantes ,$?
reflète$False
si l'instruction précédente a déclenché une erreur de terminaison de l'instruction.
- dans les fonctions avancées, vous devez utiliser
- notamment, si une erreur se produit dans une fonction cmdlet / advanced qui n'accepte qu'un seul ou aucun objet d'entrée et ne produit aucun ou un seul objet de sortie.
malheureusement, tous les cmdlets du noyau de PowerShell ne suivent pas ces règles :
-
bien que peu probable,
New-TemporaryFile
(PSv5+) signalerait une erreur non terminante si elle échouait, malgré le fait qu'elle n'acceptait pas l'entrée du pipeline et produisait seulement un objet de sortie-cela changera probablement dans v6, cependant: voir ce numéro GitHub . -
Resume-Job
's help prétend que passer un type d'emploi non supporté (tel qu'un emploi créé avecStart-Job
, qui n'est pas supporté, parce queResume-Job
ne s'applique qu'à workflow jobs) provoque une erreur de terminaison, mais ce n'est pas vrai à partir de PSv5.1.
Write-Error
permet au consommateur de la fonction de supprimer le message d'erreur avec -ErrorAction SilentlyContinue
(alternativement -ea 0
). Alors que throw
nécessite un try{...} catch {..}
À l'utilisation de l'essayer...catch avec Write-Error
:
try {
SomeFunction -ErrorAction Stop
}
catch {
DoSomething
}
ajout à réponse D'Andy Arismendi :
si Write-Error met fin au processus ou non dépend du paramètre $ErrorActionPreference
.
pour les scripts non-triviaux, $ErrorActionPreference = "Stop"
est un paramètre recommandé pour échouer rapidement.
"PowerShell comportement par défaut à l'égard d'erreurs, ce qui est à continuez sur erreur ...feels very VB6 "On Error Resume Next" - ish"
(de http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem / )
cependant, il fait des appels Write-Error
se terminant.
pour utiliser Write-Error comme commande non-terminante indépendamment des autres paramètres d'environnement, vous pouvez utiliser paramètre commun -ErrorAction
avec la valeur Continue
:
Write-Error "Error Message" -ErrorAction:Continue
Si votre lecture du code est correcte, alors vous avez raison. Les erreurs de terminaison doivent utiliser throw
, et si vous avez affaire à des types .NET, alors il est utile de suivre également les conventions d'exception .NET.