En regardant 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 en est la raison par opposition à la suivante?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
Ou encore mieux:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Si je comprends bien, vous devez utiliser Write-Error pour les erreurs non terminantes et Throw pour les erreurs terminales, il me semble donc que vous ne devriez pas utiliser Write-Error suivi de Return. Y a-t-il une différence?
powershell
error-handling
powershell-2.0
Bill Barry
la source
la source
return
cela ne revient pas à l'appelant dans leprocess
bloc d'une fonction (avancée); à la place, il passe à l' objet d'entrée suivant dans le pipeline. En effet, c'est le scénario typique pour générer des erreurs sans fin: si le traitement d'autres objets d'entrée est toujours possible.Throw
génère une erreur de fin de script , qui n'est pas la même que erreurs de fin de déclaration déclenchées, par exemple, parGet-Item -NoSuchParameter
ou1 / 0
.Réponses:
Write-Error
doit être utilisé si vous souhaitez informer l'utilisateur d'une erreur non critique. Par défaut, il ne fait qu'imprimer un message d'erreur en texte rouge sur la console. Cela n'empêche pas un pipeline ou une boucle de se poursuivre.Throw
d'autre part produit ce que l'on appelle une erreur de fin. Si vous utilisez throw, le pipeline et / ou la boucle de courant seront terminés. En fait, toute exécution sera interrompue à moins que vous n'utilisieztrap
unetry/catch
structure ou pour gérer l'erreur de fin.Il y a une chose à noter, si vous définissez
$ErrorActionPreference
à"Stop"
et utiliserWrite-Error
il produira une erreur de terminaison .Dans le script que vous avez lié, nous trouvons ceci:
Il semble que l'auteur de cette fonction ait voulu arrêter l'exécution de cette fonction et afficher un message d'erreur à l'écran mais ne voulait pas que le script entier s'arrête de s'exécuter. L'auteur du script aurait pu utiliser
throw
mais cela signifierait que vous devrez utiliser atry/catch
lors de l'appel de la fonction.return
quittera la portée actuelle qui peut être une fonction, un script ou un bloc de script. Ceci est mieux illustré avec du code:Sortie pour les deux:
Un gotcha ici utilise
return
avecForEach-Object
. Cela n'interrompra pas le traitement comme on pourrait s'y attendre.Plus d'information:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_Returnla source
return
.La principale différence entre le applet de commande Write-Error et le mot clé throw dans PowerShell est que la première imprime simplement du texte dans le flux d'erreur standard (stderr) , tandis que la seconde met fin en fait au traitement de la commande ou de la fonction en cours d'exécution, qui est alors gérée par PowerShell en envoyant des informations sur l'erreur à la console.
Vous pouvez observer le comportement différent des deux dans les exemples que vous avez fournis:
Dans cet exemple, le
return
mot - clé a été ajouté explicitement arrêter l'exécution du script après l'envoi du message d'erreur à la console. Dans le deuxième exemple, en revanche, lereturn
mot-clé n'est pas nécessaire car la terminaison est implicitement effectuée parthrow
:la source
[System.Management.Automation.ErrorRecord]
instances, qui sont par défaut collectées dans la$Error
collection automatique ($Error[0]
contient l'erreur la plus récente). Même si vous utilisez simplementWrite-Error
avec une chaîne , cette chaîne est enveloppée dans une[System.Management.Automation.ErrorRecord]
instance.Important : il existe 2 types d'erreurs de fin , que les rubriques d'aide actuelles confondent malheureusement :
Déclaration -terminating erreurs, tel que rapporté par cmdlets dans certaines situations non récupérables et des expressions dans lesquelles une exception .NET / une erreur d'exécution PS se produit; seule l' instruction est terminée et l' exécution du script se poursuit par défaut .
écriture -terminating erreurs (plus précisément: instance d' exécution de terminaison ), soit comme déclenchée par
Throw
ou parescaladeun des autres types d'erreur parintermédiairepréférence variable action d'erreur / valeur de paramètreStop
.À moins d'être interceptés, ils terminent l'espace d'exécution actuel (thread); c'est-à-dire qu'ils terminent non seulement le script courant, mais aussi tous ses appelants, le cas échéant).
Pour une présentation complète de la gestion des erreurs de PowerShell, consultez ce problème de documentation GitHub .
Le reste de cet article se concentre sur les erreurs non terminales par rapport aux erreurs de fin d'instruction .
Pour compléter les réponses utiles existantes en mettant l'accent sur le cœur de la question: Comment choisissez si vous souhaitez signaler un Instruction- terminaison ou non terminaison erreur ?
Le rapport d'erreurs de la cmdlet contient des instructions utiles; laissez-moi tenter un résumé pragmatique :
L'idée générale derrière les erreurs sans terminaison est de permettre le traitement "tolérant aux pannes" de grands ensembles d'entrées : l'échec du traitement d'un sous - ensemble des objets d'entrée ne doit pas (par défaut) interrompre le processus - potentiellement de longue durée - dans son ensemble , vous permettant d'inspecter les erreurs et de retraiter uniquement les objets ayant échoué ultérieurement - comme indiqué via les enregistrements d'erreurs collectés dans la variable automatique
$Error
.Signalez une erreur NON-TERMINATING , si votre applet de commande / fonction avancée:
$PSCmdlet.WriteError()
pour signaler une erreur sans fin (Write-Error
malheureusement, cela ne provoque pas$?
de définition$False
dans la portée de l' appelant - voir ce problème GitHub ).$?
vous indique si la commande la plus récente a signalé au moins un erreur sans fin.$?
être$False
peut signifier que tout sous-ensemble (non vide) - d'objets d'entrée n'a pas été correctement traité, peut-être l'ensemble entier.$ErrorActionPreference
et / ou le paramètre de cmdlet commun-ErrorAction
peuvent modifier le comportement des erreurs sans fin (uniquement) en termes de comportement de sortie d'erreur et si les erreurs sans fin doivent être escaladées en erreurs de fin de script .Signaler une erreur STATEMENT-TERMINATING dans tous les autres cas .
$PSCmdlet.ThrowTerminatingError()
pour générer une erreur de fin d'instruction.Throw
mot - clé génère une erreur de fin de script qui annule l' intégralité du script (techniquement: le thread actuel ).try/catch
gestionnaire ou unetrap
instruction peut être utilisé (qui ne peut pas être utilisé avec des erreurs sans fin ), mais notez que même les erreurs de fin d' instruction par défaut n'empêchent pas le reste du script de s'exécuter. Comme dans le cas de non-terminaison des erreurs,$?
reflète$False
si l'instruction précédente a déclenché une erreur de traitement de terminaison.Malheureusement, toutes les applets de commande principales de PowerShell ne respectent pas ces règles :
Bien qu'il soit peu probable d'échouer,
New-TemporaryFile
(PSv5 +) signalerait une erreur sans fin en cas d'échec, bien qu'il n'accepte pas l'entrée de pipeline et ne produise qu'un seul objet de sortie - cela a été corrigé depuis au moins PowerShell [Core] 7.0, cependant: voir ce GitHub problème .Resume-Job
L'aide de affirme que la transmission d'un type de travail non pris en charge (tel qu'un travail créé avecStart-Job
, qui n'est pas pris en charge, carResume-Job
ne s'applique qu'aux travaux de flux de travail) provoque une erreur de fin, mais ce n'est pas le cas à partir de PSv5.1.la source
Write-Error
permet au consommateur de la fonction de supprimer le message d'erreur avec-ErrorAction SilentlyContinue
(alternativement-ea 0
). Bien quethrow
nécessite untry{...} catch {..}
Pour utiliser un essai ... attraper avec
Write-Error
:la source
Ajout à la réponse d'Andy Arismendi :
Le fait que Write-Error termine le processus ou non dépend de la
$ErrorActionPreference
paramètre.Pour les scripts non triviaux,
$ErrorActionPreference = "Stop"
est un paramètre recommandé pour échouer rapidement.(à partir de http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Cependant, cela fait
Write-Error
fin aux appels.Pour utiliser Write-Error comme commande sans fin indépendamment des autres paramètres d'environnement, vous pouvez utiliser le paramètre commun
-ErrorAction
avec la valeurContinue
:la source
Si votre lecture du code est correcte, vous avez raison. Les erreurs de terminaison doivent être utilisées
throw
, et si vous avez affaire à des types .NET, il est utile de suivre également les conventions d'exception .NET.la source