I just came across a funny behavior when using Write-Host
on powershell.
What I wanted to do is get the colored output from Write-Host
and concurrently save the result in a variable. Checking other SO questions, led me to try the following:
$zz = &{
Write-Warning "hello"
Write-Error "hello"
Write-Output "hi"
} 3>&1 2>&1
$zz
#WARNING: hello
#Write-Error: hello
#hi
$zz = &{ Write-Host -ForegroundColor Red "[ERROR]: Package id: ""jaja"" not found!"; } 3>&1 2>&1
# [ERROR]: Package id: "jaja" not found!
$zz
# [nothing]
The output was surprising, and I could not find a way to have the output saved into a variable while also see it displayed, unlike when using the other Write-xxx
commandlets.
Q: What's gong on and how can I get both the output shown and save the results into a variable?
REFERENCES:
UPDATE-1
Thanks to mklement0's updated answer, I also tried the following, which almost does what I want, but does not produce the color.
Write-Host -ForegroundColor Red "[ERROR]: Package id: ""jaja"" not found!" 6>&1 | Tee-Object -Variable zz
($zz = Write-Host -ForegroundColor Red "[ERROR]: Package id: ""$package"" not found!" 6>&1)
The conclusion seem to be that any coloring information is lost when using anything that has to do with redirecting output from Write-Host
.
UPDATE-2
Interestingly, the color information are still "there" somewhere. Following mklement0's suggestion, I tried to save the color info for 2 different lines. But then the parsing is not correct, as shown below.
So with:
$captured = &{ Write-Host -ForegroundColor Red -NoNewline "[ERROR]: some error! " 6>&1; Write-Host -ForegroundColor Green "OKAY" 6>&1 }
We get:
As explained in the answer you link to, you need redirection 6>&1
in order to capture Write-Host
output (only works in PowerShell v5 and above):
Write-Host
output captured via 6>&1
consists of one or more System.Management.Automation.InformationRecord
instances, which print as if they were strings, namely by their .MessageData.Message
property value, which is the string content of the argument(s) passed to Write-Host
.
Therefore, any coloring that stems from the use of the -ForegroundColor
and -BackgroundColor
parameters is not (directly) passed through:
.MessageData.ForegroundColor
and .MessageData.BackgroundColor
properties, along with the information about whether -NoNewLine
was passed to Write-Host
, in Boolean property .MessageData.NoNewLine
By contrast, coloring via ANSI / VT escape sequences embedded in the original string argument(s) is preserved.
Thus, you can recreate the original coloring as follows - note that Write-Host
is again used:
$captured = Write-Host -ForegroundColor Red "[ERROR]: some error" 6>&1
$captured | ForEach-Object {
$messageData = $_.MessageData
$colorArgs = @{}
if (-1 -ne $messageData.ForegroundColor) { $colorArgs.ForegroundColor = $messageData.ForegroundColor }
if (-1 -ne $messageData.BackgroundColor) { $colorArgs.BackgroundColor = $messageData.BackgroundColor }
Write-Host -Object $captured @colorArgs -NoNewline:$messageData.NoNewLine
}