Home > OS >  How to get both the output and results to a variable using Write-Host in powershell?
How to get both the output and results to a variable using Write-Host in powershell?

Time:12-10

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]

enter image description here

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:

  • enter image description here

    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:

    enter image description here

    CodePudding user response:

    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:

      • However, the information is preserved, namely in the .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
    }
    
  • Related