Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should cmdlets not use the Console API?

Tags:

powershell

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?

like image 311
David Klempfner Avatar asked Oct 14 '16 03:10

David Klempfner


People also ask

What are the drawbacks of PowerShell?

Many IT professionals use it as a way to connect remotely to other computers and servers. When engaging in this process, PowerShell can leave some loopholes open for security breaches. This is the major drawback of using PowerShell script.

Is PowerShell cmdlets case sensitive?

PowerShell is as case-insensitive as possible while preserving case.

What is the difference between cmdlet and command?

Cmdlets differ from commands in other command-shell environments in the following ways: Cmdlets are instances of . NET classes; they are not stand-alone executables. Cmdlets can be created from as few as a dozen lines of code.

What is the format when typing cmdlets in PS?

PowerShell Formatting Overview PowerShell has a set of commands that gives you control over how you wish to display the output for any particular object. The names of all the cmdlets begin with the verb Format . You can use these cmdlets to decide how you like to see the data.


2 Answers

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.

like image 195
mklement0 Avatar answered Oct 17 '22 13:10

mklement0


[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.

like image 27
davidhigh Avatar answered Oct 17 '22 15:10

davidhigh