PowerShellの文字エンコード切り替え関数

## はじめに
PowerShellの文字エンコードは思った以上に複雑で、いろいろ試しながら理解していく必要がありそうです。そこで、これまで調べてきたことを元に、現時点でわかっている範囲で、文字エンコードを切り替える関数群を定義してみました。

## おさらい
これまで、`$PSDefaultParameterValues`と`$OutputEncoding`でUTF-8の環境設定をしてきたので、これらに関してもう一度ドキュメントを確認してみます。

* 参考：[文字エンコードについて - PowerShell | Microsoft Docs (既定のエンコードの変更)](https://docs.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_character_encoding?view=powershell-5.1#changing-the-default-encoding)

このドキュメントに、
> PowerShell 5.1 から、リダイレクト演算子 ( と ) は コマンドレット > >> を呼び出 Out-File します。 したがって、次の例に示すように、ユーザー設定変数を使用して、これらの既定 $PSDefaultParameterValues のエンコードを設定できます。

こう書いてあります。従って、`$PSDefaultParameterValues`が`cat`などのコマンドだけでなく、ファイルに書き出すときにも使われるということがわかりました。

また、セクションの最後の部分にもこう但し書きがありました。
> 自動変数は $OutputEncoding 、外部プログラムとの通信に PowerShell が使用するエンコードに影響します。 出力リダイレクト演算子と PowerShell コマンドレットがファイルに保存するために使用するエンコードには影響しません。

二つの変数が独立しているため、組み合わせによって意図しない結果を招きそうです。

ということで、これらを揃えてしまえば混乱は減るはずなので、環境を揃える関数群を定義してみました。

## 関数定義
```swenc.ps1
# 文字エンコードをUTF8に設定する
function utf8 {
	$PSDefaultParameterValues['*:Encoding'] = 'utf8'
	$global:OutputEncoding = [System.Text.Encoding]::UTF8
	[console]::OutputEncoding = [System.Text.Encoding]::UTF8
	$Host.UI.RawUI.WindowTitle = "Windows PowerShell (" +  $OutputEncoding.WebName + ")"
}

# 文字エンコードをデフォルト(SJIS)に設定する
function sjis {
	$PSDefaultParameterValues['*:Encoding'] = 'default'
	$global:OutputEncoding = [System.Text.Encoding]::Default
	[console]::OutputEncoding = [System.Text.Encoding]::Default
	$Host.UI.RawUI.WindowTitle = "Windows PowerShell (" +  $OutputEncoding.WebName + ")"
}

# 文字エンコードをASCIIに設定する
function ascii {
	$PSDefaultParameterValues.Remove('*:Encoding')
	$global:OutputEncoding = [System.Text.Encoding]::ASCII
	[console]::OutputEncoding = [System.Text.Encoding]::ASCII
	$Host.UI.RawUI.WindowTitle = "Windows PowerShell (" +  $OutputEncoding.WebName + ")"
}

# デフォルトパラメータの文字エンコード指定を解除する
function rmenc {
	$PSDefaultParameterValues.Remove('*:Encoding')
}

# 文字エンコード設定を初期状態に戻す
function reset_enc {
	$PSDefaultParameterValues.Remove('*:Encoding')
	$global:OutputEncoding = [System.Text.Encoding]::ASCII
	[console]::OutputEncoding = [System.Text.Encoding]::Default
	$Host.UI.RawUI.WindowTitle = "Windows PowerShell (INITIAL ENCODING)"
}
```

## 使い方

上記のコードを`swenc.ps1`というファイルに保存した場合は、`. .\swenc.ps1`として読み込みます。好みに応じて関数名を変えると良いと思います。常用する場合には、`$profile`ファイルに組み込むと便利です。

* `utf8`  : UTF-8の環境に切り替える
* `sjis`  : SJISの環境に切り替える
* `ascii` : ASCIIの環境に切り替える (実用性はなさそう)
* `rmenc` : `$PSDefaultParameterValues`の文字エンコード設定を削除
* `reset_enc` : 文字エンコード設定を初期状態に戻す

各コマンドをタイプするだけです。どの状態に切り替えたかは、タイトルバーに表示するようにしています。([^1]参照)

### 使用例
環境を切り替えて、環境に対応した入力行を以下からコピペした結果を示します。(`ascii`では文字化けするので直接タイプは困難)

#### 入力

```PowerShell
echo UTF-8の文字エンコードです。 > utf8_echo.txt
echo SJISの文字エンコードです。 > sjis_echo.txt
echo ASCIIの文字エンコードです。 > ascii_echo.txt
echo Initialの文字エンコードです。 > init_echo.txt
```

#### 実行結果

```
PS > utf8
PS > echo UTF-8の文字エンコードです。 > utf8_echo.txt
PS > cat utf8_echo.txt
UTF-8の文字エンコードです。
PS > fhx utf8_echo.txt | %{$_.ToString()}
00000000   EF BB BF 55 54 46 2D 38 E3 81 AE E6 96 87 E5 AD  ï»¿UTF-8ã®æå­
00000010   97 E3 82 A8 E3 83 B3 E3 82 B3 E3 83 BC E3 83 89  ã¨ã³ã³ã¼ã
00000020   E3 81 A7 E3 81 99 E3 80 82 0D 0A                 ã§ãã..

PS > sjis
PS > echo SJISの文字エンコードです。 > sjis_echo.txt
PS > cat sjis_echo.txt
SJISの文字エンコードです。
PS > fhx sjis_echo.txt | %{$_.ToString()}
00000000   53 4A 49 53 82 CC 95 B6 8E 9A 83 47 83 93 83 52  SJISÌ¶GR
00000010   81 5B 83 68 82 C5 82 B7 81 42 0D 0A              [hÅ·B..

PS > ascii
PS > echo ASCII??????????? > ascii_echo.txt
PS > cat ascii_echo.txt
ASCIIの文字エンコードです。
PS > fhx ascii_echo.txt | %{$_.ToString()}
00000000   FF FE 41 00 53 00 43 00 49 00 49 00 6E 30 87 65  .þA.S.C.I.I.n0e
00000010   57 5B A8 30 F3 30 B3 30 FC 30 C9 30 67 30 59 30  W[¨0ó0³0ü0É0g0Y0
00000020   02 30 0D 00 0A 00                                .0....

PS > reset_enc
PS > echo Initialの文字エンコードです。 > init_echo.txt
PS > cat init_echo.txt
Initialの文字エンコードです。
PS > fhx init_echo.txt | %{$_.ToString()}
00000000   FF FE 49 00 6E 00 69 00 74 00 69 00 61 00 6C 00  .þI.n.i.t.i.a.l.
00000010   6E 30 87 65 57 5B A8 30 F3 30 B3 30 FC 30 C9 30  n0eW[¨0ó0³0ü0É0
00000020   67 30 59 30 02 30 0D 00 0A 00                    g0Y0.0....
```
:::note warn
警告
`sjis` に切り替えた場合、`Format-Hex` など `-Encoding` に `oem` や `dafault` を指定できないコマンドをパイプラインで使うと警告が出ることに注意してください。(PowerShell 7.2では `oem` は有効)
:::

#### リダイレクトしたファイルの文字エンコード
環境|ファイル|文字エンコード
-|-|-
utf8|utf8_echo.txt|BOM付きUTF-8
sjis|sjis_echo.txt|Shift-JIS
ascii|ascii_echo.txt|BOM付きUnicode
初期状態|init_echo.txt|BOM付きUnicode


### 確認環境
* WIndows10 Home 21H2
* PowerShell 5.1

```
OS 名:                  Microsoft Windows 10 Home
OS バージョン:          10.0.19044 N/A ビルド 19044
PSVersion:              5.1.19041.1320
```

## 参考

https://qiita.com/e4rfx/items/cd162a4ad1db10e86f50

https://qiita.com/e4rfx/items/243a19d7853a2a585422

[^1]: [コンソールをカスタマイズする - PowerShell Memo (コンソールタイトルを変更)](https://newpops.hatenadiary.org/entry/20060719/p1)