以前PowerShellの実行結果をクリップボードに入れる記事を書きました。clip
はWSLから使えて大変便利ですが、Windows PowerShell(5.1)やPowerShell 7で日本語を含む文字列をクリップボードに出力したとき文字化けすることがあります。
今回は、質問をコメントで受けたのでその対策と原因を紹介します。こんなことはあまり気にしたくないんですが、現時点ではしょうがないです。
2025/4/17追記
PowerShell 5.1/7共にSet-Clipboard
コマンドレットを使うと文字化けしないので例を追加しました。
簡単まとめ
Set-Clipboard
コマンドレットを使うと文字化けしません。clip
コマンドは文字エンコーディングの違いで文字化けします。
clip
を使う場合、PowerShell 5.1、PowerShell 7いずれもコンソールの出力エンコーディングと外部プログラムへの出力エンコーディングを合わせましょう。
PowerShell 5.1では、$global:OutputEncoding
を[Console]::OutputEncoding
に合わせます。PowerShell 7では、[Console]::OutputEncoding
をUTF-8に変更します。
# PowerShell 5.1 PS> $global:OutputEncoding = [Console]::OutputEncoding # PowerShell 7+ PS> [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
PowerShell 5.1
症状の再現からしましょう。パイプライン越しのclip
コマンドでクリップボードに出力を送って、Get-Clipboard
でクリップボードの内容を確認すると日本語文字化けが再現できます。
外部プログラムに渡すエンコーディングがずれているのが原因なので、$global:OutputEncoding
を[Console]::OutputEncoding
に合わせると文字化けが解消します。
PS> $PSVersionTable Name Value ---- ----- PSVersion 5.1.26100.3624 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.26100.3624 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 # Set-Clipboardは文字化けない PS> "テキスト文書に張り付けると文字化けします" | Set-Clipboard PS> Get-Clipboard テキスト文書に張り付けると文字化けします # clipは文字化けする PS> "テキスト文書に張り付けると文字化けします" | clip PS> Get-Clipboard ???????????????????? # clipの文字化けは外部プログラムに渡すエンコーディングをコンソールのエンコーディングに合わせればOK PS> $global:OutputEncoding = [Console]::OutputEncoding PS> "テキスト文書に張り付けると文字化けします" | clip PS> Get-Clipboard テキスト文書に張り付けると文字化けします
原因
PowerShellの出力文字列が文字化けする場合、「コンソールの出力エンコーディング」と「PowerShell が外部プログラムとの通信に使用するエンコード」を確認しましょう。前者は[Console]::OutputEncoding
で、後者は$global:OutputEncoding
で設定します。
新規コンソールを立ち上げエンコーディングを確認してみると、us-asciiとShift-JISのずれと分かります。このため、$OutputEncoding
を[Console]::OutputEncoding
に合わせれば解消できます。
PS> $OutputEncoding IsSingleByte : True BodyName : us-ascii EncodingName : US-ASCII HeaderName : us-ascii WebName : us-ascii WindowsCodePage : 1252 IsBrowserDisplay : False IsBrowserSave : False IsMailNewsDisplay : True IsMailNewsSave : True EncoderFallback : System.Text.EncoderReplacementFallback DecoderFallback : System.Text.DecoderReplacementFallback IsReadOnly : True CodePage : 20127 # デフォルトはOEMエンコーディングなので、日本語環境ではShiuft-JISになる。 PS> [Console]::OutputEncoding BodyName : iso-2022-jp EncodingName : Japanese (Shift-JIS) HeaderName : iso-2022-jp WebName : shift_jis WindowsCodePage : 932 IsBrowserDisplay : True IsBrowserSave : True IsMailNewsDisplay : True IsMailNewsSave : True IsSingleByte : False EncoderFallback : System.Text.InternalEncoderBestFitFallback DecoderFallback : System.Text.InternalDecoderBestFitFallback IsReadOnly : False CodePage : 932
UTF-8直接指定は避ける
外部コマンドに渡すからと[Console]::OutputEncoding
と$global:OutputEncoding
にUTF-8を指定すると文字列の先頭にゴミが入るので避けたほうがいいです。納得感がないですね。
PS> $global:OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 PS> "テキスト文書に張り付けると文字化けします" | clip PS> Get-Clipboard <feff>テキスト文書に張り付けると文字化けします
chcp指定は避ける
chcp 65001
でも同じように対応できるケースもありますが、エンコーディングが実際に何かを確認したほうが確実なのでchcpを使うのはオススメしません。今回のケースでも65001では文字化けが解消しないことは明らかです。
PS> chcp 65001 PS> "テキスト文書に張り付けると文字化けします" | clip PS> Get-Clipboard ・ソ????????????????????
PowerShell 7
PowerShell 7でも文字化けが再現します。しかし文字化け具合がWindows PowerShellとは異なっており、よく見かけるShift-JISとUTF-8の違いで起こる文字化けパターンのようです。
PowerShell 7では、$global:OutputEncoding
はUTF-8がデフォルトなので、単純に[Console]::OutputEncoding
をUTF-8に変更することで、クリップボードに出力できます。だいぶん素直ですね。
PS> $PSVersionTable Name Value ---- ----- PSVersion 7.5.0 PSEdition Core GitCommitId 7.5.0 OS Microsoft Windows 10.0.26100 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0 # Set-Clipboardは文字化けない PS> "テキスト文書に張り付けると文字化けします" | Set-Clipboard PS> Get-Clipboard テキスト文書に張り付けると文字化けします # clipは文字化けする PS> "テキスト文書に張り付けると文字化けします" | clip PS> Get-Clipboard 繝・く繧ケ繝域枚譖ク縺ォ蠑オ繧贋サ倥¢繧九→譁・ュ怜喧縺代@縺セ縺・ # コンソールの出力エンコーディングをUTF-8に変更すればOK PS> [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 PS> "テキスト文書に張り付けると文字化けします" | clip PS> Get-Clipboard テキスト文書に張り付けると文字化けします
原因
新規コンソールを立ち上げエンコーディングを確認してみると、Shift-JISとUTF-8のずれと分かります。このため、[Console]::OutputEncoding
をUTF-8に変更すれば解消できます。
PS> $OutputEncoding Preamble : BodyName : utf-8 EncodingName : Unicode (UTF-8) HeaderName : utf-8 WebName : utf-8 WindowsCodePage : 1200 IsBrowserDisplay : True IsBrowserSave : True IsMailNewsDisplay : True IsMailNewsSave : True IsSingleByte : False EncoderFallback : System.Text.EncoderReplacementFallback DecoderFallback : System.Text.DecoderReplacementFallback IsReadOnly : True CodePage : 65001 PS> [Console]::OutputEncoding EncodingName : Japanese (Shift-JIS) WebName : shift_jis HeaderName : iso-2022-jp BodyName : iso-2022-jp Preamble : WindowsCodePage : IsBrowserDisplay : IsBrowserSave : IsMailNewsDisplay : IsMailNewsSave : IsSingleByte : False EncoderFallback : System.Text.InternalEncoderBestFitFallback DecoderFallback : System.Text.InternalDecoderBestFitFallback IsReadOnly : False CodePage : 932
PowerShell起動時にエンコーディングを自動調整する
PowerShellのプロファイルでエンコーディングを合わせておくと、エンコーディングを考慮する機会が減るでしょう。 PowerShell 5.1とPowerShell 7でプロファイルの場所が異なるのと、エンコーディングを合わせるコマンドが異なるので注意してください。
# PowerShell 5.1 PS> $profile ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 # エンコーディングを合わせるコマンドを自動実行させる PS> '$global:OutputEncoding = [Console]::OutputEncoding' >> $profile # あるいはVS Codeで開いて編集 PS> code $profile
# PowerShell 7 PS> $profile ${env:USERPROFILE}\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 # エンコーディングを合わせるコマンドを自動実行させる PS> '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8' >> $profile # あるいはVS Codeで開いて編集 PS> code $profile
まとめ
PowerShell単独であればSet-Clipboardが素直です。 ただ、他ターミナルも含めてclipコマンドでやりたいケースもあるので、いい感じにエンコーディングを合わせてあげるといいでしょう。