Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should Write-Host still be avoided? #1118

Open
jaredmmartin opened this issue Dec 26, 2018 · 15 comments
Open

Should Write-Host still be avoided? #1118

jaredmmartin opened this issue Dec 26, 2018 · 15 comments

Comments

@jaredmmartin
Copy link

It's always been recommended to avoid using Write-Host because it outputs only to the console and not to any of the standard output streams. As of PowerShell 5.0, Write-Host is just a wrapper for Write-Information and thus outputs to the standard output streams similar to the other Write-* cmdlets.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-host?view=powershell-6

Should the use of Write-Host still be flagged as something to be avoided? Is it possible to implement a rule that only flags the use of Write-Host if the computer is running a version of PowerShell earlier than 5.0?

Thanks!

@bergmeister
Copy link
Collaborator

We could consider running the rule only on version 3 and 4 using e.g. condition compilation of the rule, so yes version specific rules are possible.
Whilst the technical problem in PowerShell has been solved, Write-Host unfortunately still gets misused and Write-Verbose/Write-Output are 2 good alternatives that the rule educates about in its help, this would be the only last remaining reason to still use the rule. However, given the user feedback about this rule in general you are probably right to not warn about Write-Host on ps version 5+ any more

@jaredmmartin
Copy link
Author

Cool. I agree that it probably still gets misused a lot. The big benefit of Write-Host is that it supports output in different colors which can be a valuable way to display different types of information with scripts that people will be interacting with/running manually.

I see the file for this rule in the repo:
https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Rules/AvoidUsingWriteHost.cs

I assume the change would be right around the section that skips the rule for cmdlets that start with the Show verb? Something like also skipping the rule if the PS version is <5? I'm not too familiar with C, but I'm happy to take a shot at modifying the rule. :)

@SeeminglyScience
Copy link
Collaborator

As of PowerShell 5.0, Write-Host is just a wrapper for Write-Information and thus outputs to the standard output streams similar to the other Write-* cmdlets.

It's worth noting that Write-Host doesn't just write to the information stream like Write-Information does. It writes to the stream with a specific tag that forces the message to ignore $InformationPreference and the InformationAction common parameter. The only way to suppress an information record created by Write-Host is to use a sort of obscure redirection syntax like Invoke-CommandThatWritesHost 6> $null.

It's no longer impossible to suppress, but I still wouldn't recommend using it outside of very specific scenarios.

We could consider running the rule only on version 3 and 4 using e.g. condition compilation of the rule, so yes version specific rules are possible.

Something to keep in mind with that, it's not uncommon to develop a script on a machine with PSv5+, while targeting an older version.

@jkavanagh58
Copy link

      We could consider running the rule only on version 3 and 4 using e.g. condition compilation of the rule, so yes version specific rules are possible.

Whilst the technical problem in PowerShell has been solved, Write-Host unfortunately still gets misused and Write-Verbose/Write-Output are 2 good alternatives that the rule educates about in its help, this would be the only last remaining reason to still use the rule. However, given the user feedback about this rule in general you are probably right to not warn about Write-Host on ps version 5+ any more

I have also gone to write-information as well.

@bergmeister
Copy link
Collaborator

Ok, so concluding, is it the best to just add more information to the documentation. Would everyone be happy with that?

@roberttoups
Copy link

What about analyzing if Write-Host is using -ForegroundColor or -BackgroundColor and the cmdlet is not used in the context of a function? There are legitimate reasons to provide feedback to an end-user with color in a script. It is unfortunate that the verb is wrong as Show-Host would be more appropriate. Write-Information does not have -ForegroundColor or -BackgroundColor arguments.

@SeeminglyScience
Copy link
Collaborator

@roberttoups Most of the cases that the rule is specifically designed to advise against include color. The idea is that generally what is written to host isn't actually necessary by default. If there is a problem, write an error, otherwise either do nothing or write output. If you want to include extra information, write it to an optional stream like information or verbose.

It's not never useful, but in the few cases were it's the best pattern to use, suppressing the warning works great.

It is unfortunate that the verb is wrong as Show-Host would be more appropriate. Write-Information does not have -ForegroundColor or -BackgroundColor arguments.

The rule doesn't warn when the parent function has the Show verb because the verb is supposed to be used mainly for interactive and purely visual commands. That's the type of use case where most would agree that Write-Host is advisable. If the cmdlet itself were named Show-Host then a different verb would likely need to be picked for the rule, but it wouldn't actually change anything about why it's not recommended.

@roberttoups
Copy link

roberttoups commented May 16, 2020

Thank you for the prompt and detailed feedback. While I disagree with sentiment that color lacks value to an end-user as a means of feedback and should be discouraged, I understand your statement in regards to errors or problems completely. I agree that information should stored in a stream.

Not everything I wish to convey is a problem or error and Write-Information and Write-Verbose are very rigid means of visual communication in realtime compared to Write-Host. Write-Verbose, itself, is a very inelegant means of communication to an end-user with its unavoidable and garish "VERBOSE:" prefix and yellow text. However, I will retract my request and live with the warnings in regards to Write-Host as I understand the stance of the enforced rule as you stated.

Is there a reason that Write-Progress is not treated with the same disdain as Write-Host? It does not provide information to any stream that I am able to discern in my testing and utilizes the same verb.

Set-StrictMode -Version 'Latest'
$InformationPreference = 'Continue'
$VerbosePreference = 'Continue'
Start-Transcript -Path (Join-Path -Path '.' -ChildPath 'Test-Output.txt')
for ($i = 0; $i -le 100; $i++) {
  Write-Progress -PercentComplete $i -Activity 'Progress Bar' -Status "Incremented Number: $i"
  Write-Verbose -Message "Verbose: $i"
  Write-Information -MessageData "Information: $i"
  Start-Sleep -Milliseconds 100
}
Write-Progress -Activity 'Incrementing Number' -Status 'Done' -Completed
Stop-Transcript

@rjmholt
Copy link
Contributor

rjmholt commented May 16, 2020

While I disagree with sentiment that color lacks value to an end-user as a means of feedback and should be discouraged

I get the impression that this isn't @SeeminglyScience's intended inference. Colour is perfectly valuable, but no matter what colour you use, Write-Host bypasses layers in PowerShell designed to provide integrations and configurability. Rather than work with PowerShell's own stream concepts, it goes straight to stdout. If another script calls that script, or it gets called in a non-interactive context, it's much harder to manipulate the Write-Host output than it is any other Write-* output. The point is that the end-user isn't always where you think they'll be, and Write-Host makes it harder to do the plumbing or programmatically examine values after they've been emitted.

Is there a reason that Write-Progress is not treated with the same disdain as Write-Host

One point is that Write-Progress is also configurable with $ProgressPreference, so it's fairly easy to suppress. But I think the big reason for having a rule for Write-Host is that it's much more commonly used and abused; needing to print something is a very basic and common scenario, and one that PowerShell has a more nuanced approach to. New users reach for Write-Host first and have to be trained to use other things, because better substitutes exist. Write-Progress on the other hand is something users tend to understand a bit more about PowerShell before coming to, and there's not a better command to recommend anyway.

and live with the warnings in regards to Write-Host as I understand the stance of the enforced rule as you stated.

There's no need to endure the warnings though! PSSA has some defaults, but they're not dictums. A configuration file or an invocation with -ExcludeRule 'AvoidUsingWriteHost' means this rule's opinion won't be foisted upon you.

@SeeminglyScience
Copy link
Collaborator

Not everything I wish to convey is a problem or error and Write-Information and Write-Verbose are very rigid means of visual communication in realtime compared to Write-Host. Write-Verbose, itself, is a very inelegant means of communication to an end-user with its unavoidable and garish "VERBOSE:" prefix and yellow text.

So it really depends on what you're doing. If you're writing a "controller script" that is only ever gonna be someone double clicking a bat file that invokes the script, sure go wild. If you're writing a reusable command though, that's when it starts to be a bit noisy. For instance, imagine if Get-ChildItem wrote "Looking for files in directory x" in green every time it was invoked. If every command wrote to host, the screen would sort of be a mess. If folks develop the habit of relying on Write-Host, when they start writing code for other folks to consume that becomes a problem.

Basically if anything is ever going to call your script that isn't a user in a console window specifically launched to run your script, it's probably better to keep your output clean.

Is there a reason that Write-Progress is not treated with the same disdain as Write-Host? It does not provide information to any stream that I am able to discern in my testing and utilizes the same verb.

It's not permanent, it's cleared from the screen between prompts and when the Completed record is written. Plus the excellent points just made by @rjmholt.

@SeeminglyScience
Copy link
Collaborator

Also

While I disagree with sentiment that color lacks value to an end-user as a means of feedback and should be discouraged

Adding onto what @rjmholt said, I'm very excitedly awaiting the arrival of color in the formatting system. Color is fantastic, PowerShell just doesn't support it well yet.

@roberttoups
Copy link

Thanks for all the feedback. I appreciate the time and effort in educating me on the mindset behind the rule and some of the under the hood PowerShell information. Write-Output with color would be amazing.

@SeeminglyScience
Copy link
Collaborator

Write-Output with color would be amazing.

Support would likely come from the formatting system, not Write-Output directly. For more information check out PowerShell/PowerShell#11890

@roberttoups
Copy link

Interestingly, I just attended a PowerShell Meetup hosted by Doug Finke which had James Brundage's discussion of PowerShell Formatting and his Module EZout https://github.com/StartAutomating/EZOut. He demonstrated color in output using formatting.

@ay-azara
Copy link

ay-azara commented Nov 22, 2023

The objections against write-host seem to boil down to "Can't turn off Write-Host" and "Must be PSv5+". This satisfies those concerns without having to bring in a whole module (PSStyle). That said, it would be nice if PSScriptAnalyzer provided quick fixes to create the PSScriptAnalyzerSettings file or add the exclusion attribute as I can never remember the syntax.

#Requires -Version 5

$InformationPreference = "Continue"
if ($InformationPreference -ne "SilentlyContinue") { Write-Host "Foo" -f Green }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants