En regardant un script Get-WebFile sur PoshCode, http://poshcode.org/3226 , j'ai remarqué cet inconvénient étrange:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Quelle est la raison de ceci par opposition à ce qui suit?
$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 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?
_Write-Error
_ doit être utilisé si vous souhaitez informer l'utilisateur d'une erreur non critique. Par défaut, tout ce qu’il fait est 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 que l’on appelle une erreur de terminaison. Si vous utilisez throw, le pipeline et/ou la boucle de courant seront terminés. En fait, toute exécution sera terminée sauf si vous utilisez une structure trap
ou _try/catch
_ pour traiter l'erreur de terminaison.
Il y a une chose à noter, si vous définissez $ErrorActionPreference
_ SUR _"Stop"
et utilisez _Write-Error
_, ce sera produit une erreur de terminaison .
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 ait voulu arrêter l'exécution de cette fonction et afficher un message d'erreur à l'écran, mais ne souhaitait pas que le script complet cesse de s'exécuter. L'auteur du script aurait pu utiliser throw
, mais cela signifierait que vous devrez utiliser un _try/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 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
_
Il faut utiliser return
avec _ForEach-Object
_. Le traitement ne sera pas interrompu comme on pourrait s'y attendre.
Plus d'information:
$ErrorActionPreference
_: about_Parference_Variablestry/catch
_: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_ReturnLa principale différence entre la cmdlet Write-Error et le mot clé throw dans PowerShell est que l'ancien est simplement affiche du texte dans le flux d'erreur standard (stderr) , alors que ce dernier réellement termine le traitement de la commande ou de la fonction en cours d'exécution, qui est alors géré par PowerShell par envoi d'informations sur l'erreur à la console.
Vous pouvez observer le comportement différent des deux dans les exemples que vous avez fournis:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Dans cet exemple, le mot clé return
a été ajouté à explicitement pour arrêter l'exécution du script après l'envoi du message d'erreur à la console. Dans le deuxième exemple, en revanche, le mot clé return
n'est pas nécessaire, car la terminaison est implicitement effectuée 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 rubriques d'aide actuelles malheureusement associent :
instruction - erreurs de terminaison , telles qu'elles sont signalées par les applets de commande dans certaines situations non récupérables et par les expressions dans lesquelles a. 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 .
script - erreurs de terminaison , déclenchées soit par Throw
, soit en escaladant l'une des autres erreurs types via error-action variable de préférence/valeur de paramètre Stop
.
Sauf s’ils sont attrapés, ils mettent fin au thread d’exécution en cours (c’est-à-dire non seulement au script actuel, mais également à tous ses appelants, le cas échéant).
Pour un aperçu complet de la gestion des erreurs de PowerShell, voir problème de documentation GitHub .
Le reste de cet article se concentre sur les erreurs non-terminantes par rapport aux instructions .
Pour compléter les réponses utiles existantes en mettant l’accent sur le cœur de la question: Comment choisissez-vous de signaler une déclaration - erreur de terminaison ou ?
Rapport d'erreurs de la cmdlet contient des instructions utiles; laissez-moi essayer un résumé pragmatique :
L'idée générale derrière les erreurs non terminales est d'autoriser 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 long - dans son ensemble, ce qui vous permet d’inspecter les erreurs et de retraiter uniquement le objets en échec plus tard - tels que signalés via les enregistrements d'erreur collectés dans la variable automatique $Error
.
Signalez une erreur NON TERMINANTE , si votre applet de commande/fonction avancée:
$PSCmdlet.WriteError()
pour signaler une erreur non-terminante (Write-Error
, malheureusement, ne provoque pas le paramétrage de $?
sur $False
dans le portée de l'appelant - voir ce problème de GitHub ).$?
vous indique si la commande la plus récente a signalé au moins une erreur non-terminante. ____.]$?
étant $False
peut signifier que un sous-ensemble (non vide) d'objets d'entrée n'a pas été traité correctement, éventuellement l'ensemble.$ErrorActionPreference
et/ou le paramètre d'applet de commande commun -ErrorAction
peuvent modifier le comportement des erreurs non-terminantes (uniquement) en termes de comportement de sortie et indiquer si les erreurs non-terminales doivent être escaladées . ) script - en terminant.Signalez une erreur STATEMENT-TERMINATING dans dans tous les autres cas .
$PSCmdlet.ThrowTerminatingError()
pour générer une erreur mettant fin aux instructions.Throw
génère un ( script - erreur de fin qui annule le script complet (techniquement: le courant fil ).try/catch
ou une instruction trap
peut être utilisé (ce qui ne peut pas être utilisé avec erreurs non-terminantes ), mais notez que même instruction - les erreurs finales par défaut n'empêchent pas le reste du script de s'exécuter. Comme pour les erreurs non terminantes , $?
reflète $False
si l'instruction précédente a déclenché une erreur mettant fin à l'instruction.Malheureusement, toutes les applets de commande principales de PowerShell ne sont pas soumises à ces règles :
Bien que cela soit peu probable, New-TemporaryFile
(PSv5 +) signalerait une erreur non-terminante si elle échouait, même si elle n'acceptait pas l'entrée de pipeline et ne produisait qu'un objet de sortie - cela changerait probablement dans la v6 cependant: voir ce numéro de GitHub .
L'aide de Resume-Job
déclare que le transfert d'un type de travail non pris en charge (tel qu'un travail créé avec Start-Job
, qui n'est pas pris en charge, car Resume-Job
s'applique uniquement au flux de travail ) provoque une erreur de terminaison, mais ce n'est pas vrai à partir de PSv5.1.
Write-Error
permet à l'utilisateur de la fonction de supprimer le message d'erreur avec -ErrorAction SilentlyContinue
(ou bien -ea 0
). Bien que throw
nécessite un try{...} catch {..}
Pour utiliser un essai ... attraper avec Write-Error
:
try {
SomeFunction -ErrorAction Stop
}
catch {
DoSomething
}
Ajout à réponse de Andy Arismendi :
Que Write-Error termine ou non le processus dépend du paramètre $ErrorActionPreference
.
Pour les scripts non triviaux, $ErrorActionPreference = "Stop"
est un paramètre recommandé pour échouer rapidement.
"Le comportement par défaut de PowerShell en ce qui concerne les erreurs, qui doivent continuer sur les erreurs ... semble très VB6" Sur erreur, Reprendre suivant "-ish"
(de http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Cependant, les appels Write-Error
se terminent.
Pour utiliser Write-Error en tant que commande qui ne se termine pas, quels que soient les 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 utilisez des types .NET, il est utile de suivre également les conventions d'exception .NET.