主にWindows環境での開発を行っている橋田です。
今回、PowerShellで現在のセッションのカルチャを変更する方法を調査しました。 これは、PowerShellのスクリプトがシステムのカルチャの影響を受けないようにしたい場合などに便利です。
バージョンによって対応方法が異なることや、その背景など、調査をして初めて知ったこともあったため、その調査結果を紹介します。
デフォルトのコマンドレット
PowerShellには、以下のようなカルチャを変更するコマンドレットが存在します。
しかしこれらのコマンドレットは、システム全体やユーザー単位の設定を書き換えるため、現在のセッションのカルチャのみを一時的に変更したいという目的では使用できません。
セッションのカルチャの動作
セッションのカルチャの動作については、PowerShell 6で仕様変更が入っています。
$PSCulture
がセッション内カルチャの変更を一貫して反映Windows PowerShell では、現在のカルチャの値がキャッシュされるため、セッションの開始後にカルチャが変更されると値が同期しなくなる場合があります。 このキャッシュ動作が、PowerShell Core で修正されています。
PowerShell 6以降では[System.Threading.Thread]::CurrentThread.CurrentCulture
を変更すると現在のセッションに反映されます。
一方、PowerShell 5.1以下では[System.Threading.Thread]::CurrentThread.CurrentCulture
を変更しても、キャッシュされた値が使われるため現在のセッションには反映されません。
キャッシュされているカルチャの値を変更する必要があります。
$culture = [System.Globalization.CultureInfo]::CreateSpecificCulture("en-US")
$assembly = [System.Reflection.Assembly]::Load("System.Management.Automation")
$type = $assembly.GetType("Microsoft.PowerShell.NativeCultureResolver")
$type.GetField('m_Culture', 'NonPublic, Static').SetValue($null, $culture)
$type.GetField('m_uiCulture', 'NonPublic, Static').SetValue($null, $culture)
参考: https://github.com/PowerShell/PowerShell/issues/19860
結論
以上の調査結果をまとめると、以下のような関数を作成することでPowerShell 5.1以下とPowerShell 6以降のどちらでも現在のセッションのカルチャを変更することができます。
function Set-CurrentCultures {
param([Parameter(Mandatory=$true)]
[string]$name)
$culture = [System.Globalization.CultureInfo]::CreateSpecificCulture($name)
$psVer = $PSVersionTable.PSVersion.Major
if ($psVer -ge 6) {
[System.Threading.Thread]::CurrentThread.CurrentUICulture = $culture
[System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
}
else {
$assembly = [System.Reflection.Assembly]::Load("System.Management.Automation")
$type = $assembly.GetType("Microsoft.PowerShell.NativeCultureResolver")
$type.GetField('m_Culture', 'NonPublic, Static').SetValue($null, $culture)
$type.GetField('m_uiCulture', 'NonPublic, Static').SetValue($null, $culture)
}
}
使用方法は以下の通りです。
> [System.Threading.Thread]::CurrentThread.CurrentUICulture
LCID Name DisplayName
---- ---- -----------
1041 ja-JP 日本語 (日本)
> [System.Threading.Thread]::CurrentThread.CurrentCulture
LCID Name DisplayName
---- ---- -----------
1041 ja-JP 日本語 (日本)
> Set-CurrentCultures "en-US"
> [System.Threading.Thread]::CurrentThread.CurrentUICulture
LCID Name DisplayName
---- ---- -----------
1033 en-US English (United States)
> [System.Threading.Thread]::CurrentThread.CurrentCulture
LCID Name DisplayName
---- ---- -----------
1033 en-US English (United States)
なお、このカルチャの変更は、現在のPowerShellのセッションにのみ影響し、セッションから呼び出した外部プログラム(exeなどの新規プロセス)には影響しません。
まとめ
今回はPowerShellで現在のセッションのカルチャを変更する方法を紹介しました。
本記事が、同様の問題で悩まれている方に少しでも役に立てば幸いです。