tech.guitarrapc.cóm

Technical updates

PowerShellでclipコマンドを使ってクリップボードに出力すると文字化けする対策

以前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コマンドでやりたいケースもあるので、いい感じにエンコーディングを合わせてあげるといいでしょう。

参考