Write-Host vs Write-Information in PowerShell 5

后端 未结 5 1447
春和景丽
春和景丽 2020-12-02 15:46

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

5条回答
  •  -上瘾入骨i
    2020-12-02 16:23

    To complement Ansgar's helpful and comprehensive answer:

    Write-Host became (in essence) a wrapper for
    Write-Information -InformationAction Continue
    in PSv5, presumably because:

    • it enables suppressing or redirecting Write-Host messages, which was not previously possible (in PowerShell 4 or below, Write-Host bypassed PowerShell's streams and output directly to the host),

    • while preserving backward compatibility in that the messages are output by default - unlike with Write-Information, whose default behavior is to be silent (because it respects preference variable $InformationPreference, whose default value is SilentlyContinue).

    While Write-Host is therefore now (PSv5+) a bit of a misnomer — it doesn't necessarily write to the host anymore — it still has one distinct advantage over Write-Information (as you state): it can produce colored output with -ForegroundColor and -BackgroundColor.


    Ansgar's answer has the conventional logging perspective covered, but PowerShell's Start-Transcript cmdlet may serve as a built-in alternative (see below).

    As for your desire to output messages to the host while also capturing them in a log file:

    PowerShell's session transcripts - via Start-Transcript and Stop-Transcript - may give you what you want.

    As the name suggests, transcripts capture whatever prints to the screen (without coloring), which therefore by default includes success output, however.
    Applied to your example:

    $null = Start-Transcript "D:\foo.log"
    
    $InformationPreference = "Continue"
    Write-Information "Some Message"
    Write-Information "Another Message"
    
    $null = Stop-Transcript
    

    The above will print messages to both the screen and the transcript file; note that, curiously, only in the file will they be prefixed with INFO:.
    (By contrast, Write-Warning, Write-Verbose and Write-Debug - if configured to produce output - use prefix WARNING:, VERBOSE:, DEBUG: both on-screen and in the file; similarly, Write-Error produces "noisy" multiline input both on-screen and in the file.)

    Note one bug that only affects Windows PowerShell (it has been fixed in PowerShell [Core].Thanks, JohnLBevan.): output from Write-Information shows up in the transcript file (but not on the screen) even when $InformationPreference is set to SilentlyContinue (the default); the only way to exclude Write-Information output (via the preference variable or -InformationAction parameter) appears to be a value of Ignore - which silences the output categorically - or, curiously, Continue, in which it only prints to the console, as PetSerAl points out.

    In a nutshell, you can use Start-Transcript as a convenient, built-in approximation of a logging facility, whose verbosity you can control from the outside via the preference variables ($InformationPreference, $VerbosePreference, ...), with the following important differences from conventional logging:

    • Generally, what goes into the transcript file is also output to the console (which could generally be considered a plus).

    • However, success output (data output) is by default also sent to the transcript - unless you capture it or suppress it altogether - and you cannot selectively keep it out of the transcript:

      • If you capture or suppress it, it won't show in in the host (the console, by default) either[1].

      • The inverse, however, is possible: you can send output to the transcript only (without echoing it in the console), by way of Out-Default -Transcript Thanks, PetSerAl; e.g.,
        'to transcript only' | Out-Default -Transcript; however, as of PowerShell 7.0 this appears to log the output twice in the transcript; also note that Out-Default is generally not meant to be called from user code - see this answer.

    • Generally, external redirections (applying > to a call to a script that internally performs transcription) keep streams out of the transcript, with two exceptions, as of PowerShell 7.0:

      • Write-Host output, even if 6> or *> redirections are used.
      • Error output, even if 2> or *> redirections are used.
        However, using $ErrorActionPreference = 'SilentlyContinue' / 'Ignore' does keep non-terminating errors out of the transcript, but not terminating ones.
    • Transcript files aren't line-oriented (there's a block of header lines with invocation information, and there's no guarantee that output produced by the script is confined to a line), so you cannot expect to parse them in a line-by-line manner.


    [1] PetSerAl mentions the following limited and somewhat cumbersome workaround (PSv5+) for sending success output to the console only, which notably precludes sending the output through the pipeline or capturing it:
    'to console only' | Out-String -Stream | ForEach-Object { $Host.UI.WriteLine($_) }

提交回复
热议问题