現在開発中のPowerShell 6.0ではクロスプラットフォーム化することを主な契機としてファイル出力のエンコーディングに大きな破壊的変更が入ります。
現在最新のPowerShell 6.0 Beta.9でその変更が一部反映されたため本エントリで紹介します。
1. -Encodingパラメーターの型が変わります
これまでのPowerShellでは、例えばOut-File
などのファイル出力に係わるコマンドレットの-Encoding
パラメーターはstring
型*1であり、主に以下の内容を指定可能でした。
手元のWindows PowerShell 5.1環境ではざっとこんな感じです。
コマンドレット | -Encodingパラメーターの型 |
---|---|
Add-Content | Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding |
Export-Clixml | System.String |
Export-Csv | System.String |
Export-PSSession | System.String |
Get-Content | Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding |
Import-Csv | System.String |
Out-File | System.String |
Select-String | System.String |
Set-Content | Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding |
-Encodingパラメータの値 | 対応する.NET Frameworkのエンコーディング |
---|---|
unknown | System.Text.Encoding.Unicode |
string | System.Text.Encoding.Default |
unicode | System.Text.Encoding.Unicode |
bigendianunicode | System.Text.Encoding.BigEndianUnicode |
utf8 | System.Text.Encoding.UTF8 |
utf7 | System.Text.Encoding.UTF7 |
utf32 | System.Text.Encoding.UTF32 |
ascii | System.Text.Encoding.ASCII |
default | System.Text.Encoding.Default (PowerShell Core 6.0だとUTF8) |
oem | GetOEMCP()関数で得られるコードページのエンコーディング |
PowerShell 6.0 Beta.9からは-Encoding
パラメーターは全てSystem.Text.Encoding
型に統一されます。
一応これまでのパラメーターも全てではないもののstring
→System.Text.Encoding
への変換をしてくれるのでそのまま使えます。
この変更により、Out-File
などのコマンドレットで使用可能なエンコーディングの制限がなくなるので利用範囲がより増えることになります。
# 例) たとえばOut-FileでEUC出力するなんてことも可能に $encoding = [Text.Encoding]::GetEncoding(51932) "鉄はホットなうちにビートダウン!" | Out-File -FilePath .\sample.txt -Encoding $encoding
非互換のパラメーターについて
今回の変更によりGet-Content
やSet-Content
の-Encoding
ではByte
を指定することが出来なくなりました。
代わりにAsByteStream
パラメーターを使う必要があります。
# PowerShell 5.1まで Get-Content -Path .\Sample.bin -Encoding Byte # PowerShell 6.0からは -AsByteStream を使う Get-Content -Path .\Sample.bin -AsByteStream
2. デフォルトのファイル出力エンコーディングがBOM無しUTF-8になります
こちらは多くの人が望んでいた変更かと思います。
PowerShellがクロスプラットフォーム化したことでより多くの環境にマッチする動作をするための変更となります。
この変更については、もともとRFCで提案されていたものが承認され、前項の変更に合わせてPowershell 6.0 Beta.9で"部分的に"導入されました。
例として以下の様なリダイレクト演算子やエンコーディング指定のないOut-File
コマンドレットを実行した場合、これまではBOM付きのUTF-16で出力されましたが、PowerShell 6.0ではBOM無しUTF-8になります。
# PowerShell 5.1まではBOM付きUTF-16、PowerShell 6.0からはBOM無しUTF-8のファイルが作成される "鉄はホットなうちにビートダウン!" > .\sample.txt "鉄はホットなうちにビートダウン!" | Out-File .\sample.txt
この変更に合わせて前項の-Encoding
パラメーターに新たに
- utf8BOM
- utf8NoBOM
と、BOMの有無を明示したものが追加されました。
RFCの未実装部分について
RFCを最後まで読むとわかるのですが、このRFCではデフォルトのエンコーディングを変える他に、これまでのWindows PowerShellとの互換を図るため$PSDefaultEncoding
変数を追加し、従来の挙動と今回変更された挙動を切り替えることができる様にすると記載されています。
この機能については現在のところ未実装でPowerShell 6.0のリリース後要望があれば実装するとの事です。*2
その要望を集めるためのIssueが
に上げられているので互換性が必要だと思う方はこちらにコメントすると良いでしょう。
注意事項
ちょっとややこしいのですが、今回の変更はファイル出力に係わるエンコーディングのはなしであるため、$OutputEncoding
変数や[Console]::OutputEncoding
については変更がありませんので注意してください。
【2017/12/25追記】
本件とは別件でPowerShell 6.0 RC1から$OutputEncoding
の既定値がBOM無しUTF8
に変更されました。
細かい経緯は
をご覧ください。
(余談ですが、はじめは既定値をISO-8859-1(いわゆるLatin-1)にする方針で思わずコメントしてしまいました...)
最後に
とりあえずこんな感じです。
今回の変更はPowerShell 6.0で発生する破壊的変更の中でも最大級のものですが、否定的な反応はさほど出ないのではと個人的には思っています。
*1:またはMicrosoft.PowerShell.Commands.FileSystemCmdletProviderEncoding型
*2:細かい話は https://github.com/PowerShell/PowerShell/pull/5080#discussion_r144723400 あたりのコメントを読んでください