powershellpowershell-5.0

Powershell 5 - Multicolored text on the same line, logged on text file on the same line


I'm currently running a ps1 script in Powershell 5, where I need two things to happen at the same time:

An example of the code used is the following:

Write-Host "Name: " -ForegroundColor "DarkMagenta" -NoNewLine
Write-Host "John"   -ForegroundColor "DarkBlue"

Unfortunately, the different methods I've tried to achieve the above goals do not work, since:

Any suggestion about how could I achieve the desired result (i.e. colored output on the console and correctly formatted log on the text file)?

Thank you!


Solution

  • Do use ANSI (VT) escape sequences, which Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1) also supports.

    The only pitfall is that PowerShell's `e escape sequence only exists in PowerShell (Core) 7, whereas in Windows PowerShell it becomes a verbatim e - use $([char] 27) or similar techniques instead; e.g.:

    # Write-Output implied
    '{0}[5;36mMyText{0}[0m' -f [char] 27
    
    # Alternative, with helper variable (you can also embed $([char] 27) every time).
    $e = [char] 27; "$e[5;36mMyText$e[0m"
    

    Optional reading: ANSI escape-sequence handling in Windows PowerShell vs. PowerShell (Core) 7:

    [1] If preserving the ANSI sequences is undesired, you'll have to strip (remove) them yourself in Windows PowerShell after the fact; you yourself came up with the following regex, though note that this doesn't cover all possible VT (ANSI) escape sequences:
    (Get-Content -Raw C:\Log.txt) -replace '\e\[[0-9;]*m' | Set-Content -NoNewLine C:\Log.txt
    Note that PowerShell 7 now offers a helper class, System.Management.Automation.Internal.StringDecorated, to achieve the same, which (presumably) covers all escape sequences:
    ([System.Management.Automation.Internal.StringDecorated] (Get-Content -Raw C:\Log.txt)).ToString('PlainText') | Set-Content -NoNewLine C:\Log.txt

    [2] These cmdlets use the for-display formatting system to create string representations of their input objects (in the case of Tee-Object, this applies to use with the -FilePath parameter, not with -Variable). While .NET primitive types as well as strings are considered out-of-band by the formatting system and are stringified with a simple .ToString() call, the [System.Management.Automation.InformationRecord] instances that Write-Host / Write-Information wrap their string arguments in do go through the formatting system and are therefore subject to $PSStyle.OutputRendering.