Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write-Host vs Write-Information in PowerShell 5

It is well known that Write-Host is evil. In PowerShell 5, Write-Information is added and is considered to replace Write-Host.

But, really, which is better?
Write-Host is evil for it does not use pipeline, so the input message can't get reused.
But, what Write-Host do is just to show something in the console right? In what case shall we reuse the input?
Anyway, if we really want to reuse the input, why not just write something like this:

$foo = "Some message to be reused like saving to a file" Write-Host $foo $foo | Out-File -Path "D:\foo.log" 

Another Cons of Write-Host is that, Write-Host can specified in what color the messages are shown in the console by using -ForegroundColor and -BackgroundColor.

On the other side, by using Write-Information, the input message can be used wherever we want via the No.6 pipeline. And doesn't need to write the extra codes like I write above. But the dark side of this is that, if we want to write messages to the console and also saved to the file, we have to do this:

# Always set the $InformationPreference variable to "Continue" $InformationPreference = "Continue";  # if we don't want something like this: # ======= Example 1 ======= # File Foo.ps1 $InformationPreference = "Continue"; Write-Information "Some Message" Write-Information "Another Message"  # File AlwaysRunThisBeforeEverything.ps1 .\Foo.ps1 6>"D:\foo.log" # ======= End of Example 1 =======  # then we have to add '6>"D:\foo.log"' to every lines of Write-Information like this: # ======= Example 2 ======= $InformationPreference = "Continue"; Write-Information "Some Message" 6>"D:\foo.log" Write-Information "Another Message" 6>"D:\foo.log" # ======= End of Example 2 ======= 

A little bit redundant I think.

I only know a little aspect of this "vs" thing, and there must have something out of my mind. So is there anything else that can make me believe that Write-Information is better than Write-Host, please leave your kind answers here.
Thank you.

like image 555
wontasia Avatar asked Jul 22 '16 09:07

wontasia


People also ask

Should I use Write-output or Write-Host?

In fact its ONLY if you need the richer output for a user interface you should use Write-Host. If you possibly want to write data to the screen, but also want the data to be passed down the pipeline to further commands, then use Write-Output.

What are the differences between Write-Host & Write-output in PowerShell?

In a nutshell, Write-Host writes to the console itself. Think of it as a MsgBox in VBScript. Write-Output , on the other hand, writes to the pipeline, so the next command can accept it as its input. You are not required to use Write-Output in order to write objects, as Write-Output is implicitly called for you.

What does PowerShell Write-Host do?

Starting in Windows PowerShell 5.0, Write-Host is a wrapper for Write-Information This allows you to use Write-Host to emit output to the information stream. This enables the capture or suppression of data written using Write-Host while preserving backwards compatibility.

Is Write-Host same as echo?

echo is an alias for Write-Output , which writes to the Success output stream. This allows output to be processed through pipelines or redirected into files. Write-Host writes directly to the console, so the output can't be redirected/processed any further.


1 Answers

The Write-* cmdlets allow you to channel the output of your PowerShell code in a structured way, so you can easily distinguish messages of different severity from each other.

  • Write-Host: display messages to an interactive user on the console. Unlike the other Write-* cmdlets this one is neither suitable nor intended for automation/redirection purposes. Not evil, just different.
  • Write-Output: write the "normal" output of the code to the default (success) output stream ("STDOUT").
  • Write-Error: write error information to a separate stream ("STDERR").
  • Write-Warning: write messages that you consider warnings (i.e. things that aren't failures, but something that the user should have an eye on) to a separate stream.
  • Write-Verbose: write information that you consider more verbose than "normal" output to a separate stream.
  • Write-Debug: write information that you consider relevant for debugging your code to a separate stream.

Write-Information is just a continuation of this approach. It allows you to implement log levels in your output (Debug, Verbose, Information, Warning, Error) and still have the success output stream available for regular output.

As for why Write-Host became a wrapper around Write-Information: I don't know the actual reason for this decision, but I'd suspect it's because most people don't understand how Write-Host actually works, i.e. what it can be used for and what it should not be used for.


To my knowledge there isn't a generally accepted or recommended approach to logging in PowerShell. You could for instance implement a single logging function like @JeremyMontgomery suggested in his answer:

function Write-Log {   Param(     [Parameter(Mandatory=$true, Position=0)]     [ValidateNotNullOrEmpty()]     [string]$Message,     [Parameter(Mandatory=$false, Position=1)]     [ValidateSet('Error', 'Warning', 'Information', 'Verbose', 'Debug')]     [string]$LogLevel = 'Information'   )    switch ($LogLevel) {     'Error'       { ... }     'Warning'     { ... }     'Information' { ... }     'Verbose'     { ... }     'Debug'       { ... }     default       { throw "Invalid log level: $_" }   } }  Write-Log 'foo'                    # default log level: Information Write-Log 'foo' 'Information'      # explicit log level: Information Write-Log 'bar' 'Debug' 

or a set of logging functions (one for each log level):

function Write-LogInformation {   Param(     [Parameter(Mandatory=$true, Position=0)]     [ValidateNotNullOrEmpty()]     [string]$Message   )    ... }  function Write-LogDebug {   Param(     [Parameter(Mandatory=$true, Position=0)]     [ValidateNotNullOrEmpty()]     [string]$Message   )    ... }  ...  Write-LogInformation 'foo' Write-LogDebug 'bar' 

Another option is to create a custom logger object:

$logger = New-Object -Type PSObject -Property @{   Filename = ''   Console  = $true } $logger | Add-Member -Type ScriptMethod -Name Log -Value {   Param(     [Parameter(Mandatory=$true, Position=0)]     [ValidateNotNullOrEmpty()]     [string]$Message,     [Parameter(Mandatory=$false, Position=1)]     [ValidateSet('Error', 'Warning', 'Information', 'Verbose', 'Debug')]     [string]$LogLevel = 'Information'   )    switch ($LogLevel) {     'Error'       { ... }     'Warning'     { ... }     'Information' { ... }     'Verbose'     { ... }     'Debug'       { ... }     default       { throw "Invalid log level: $_" }   } } $logger | Add-Member -Type ScriptMethod -Name LogDebug -Value {   Param([Parameter(Mandatory=$true)][string]$Message)   $this.Log($Message, 'Debug') } $logger | Add-Member -Type ScriptMethod -Name LogInfo -Value {   Param([Parameter(Mandatory=$true)][string]$Message)   $this.Log($Message, 'Information') } ...  Write-Log 'foo'                    # default log level: Information $logger.Log('foo')                 # default log level: Information $logger.Log('foo', 'Information')  # explicit log level: Information $logger.LogInfo('foo')             # (convenience) wrapper method $logger.LogDebug('bar') 

Either way you can externalize the logging code by

  • putting it into a separate script file and dot-sourcing that file:

    . 'C:\path\to\logger.ps1' 
  • putting it into a module and importing that module:

    Import-Module Logger 
like image 80
Ansgar Wiechers Avatar answered Sep 30 '22 10:09

Ansgar Wiechers