It is well known that Write-Host
is evil.
In PowerShell 5
, Write-Information
is added and is considered to replace Write-Host
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.2>
or *>
redirections are used.$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($_) }