J'essaie de maîtriser PowerShell. Une chose simple que je peine à comprendre, c'est qu'il semble y avoir un certain nombre de façons différentes d'envoyer des messages. Que dois-je utiliser et quelle est la différence et existe-t-il un moyen conventionnel de le faire?
Je remarque aussi que si j'utilise:
write-Host "count=" + $count
Le +
est inclus dans la sortie. Pourquoi ça? L'expression ne devrait-elle pas être évaluée pour produire une seule chaîne concaténée avant d'être écrite?
Write-Output
doit être utilisé lorsque vous souhaitez envoyer des données dans la ligne de conduite, mais que vous ne voulez pas nécessairement les afficher à l'écran. Le pipeline finira par l'écrire dans out-default
si rien d'autre ne l'utilise en premier. Write-Host
doit être utilisé lorsque vous voulez faire le contraire. [console]::WriteLine
est essentiellement ce que Write-Host
fait en coulisse.
Exécutez ce code de démonstration et examinez le résultat.
function Test-Output {
Write-Output "Hello World"
}
function Test-Output2 {
Write-Host "Hello World" -foreground Green
}
function Receive-Output {
process { Write-Host $_ -foreground Yellow }
}
#Output piped to another function, not displayed in first.
Test-Output | Receive-Output
#Output not piped to 2nd function, only displayed in first.
Test-Output2 | Receive-Output
#Pipeline sends to Out-Default at the end.
Test-Output
Vous devez placer l'opération de concaténation entre parenthèses afin que PowerShell traite la concaténation avant de marquer la liste de paramètres pour Write-Host
.
write-Host ("count=" + $count)
BTW - Regardez cette vidéo de Jeffrey Snover expliquant le fonctionnement du pipeline. À l'époque où j'ai commencé à apprendre PowerShell, je trouvais que c'était l'explication la plus utile du fonctionnement du pipeline.
Outre ce que Andy a mentionné, une autre différence pourrait être importante: write-Host écrit directement sur l'hôte et ne renvoie rien, ce qui signifie que vous ne pouvez pas rediriger la sortie, par exemple, vers un fichier.
---- script a.ps1 ----
write-Host "hello"
Maintenant, lancez PowerShell:
PS> .\a.ps1 > someFile.txt
hello
PS> type someFile.txt
PS>
Comme on le voit, vous ne pouvez pas les rediriger dans un fichier. C'est peut-être surprenant pour quelqu'un qui ne fait pas attention.
Mais si vous utilisez à la place l'écriture en sortie, la redirection fonctionnera comme prévu.
Voici un autre moyen d'accomplir l'équivalent de Write-Output. Il suffit de mettre votre chaîne entre guillemets:
"count=$count"
Vous pouvez vous assurer que cela fonctionne de la même manière que Write-Output en exécutant ce test:
"blah blah" > out.txt
Write-Output "blah blah" > out.txt
Write-Host "blah blah" > out.txt
Les deux premiers produiront "bla bla" dans out.txt, mais pas le troisième.
"help Write-Output" donne un indice de ce comportement:
Cette cmdlet est généralement utilisée dans les scripts pour afficher des chaînes et autres objets sur la console. Cependant, parce que le comportement par défaut est to afficher les objets à la fin d'un pipeline, ce n'est généralement pas nécessaire d'utiliser l'applet de commande.
Dans ce cas, la chaîne elle-même "count = $ count" est l'objet situé à la fin d'un pipeline et est affichée.
D'après mes tests, Write-Output et [Console] :: WriteLine () fonctionnent beaucoup mieux que Write-Host.
En fonction de la quantité de texte que vous devez écrire, cela peut être important.
Ci-dessous si le résultat de 5 tests chacun pour Write-Host, Write-Output et [Console] :: WriteLine ().
Dans mon expérience limitée, j'ai constaté que lorsque je travaillais avec des données du monde réel, je devais abandonner les applets de commande et aller directement aux commandes de niveau inférieur pour obtenir des performances décentes dans mes scripts.
measure-command {$count = 0; while ($count -lt 1000) { Write-Host "hello"; $count++ }}
1312ms
1651ms
1909ms
1685ms
1788ms
measure-command { $count = 0; while ($count -lt 1000) { Write-Output "hello"; $count++ }}
97ms
105ms
94ms
105ms
98ms
measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}
158ms
105ms
124ms
99ms
95ms
Pour les utilisations de Write-Host
, PSScriptAnalyzer
génère le diagnostic suivant:
Évitez d'utiliser
Write-Host
car il pourrait ne pas fonctionner sur tous les hôtes, ne fonctionne pas lorsqu'il n'y a pas d'hôte et (avant PS 5.0) ne peut pas être supprimé, capturé ou redirigé. Utilisez plutôtWrite-Output
,Write-Verbose
ouWrite-Information
.
Voir le documentation derrière cette règle pour plus d'informations. Extraits pour la postérité:
L'utilisation de
Write-Host
est fortement déconseillée sauf si vous utilisez des commandes avec le verbeShow
. Le verbeShow
signifie explicitement "montrer à l'écran, sans autre possibilité".Les commandes avec le verbe
Show
n'ont pas cette vérification appliquée.
Jeffrey Snover a publié un article sur le blog Write-Host considéré comme préjudiciable dans lequel il affirme que Write-Host est presque toujours la mauvaise chose à faire, car il interfère avec l'automatisation et fournit plus d'explications derrière le diagnostic est un bon résumé.
Concernant [Console] :: WriteLine () - vous devriez l’utiliser si vous voulez utiliser des pipelines dans CMD (pas dans Powershell). Supposons que votre ps1 diffuse de nombreuses données sur stdout, et qu'un autre utilitaire les consomme/les transforme. Si vous utilisez Write-Host dans le script, le processus sera beaucoup plus lent.