Repository navigation
Description
PowerShell Core now commendably defaults to UTF-8 encoding, including when sending strings to external programs, as reflected in $OutputEncoding's default value.
However, because the console-window shortcut file / taskbar entry still defaults to the OEM code page implied by the legacy system locale (e.g. 437 on US-English systems), it misinterprets strings from external programs; e.g., with Node.js installed:
PSCoreOnWin> $captured = '€' | node -pe "require('fs').readFileSync(0).toString().trim()"; $captured
Γé¼ # !! node's UTF-8 output was misinterpreted.This currently requires the following workaround (in addition to requiring the console window to use a TrueType font (true by default on Windows 10)):
[console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8EncodingPrepend $OutputEncoding = to make a Windows PowerShell console fully UTF-8-aware.
The above implicitly switches to the UTF-8 code page (65001), as then reflected in chcp.
This obscure workaround shouldn't be necessary, and I think it would make sense for PowerShell to automatically set [console]::InputEncoding and [console]::OutputEncoding to (BOM-less) UTF-8 on startup.
Update: When this issue was originally created, there was no mechanism for presetting code page 65001 (UTF-8) system-wide, which necessitated the awkward workaround. In recent versions of Windows 10 it is now possible to switch to code page 65001 as the system locale and therefore system-wide, although as of Windows 10 version 1909 that feature is still in beta - see this SO answer.
- Caveat: In addition to defaulting the OEM code page to
65001in all console windows (includingcmd.exewindows), this invariably also makes Windows PowerShell's ANSI-encoding-default cmdlets default to UTF-8, notablyGet-ContentandSet-Content, which can be problematic from a backward-compatibility perspective.
Additionally, there is a bug - see below.
The change, which can also be made programmatically (see below), requires administrative privileges and a reboot.
Environment data
PowerShell Core 7.1.0-preview.3 on Windows 10
Activity
iSazonov commentedon Aug 27, 2018
It is a platform default:
https://source.dot.net/#System.Console/System/Console.cs,a570cd79bd33ceab
https://source.dot.net/#System.Console/System/ConsolePal.Windows.cs,c997db0e94f0d1cc
https://source.dot.net/#System.Console/Common/Interop/Windows/Interop.GetConsoleOutputCP.cs,f028312cfc964730
So we need do
[console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encodingat PowerShell Core startup. Michael Klement (@mklement0) Right fix for all platforms and Windows versions (Windows 7?) ?mklement0 commentedon Aug 28, 2018
Thanks for the sleuthing, Ilya (@iSazonov).
Yes, I think the fix is also appropriate for Windows 7:
While you're more likely to run into problems with standard console programs there that can even break with UTF-8 input, I think it's more important for PowerShell Core to exhibit consistent encoding behavior and to support modern, cross-platform utilities that natively speak UTF-8 by default.
mklement0 commentedon Aug 28, 2018
Ilya (@iSazonov): Forgot to clarify: It is only the right fix for Windows - on Unix-like platforms the CoreFx default should be used, as discussed in #7634 (even though there's a CoreFx fix pending).
iSazonov commentedon Aug 29, 2018
I hope James Truher (@JamesWTruher) could comment. I think he considered this in time writing and implementing Encoding RFC.
iSazonov commentedon Mar 12, 2020
Since Windows 7 EOL and community are migrating to Windows 10 it seems a time to switch a console default to UTF8 on WIndows.
/cc Steve Lee (@SteveL-MSFT)
KalleOlaviNiemitalo commentedon Jun 6, 2020
Steven Penny (@nu8), are you using Windows PowerShell? In PowerShell Core, the default encoding for
Get-Contenton files has beenUTF8NoBOMsince #5080.mklement0 commentedon Jun 6, 2020
mklement0 commentedon Jun 6, 2020
mklement0 commentedon Jun 6, 2020
mklement0 commentedon Jun 6, 2020
mklement0 commentedon Jun 6, 2020
mklement0 commentedon Jun 7, 2020
Let me try to summarize, now that we (hopefully) have the full picture:
I've hidden my previous comments in favor of this one, Steven Penny (@nu8) - I encourage you to do the same, as appropriate. This comment also corrects my incorrect earlier claim that you cannot set the ANSI code page to
65001.This issue is about making UTF-8 support in PowerShell on Windows complete, by making sure that PowerShell also uses UTF-8 when communicating with external programs (the built-in cmdlets already default to UTF-8, invariably so), which requires setting
[console]::InputEncodingand[console]::OutputEncodingto (BOM-less) UTF-8 (possibly indirectly).Currently, in the absence of PowerShell doing that itself, there are two workarounds:
Option 1: Put the following statement in your
$PROFILE:Pros and cons:
$PROFILEpwsh -noprofile ...Note: In Windows PowerShell, you must prepend
$OutputEncoding =to the above command, in order to also make Windows PowerShell send UTF-8 to external programs. (In PowerShell [Core], this preference variably commendably defaults to (BOM-less) UTF-8.)Option 2: Change the active code pages to
65001system-wide (W10+):GUI method: via
intl.cpl(Control Panel), tabAdministrative,Change system locale...); as previously noted, this is still labeled asBeta:as of Windows 10 release 1909, though I suspect it will work fine as long as you use only modern command-line utilities.Equivalent programmatic method, based on @nu8's approach:
Pros and cons:
Due to a .NET bug still present in the .NET version underlying PowerShell Core 7.1.0-preview.3,
[console]::InputEncodingand[console]::OutputEncodingare mistakenly set to UTF-8 encoding with BOM, which causes follow-on bugs; notably, it breaksStart-Jobin PowerShell. See System.Console unexpectedly uses a UTF-8 encoding *with BOM* on Windows dotnet/runtime#28929. Option 1 above doesn't have this problem.Curiously, by contrast, the
[System.Text.Encoding]::Defaultencoding that reflects the active ANSI code page contains a BOM-less UTF-8 encoding after the system-wide change (see below).Note that the bug can also manifest without the system-wide change, namely if you manually run
chcp 65001fromcmd.exe, for instance, before invoking PowerShell (runningchcpfrom inside PowerShell isn't supported and requires Option 1 instead).Requires administrative privileges and a reboot.
Takes effect system-wide: it applies to all console / Windows Terminal windows, notably including those running
cmd.exeInvariably also uses UTF-8 as the ANSI code page (not just the OEM code page), as reflected in
[System.Text.Encoding]::Default(note that this also applies if you set only theOEMCPregistry value to65001;(Get-Culture).TextInfo.ANSICodePage, by contrast, continues to report the locale-appropriate code page, e.g.1252).Get-ContentandSet-Content, which, depending on your backward-compatibility needs:$PSDefaultParameterValues['*:Encoding'] = 'utf8'in your$PROFILE, this is the only way to get Windows PowerShell to consistently default to UTF-8.Curiously, the system-wide change causes Windows PowerShell to then create BOM-less UTF-8 files by default with
Set-Content, something that cannot otherwise achieved, except with direct use of .NET.Get-ContentandSet-Contentwithout-Encodingand you need to process BOM-less files that are ANSI- rather than UTF-8-encoded.$OutputEncoding = [System.Text.Utf8Encoding]::new()(via$PROFILE) in order to also make Windows PowerShell send UTF-8 to external programs.A note on file encoding:
If making Windows PowerShell too default to UTF-8 via the system-wide change is not an option, BOM-less UTF-8 files will only be read correctly under one of the following conditions:
you use
-Encoding Utf8with file-handling cmdlets.you convert your BOM-less UTF-8 files to have a BOM
you preset the default encoding via
$PSDefaultParameterValues['*:Encoding'] = 'utf8', but you'll have to scope this setting if you don't want all code to use these defaults.Note that Windows PowerShell - curiously, except if the system-wide change is made - only ever creates UTF-8 files with BOM (whereas PowerShell [Core] defaults to BOM-less UTF-8 and has an
-Encoding utf8BOMopt-in); direct use of .NET is required to work around that - see this SO answer.mklement0 commentedon Dec 8, 2020
gerardog commentedon Mar 29, 2022
Is it a good idea to implement this inside PowerShell?
Changing the encoding inside
pwshalso changes the code page, which also affects:CMD.EXEThose changes remain after
pwshends, until the console is closed.In other words: if running PWSH changes the encoding, it will impact the console session permanently:
So, (unless there is a way to decouple the encoding and the codepage... Why are they coupled in first place?) should the current code page by changed by a console app? I don't think so.
IMO, it either should be a system-wide setting, or a setting in WindowsTerminal / ConHost. Not a responsibility of a console app or a shell...
7 remaining items
webstean commentedon Jan 13, 2025
Been 6 months, any progress from the Working Group Jason Helmick (@theJasonHelmick)
Frulfump commentedon Jun 21, 2025
Jason Helmick (@theJasonHelmick) Steve Lee (@SteveL-MSFT) We are now a full year into the working group reviewing and discussing this... and crickets...
I ran into this nonsense when piping to ripgrep on Windows 10 22H2 in PowerShell 7.5.1. Fortunately they document this in their FAQ https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#how-do-i-pipe-non-ascii-content-to-ripgrep-on-windows
so I could use
[System.Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()to set it to UTF-8 (without BOM as I have a hunch BOM could lead to other issues, but I guess no BOM could also lead to issues but I much prefer issues in programs that undestand UTF-8 without a BOM as I only use modern programs anyways. This seems similar to what Michael Klement (@mklement0) already has pointed out). Importantly (but not surprisingly) I also had to set[System.Console]::InputEncoding = [System.Console]::OutputEncodingas otherwiseImport-Modulewould fail with weird errors like the following on restarts of my shellDocumenting is a good first step, obviously I would prefer it be fixed but this should be easier to handle in the meantime maybe a developer setting in Windows if the defaults can't be changed? But preferably a new major release where this can be a breaking change? Also even if this is documented not everyone will read the documents so if the issue can be automatically identified somehow and the user notified that would also improve things.
I worry this issue will be closed as wontfix after it's just documented as "by design".
theJasonHelmick commentedon Jun 23, 2025
Frulfump You’re right that this issue has been under discussion within the working group for quite a while, and we have documented the behavior and provided guidance (as you’ve noted). The core challenge is that we haven’t yet reached a consensus across the working group on the right path forward. There are tradeoffs around default behavior, breaking changes, and cross-platform consistency that we’re still trying to balance.
That said, your experience and the clarity of your examples are incredibly helpful. I’ll raise this again in the next working group discussion and push for us to land on a resolution.
iSazonov commentedon Jun 24, 2025
Why not make it an experimental feature in 7.7 Preview1?
theJasonHelmick commentedon Jul 1, 2025
Thank you Michael Klement (@mklement0) and everyone else for the detailed discussion. This issue has been around for a long time - and I deeply appreciate the level of discussion. The Working Group has reviewed this in depth.
After looking into it, we’ve decided not to move forward with this change. The risk is too high, and there are too many unknowns for us to safely make this update. Also, this is something that would likely need to be addressed by the Windows team directly, since they’d need to ensure compatibility across the entire system. Fo these reasons we are closing this issue as "Won't fix".
Frulfump commentedon Jul 1, 2025
So it took you 7 years to figure that out, it was kind of looking like it leaned towards that from the get go anyways. So we essentially wasted 7 years where the Windows team could've had this on their plate then? Will this be raised internally or can we track that somewhere?
methane commentedon Jul 2, 2025
Compared with 7 years ago, Windows Terminal is the new default terminal now.
Even if MS cannot change the default codepage for console, MS would be able to add UTF-8 Power Shell profile to Windows Terminal, and make it default finally.
microsoft-github-policy-service commentedon Jul 3, 2025
This issue has been marked as won't fix and has not had any activity for 1 day. It has been closed for housekeeping purposes.
microsoft-github-policy-service commentedon Jul 3, 2025
📣 Hey @Michael Klement (@mklement0), how did we do? We would love to hear your feedback with the link below! 🗣️
🔗 https://aka.ms/PSRepoFeedback