Note: This issue may well be just a symptom of #5579; if so, it still may be of interest, because it demonstrate that the linked issue has real-world consequences.
Preference variable $OutputEncoding
determines the encoding used to send text to external utilities.
In the _global_ scope, assigning the output from a New-Object
call or, generally, a _command_ (as opposed to an _expression_) works fine.
However, in a _non-global_ scope, such as inside a function, it does not: assigning output from a _command_ to $OutputEncoding
is effectively ignored.
For simplicity, the example below uses Write-Output
in a somewhat contrived manner, but an attempt to use New-Object
to instantiate a specific encoding, e.g., New-Object System.Text.Utf8Encoding
, would exhibit the same problem: it would be ignored.
The workaround is to apply .psobject.BaseObject
to New-Object
's result, or, in PSv5+, to use [<encoding>]::new()
instead.
On Windows:
function foo0 { '眉' | findstr '眉' }
function foo1 { $OutputEncoding = [Console]::OutputEncoding; '眉' | findstr '眉' }
# Same as foo1, except that Write-Output is used to produce output.
function foo2 { $OutputEncoding = Write-Output ([Console]::OutputEncoding); '眉' | findstr '眉' }
foo0; '---'; foo1; '---'; foo2
---
眉
---
眉
Note that foo0
, perhaps surprisingly, does _not_ output anything, because the default $OuputEncoding
value - UTF-8 in PowerShell Core and ASCII in Windows PowerShell - results in output that prevents findstr.exe
from matching non-ASCII characters.
---
眉
---
That is, only the _expression-based_ assignment to the (non-global) $OutputEncoding
variable took effect, not the _command-based_ one.
The command-based one seems to _quietly fall back to ASCII_.
Also note that this issue won't arise on _Unix_ platforms, where PowerShell now emits UTF-8 by default and external utilities such as grep
expect just that.
PowerShell Core v6.0.0-rc.2 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.674 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Write-Output [Console]::OutputEncoding
-> Write-Output ([Console]::OutputEncoding)
Culprit line. Should call PSObject.Base
before as
.
Most helpful comment
Write-Output [Console]::OutputEncoding
->Write-Output ([Console]::OutputEncoding)
Culprit line. Should call
PSObject.Base
beforeas
.