180 votes

Quand dois-je utiliser Write-Error ou Throw ? Erreurs terminales ou non terminales

Je regarde un Get-WebFile script sur PoshCode, http://poshcode.org/3226 j'ai remarqué cet engin étrange pour moi :

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

Quelle en est la raison par rapport à ce qui suit ?

$URL_Format_Error = [string]"..."
Throw $URL_Format_Error

Ou encore mieux :

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

Si j'ai bien compris, vous devez utiliser Write-Error pour les erreurs qui ne se terminent pas, et Throw pour les erreurs qui se terminent. Il me semble donc que vous ne devez pas utiliser Write-Error suivi de Return. Y a-t-il une différence ?

4 votes

Qu'est-ce que tu veux dire ? Si Write_error permet au script de continuer, il est très compréhensible d'avoir une déclaration de retour après Write-Error. L'erreur a été écrite et vous revenez au code qui a appelé la fonction en premier lieu. Puisque Throw est destinée à mettre fin aux erreurs, elle se terminera automatiquement, de sorte qu'une déclaration de retour dans une déclaration throw est inutile.

1 votes

@Gisli : Il est important de noter que return hace no retourne à l'appelant dans le process d'une fonction (avancée) ; au lieu de cela, il passe au bloc objet d'entrée suivant en cours de réalisation. En effet, il s'agit du scénario typique de génération d'erreurs de non-terminaison : si le traitement d'autres objets d'entrée est encore possible.

1 votes

Notez que Throw génère un script -qui n'est pas la même que l'erreur de terminaison. déclaration -les erreurs de terminaison déclenchées, par exemple, par Get-Item -NoSuchParameter o 1 / 0 .

225voto

Andy Arismendi Points 16501

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 rouge sur la console. Elle n'empêche pas un pipeline ou une boucle de continuer. Throw d'autre part, produit ce que l'on appelle une erreur de terminaison. Si vous utilisez throw, le pipeline et/ou la boucle en cours seront terminés. En fait, toute l'exécution sera interrompue, à moins que vous n'utilisiez un paramètre de type trap ou un try/catch pour gérer l'erreur de terminaison.

Il y a une chose à noter, si vous définissez $ErrorActionPreference a "Stop" et utiliser Write-Error elle le fera produire 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 voulait arrêter l'exécution de cette fonction et afficher un message d'erreur à l'écran mais ne voulait pas que l'ensemble du script arrête de s'exécuter. L'auteur du script aurait pu utiliser throw cependant, cela signifierait que vous devriez utiliser une 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 script. Ceci est mieux illustré avec du 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

Un problème ici est d'utiliser return con ForEach-Object . Il ne brisera pas la transformation comme on pourrait s'y attendre.

Plus d'informations :

0 votes

Ok, donc Throw arrêtera tout, Write-Error + return arrêtera seulement la fonction courante.

0 votes

@BillBarry J'ai un peu mis à jour ma réponse avec une explication de return .

2 votes

Qu'en est-il de Write-Error suivi de exit(1) pour assurer le retour du code d'erreur approprié au système d'exploitation ? Est-ce que cela est toujours approprié ?

21voto

Enrico Campidoglio Points 17157

La principale différence entre les Erreur d'écriture et le lancez dans PowerShell est que le premier est tout simplement imprime du texte à la flux d'erreur standard (stderr) alors que ce dernier est en fait met fin à le traitement de la commande ou de la fonction en cours, qui est puis 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 :

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

Dans cet exemple, le return Le 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, par contre, le script return n'est pas nécessaire puisque la terminaison est implicitement effectuée par la fonction throw :

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

2 votes

Si vous avez $ErrorActionPreference = "Stop", Write-Error mettra également fin au processus.

4 votes

Bonne info, mais si le flux d'erreur de PowerShell est analogues au basé sur le texte stderr dans d'autres shells, comme tous les flux PowerShell il contient objets à savoir [System.Management.Automation.ErrorRecord] qui sont par défaut collectées dans la base de données automatique des $Error collection ( $Error[0] contient l'erreur la plus récente). Même si vous utilisez simplement Write-Error avec un chaîne de caractères cette chaîne est enveloppée dans un [System.Management.Automation.ErrorRecord] instance.

12voto

Michael Freidgeim Points 4002

Ajout à La réponse d'Andy Arismendi :

Si Erreur d'écriture met fin ou non au processus dépend de la $ErrorActionPreference réglage.

Pour les scripts non triviaux, $ErrorActionPreference = "Stop" est un réglage recommandé pour échouer rapidement.

"Le comportement par défaut de PowerShell en ce qui concerne les erreurs, qui est de continuer sur l'erreur ... semble très VB6 "On Error Resume Next"-ish".

(de http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )

Cependant, il fait Write-Error appels terminés.

Pour utiliser Erreur d'écriture comme une commande non terminale indépendamment des autres paramètres d'environnement, vous pouvez utiliser paramètre commun -ErrorAction avec valeur Continue :

 Write-Error "Error Message" -ErrorAction:Continue

8voto

Rynant Points 6575

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 {..}

Pour utiliser un try...catch avec Write-Error :

try {
    SomeFunction -ErrorAction Stop
}
catch {
    DoSomething
}

0 votes

Pourquoi faut-il appeler Write-Error, si l'on veut supprimer le message d'erreur ?

0voto

yzorg Points 1139

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, il est utile de suivre également les conventions d'exception .NET.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X