Skip to content

Save pure string text to file with redirection or Out-File unexpectedly strip off VT sequences from the original text #17452

@daxian-dbw

Description

@daxian-dbw

Prerequisites

Steps to reproduce

This happens in 7.3.0-preview.4, and all other 7.3 preview versions.
This is a regression from both 7.0.x and 7.2.x (both are LTS versions).

Content of the test file try.ps1: (Ansi escape sequence is used for color).

Read-Host -Prompt "�[33mEnter your device code�[0m"

Try replacing "`r`n" with "`n" for the content in the file and save it to another file:

(Get-Content .\try.ps1 -Raw).Replace("`r`n", "`n") > new.ps1
## Or, (Get-Content .\try.ps1 -Raw).Replace("`r`n", "`n")  | Out-File new.ps1

Now all Ansi escape sequences are lost in the content of new.ps1:

Read-Host -Prompt "Enter your device code"

Set-Content works as expected, which preserves the Ansi escape sequences.

(Get-Content .\try.ps1 -Raw).Replace("`r`n", "`n") | Set-Content new.ps1

Behavior in 7.0.11:

image

Behavior in 7.2.2:

image


Root cause and behavior proposal

The root cause of this regression is having Host to be the default value for $PSStyle.OutputRendering, which make the Out-* cmdlet to strip off escape sequences from the passed-in input.

  • In 7.0.x, the $PSStyle feature is not there, so Out-* commands don't do anything special to Ansi escape sequences in the input.
  • In 7.2.x, the default value for $PSStyle.OutputRendering is Ansi, so the behavior is unchanged without a user knowing about the $PSStyle feature.
  • In 7.3, the default value is changed to Host, which makes Out-* cmdlets to always strip off escape sequences from the input, and hence the regression.

I understand the purpose of having Host option for $PSStyle.OutputRendering -- it's nice to have ANSI decorations in the formatting output when it's rendered on terminal, but when redirecting the formatting out like in Get-Process > file, the escape sequences in the formatting output becomes annoying. The Host option is to tell PowerShell to not keep ANSI decorations in case of redirection (essentially Out-File, and basically any Out-* cmdlets such as Out-String).

But for pure string input that doesn't really go through formatting, it doesn't seem right to remove the Ansi escape sequences, given that the formatting system doesn't add any to it. The Out-* should treat the pure string input as is, and only remove escape sequences when the input object actually goes through formatting.

So, the proposal is: option Host makes Out-* cmdlets remove escape sequences only if the input object actually goes through formatting within the Out-* cmdlets. For string input, Out-* cmdlet should not do anything special regarding Ansi escape sequences.

Expected behavior

The content in new.ps1 should be the same as in try.ps1, except that all "\r\n" characters are replaced with "\n".

Actual behavior

The escape sequences in the original file was removed during redirection.

Error details

N/A

Environment data

PS:24> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.3.0-preview.4
PSEdition                      Core
GitCommitId                    7.3.0-preview.4
OS                             Microsoft Windows 10.0.19044
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-BugIssue has been identified as a bug in the productResolution-FixedThe issue is fixed.WG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions