6

According to the MSDN for Strongly Encouraged Development Guidelines:

Cmdlets should not use the Console API.

Why is this?

If I write [Console]::Write("test"), it works just as well as

Write-Host "test"

EDIT: It's well known that Write-Host should be avoided. When MSDN says to not use the Console API, is it safe to assume that they are implying that we should not use Write-Host either since that uses the Console API behind the scenes?

David Klempfner
  • 8,700
  • 20
  • 73
  • 153

2 Answers2

10

The main reason you shouldn't use console-related functionality is that not all PowerShell host environments are consoles.

While the typical use case is to run PowerShell in a console, PowerShell does not need a console and can cooperate with different kinds of host environments.

Thus, for your code to remain portable, it shouldn't assume the existence of a console.

It is safe, however, to assume the existence of (the abstraction called) host, which PowerShell exposes via the automatic $HOST variable.
The capabilities of hosts vary, however, which has historically created problems even when not using the console API directly, but its PowerShell abstraction, Write-Host - see below.


PowerShell provides a hosting API,

with which the PowerShell runtime can be embedded inside other applications. These applications can then use PowerShell functionality to implement certain operations, including those exposed via the graphical interface.

https://en.wikipedia.org/wiki/PowerShell

The regular PowerShell console using the Console Window Host (conhost.exe) on Windows is therefore just one implementation of a PowerShell host - the PowerShell ISE is another example, as is the Microsoft Exchange Server management GUI (2007+).


As for Write-Host:

Up to PSv4, as the name suggests, it used to write to the host - which may or may not be a console - so Write-Host could actually fail on hosts that don't support user interaction; see this question.

Starting with PSv5, Write-Host is safe to use, because it now writes to the newly introduced, host-independent information stream (number 6) - see Get-Help about_Redirection and the next section.

Note that Write-Host still does and always has generated output outside of the normal PowerShell output stream - its output is meant to be "commentary" (feedback to the user) rather than data.

While Write-Host is safe to use in PSv5+, it exist for backward compatibility, so instead consider using
Write-Information -InformationAction Continue or using Write-Information with preference variable $InformationPreference set to Continue
, because:

  • "Write-Host" is now a bit of a misnomer, given that it doesn't actually directly write to the host anymore.

  • Write-Host, in the interest of backward compatibility, doesn't integrate with the $InformationPreference preference variable - see below.

  • Write-Host still offers console-inspired formatting parameters (-ForegroundColor, -BackgroundColor), which not all hosts (ultimately) support.


Write-Host vs. Write-Information:

Tip of the hat to PetSerAl for his help with the following.

Write-Information, introduced in PSv5, is the cmdlet that fully integrates with the new, host-independent information stream (number 6).
Notably, you can now redirect and thus capture Write-Information / Write-Host output by using 6>, something that wasn't possible with Write-Host in PSv4-.
Also note that this redirection works even with $InformationPreference's default value, SilentlyContinue, which only governs the display, not the output aspect (only using common parameter -InformationAction Ignore truly suppresses writing to the stream).

In line with how PowerShell handles errors and warnings, the display behavior of Write-Information is controllable via the new $InformationPreference preference variable / the new common -InformationAction cmdlet parameter.
Write-Information's default behavior is to be silent - $InformationPreference defaults to SilentlyContinue.

Note that Write-Information has no direct formatting parameters[1] and instead offers keyword tagging with the -Tags parameter[2] .

By contrast, for backward compatibility, Write-Host effectively behaves like
Write-Information -InformationAction Continue
, i.e., it outputs by default, and the only way to silence it is to use Write-Host -InformationAction Ignore[3] - it does not respect an $InformationPreference value of SilentlyContinue (it does, however, respect the other values, such as Inquire).


[1] PetSerAl points out that you can pass formatting information to Write-Information, but only in an obscure fashion that isn't even documented as of PSv5.1; e.g.:
Write-Information -MessageData ([System.Management.Automation.HostInformationMessage] @{Message='Message'; ForegroundColor='Red'}) -InformationAction Continue

[2] Note how parameter name "Tags" actually violates one of the strongly encouraged cmdlet development guidelines: it should be "Tag" (singular).

[3] PetSerAl explains that this behavior stems from Write-Host passing the PSHOST tag to Cmdlet.WriteInformation behind the scenes.

Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775
2

[Console]::Write or Write-Host are basically the same. They both write a message to the console which can be seen on the screen.

The basic reason why this is discouraged is that it breaks the workflow. The output of a Write-Host cmdlet can't be piped or used further. Now if the script runs on a machine without graphical output or similar constraints the command is lost.

According to this and this thread, you should therefore rather use Write-Output, which sends the output message to the pipeline where it can be further used. Further, you can use exceptions if your message is meant to signal an error.

Community
  • 1
  • 1
davidhigh
  • 14,652
  • 2
  • 44
  • 75
  • Are you saying that both [Console]::Write and Write-Host break the workflow and can't be piped further? That's fine, what I'm interested in is why we shouldn't use [Console]::Write if it does the same thing as Write-Host. – David Klempfner Oct 14 '16 at 03:52
  • The message, as I understand, is: use none of the two. – davidhigh Oct 14 '16 at 03:53
  • The MSDN article doesn't say to not use Write-Host, it says to not use the Console API. Do you think since Write-Host uses the Console API behind the scenes, that they are insinuating that we should not use that either? – David Klempfner Oct 14 '16 at 03:56
  • You're right, this is a bit vague. My line of thinking was, if you shouldn't use `[console]::write`, and `[console]::write` is basically the same as `Write-Host`, so don't use both. But it's the second assumption you're questioning, I know ... this where I refered to another SO answer, but that's far from being sure ;-) – davidhigh Oct 14 '16 at 04:01
  • `[Console]::Write` and `Write-Host` _used to be_ essentially the same, up to PowerShell v4. Since not all PowerShell hosts are consoles, `Write-Host` _used to_ potentially break your code. Starting in PowerShell v5, `Write-Host` is safe to use with all hosts, but it's better to use `WriteInformation -InformationAction Continue`. – mklement0 Oct 14 '16 at 16:35
  • While it's important to understand the difference between printing to the console (`Write-Host`) and sending data to the success output stream (implicitly, and with `Write-Output`), there's nothing with _intentionally_ using `Write-Host` to simply supply _supplemental information_, _outside_ of the output data stream. Indeed, that is the mechanism that the new _information stream_ (number `6`) and the `Write-Information` cmdlet formalize. – mklement0 Oct 14 '16 at 16:36