Last active
July 6, 2019 10:06
-
-
Save stknohg/9793cddd3311e1e0941d3b25b6f8cd35 to your computer and use it in GitHub Desktop.
エンコーディング設定を変更したスクリプトブロックを実行するファンクション
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSYS | |
ファイル出力に関わるエンコーディング設定を変更したスクリプトブロックを実行します。 | |
.DESCRIPTION | |
指定したスクリプトブロック内でのみファイル出力をするコマンドレット(Out-Fileなど)のエンコーディングの挙動を変更します。 | |
現在変更可能な点は以下になります。 | |
1. 通常BOM付きのUTF8をBOM無しのUTF8に変更する | |
2. DEFAULTエンコーディングを指定したコードページのエンコーディングに変更する | |
.PARAMETER UseBOMlessUTF8 | |
UTF8パラメーターで指定されるエンコーディングをBOM無しUTF8に変更します。 | |
.PARAMETER DefaultCodePage | |
Defaultパラメーターのエンコーディングを指定したコードページのエンコーディングに変更します。 | |
.EXAMPLE | |
PS C:\> Invoke-CustomEncodingBlock { "BOMなしUTF8" | Out-File .\BOMless.txt -Encoding utf8 } -UseBOMlessUTF8 | |
この例ではOut-Fileコマンドレットの出力をBOM無しUTF8にします。 | |
.EXAMPLE | |
PS C:\> Invoke-CustomEncodingBlock { "デフォルトEUC(51932)" | Out-File .\Default51932.txt -Encoding default } -DefaultCodePage 51932 | |
この例ではOut-Fileコマンドレットの出力をEUC(コードページ51932)にします。 | |
#> | |
function Invoke-CustomEncodingBlock { | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Mandatory = $true, Position = 0)] | |
[ScriptBlock]$Block, | |
[Parameter(Mandatory = $false)] | |
[Switch]$UseBOMlessUTF8 = $false, | |
[Parameter(Mandatory = $false)] | |
[int]$DefaultCodePage = [System.Text.Encoding]::Default.WindowsCodePage | |
) | |
# PowerShell 6.0ではエンコーディングの取り扱いが変わったためこの関数を使う必要が無い | |
if ($PSVersionTable.PSVersion.Major -ge 6) { | |
Write-Error "PowrShell 6.0以降でこの関数は使えません。" | |
return | |
} | |
# 変更判定 | |
$isChangeUTF8 = $UseBOMlessUTF8 | |
# * .NET Coreだと $null -eq [System.Text.Encoding]::Default なため [int]の値で比較する | |
$isChangeDefault = $DefaultCodePage -ne [int]([System.Text.Encoding]::Default.WindowsCodePage) | |
# 変更なしの場合は単純にスクリプトブロックを実行して終了 | |
if (-not $isChangeUTF8 -and -not $isChangeDefault ) { | |
$Block.Invoke() | |
return | |
} | |
try { | |
# 既定の動作を変更 | |
$type = [System.Text.Encoding] | |
if ($isChangeUTF8) { | |
$UTF8wBOM = [System.Text.Encoding]::UTF8 | |
$UTF8woBOM = New-Object "System.Text.UTF8Encoding" -ArgumentList @($false) | |
$mUTF8 = $type.GetMember("utf8Encoding", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static) | |
if ($mUTF8.Length -eq 0) { | |
throw ("Type member {0} not found." -f "utf8Encoding") | |
} | |
$mUTF8[0].SetValue($mUTF8[0], $UTF8woBOM) | |
} | |
if ($isChangeDefault) { | |
$currentDefaultEncoding = [System.Text.Encoding]::Default | |
$newDefaultEncoding = [Text.Encoding]::GetEncoding($DefaultCodePage) | |
# PS 5.0以降は System.Management.Automation.ClrFacade クラスにエンコーディングのキャッシュがあるのでここを変える | |
if ($PSVersionTable.PSVersion.Major -lt 5) { | |
$mDefault = $type.GetMember("defaultEncoding", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static) | |
if ($mDefault.Length -eq 0) { | |
throw ("Type member {0} not found." -f "defaultEncoding") | |
} | |
$mDefault[0].SetValue($mDefault[0], $newDefaultEncoding) | |
} else { | |
$asm = $MyInvocation.GetType().Assembly | |
$typeFacade = $asm.GetType("System.Management.Automation.ClrFacade") | |
# PS 5.0 - 5.1 は _defaultEncoding | |
# PS 6.0(.NET Core)だと s_defaultEncoding っぽい... | |
foreach ($name in @("_defaultEncoding", "s_defaultEncoding")) { | |
$mDefault = $typeFacade.GetMember($name, [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static) | |
if ($mDefault.Length -ne 0) { | |
break | |
} | |
} | |
if ($mDefault.Length -eq 0) { | |
throw ("Type member {0} not found." -f "defaultEncoding") | |
} | |
$mDefault[0].SetValue($mDefault[0], $newDefaultEncoding) | |
} | |
} | |
# Scriptblock実行 | |
$Block.Invoke() | |
} finally { | |
if ($isChangeUTF8) { | |
if ($null -ne $mUTF8) { | |
$mUTF8[0].SetValue($mUTF8[0], $UTF8wBOM) | |
} | |
} | |
if ($isChangeDefault) { | |
if ($null -ne $mDefault) { | |
$mDefault[0].SetValue($mDefault[0], $currentDefaultEncoding) | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# ちょっとだけテスト | |
# | |
Import-Module Pester | |
Describe "UseBOMlessUTF8パラメーターのテスト" { | |
It "BOMなしUTF8 - 最初の3ByteがBOMでないこと" { | |
$filePath = ".\BOMless.txt" | |
Invoke-CustomEncodingBlock { "BOMなしUTF8" | Out-File $filePath -Encoding utf8 } -UseBOMlessUTF8 | |
$bytes = (Format-Hex -InputObject (Get-Item $filePath)).Bytes | |
$bytes[0..2] | Should Not Be @(0xEF, 0xBB, 0xBF) | |
} | |
It "BOMなしUTF8 - ファイルの内容が正しく出力されていること" { | |
$filePath = ".\BOMless.txt" | |
Invoke-CustomEncodingBlock { "BOMなしUTF8" | Out-File $filePath -Encoding utf8 } -UseBOMlessUTF8 | |
$bytes = (Format-Hex -InputObject (Get-Item $filePath)).Bytes | |
$bytes | Should Be @(0x42, 0x4F, 0x4D, 0xE3, 0x81, 0xAA, 0xE3, 0x81, 0x97, 0x55, 0x54, 0x46, 0x38, 0x0D, 0x0A) | |
} | |
# 必ず Invoke-CustomEncodingBlock を実行した後にテストする | |
It "BOM付きUTF8 - 最初の3ByteがBOMであること" { | |
$filePath = ".\BOM.txt" | |
"BOMありUTF8" | Out-File .\BOM.txt -Encoding utf8 | |
$bytes = (Format-Hex -InputObject (Get-Item $filePath)).Bytes | |
$bytes[0..2] | Should Be @(0xEF, 0xBB, 0xBF) | |
} | |
It "BOM付きUTF8 - ファイルの内容が正しく出力されていること" { | |
$filePath = ".\BOM.txt" | |
"BOMありUTF8" | Out-File .\BOM.txt -Encoding utf8 | |
$bytes = (Format-Hex -InputObject (Get-Item $filePath)).Bytes | |
$bytes | Should Be @(0xEF, 0xBB, 0xBF, 0x42, 0x4F, 0x4D, 0xE3, 0x81, 0x82, 0xE3, 0x82, 0x8A, 0x55, 0x54, 0x46, 0x38, 0x0D, 0x0A) | |
} | |
} | |
Describe "DefaultCodePageパラメーターのテスト" { | |
It "Default変更 - ファイルの内容が正しくEUC(CP51932)になっていること" { | |
$filePath = ".\Default51932.txt" | |
Invoke-CustomEncodingBlock { "デフォルト51932" | Out-File $filePath -Encoding default } -DefaultCodePage 51932 | |
$bytes = (Format-Hex -InputObject (Get-Item $filePath)).Bytes | |
$bytes | Should Be @(0xA5, 0xC7, 0xA5, 0xD5, 0xA5, 0xA9, 0xA5, 0xEB, 0xA5, 0xC8, 0x35, 0x31, 0x39, 0x33, 0x32, 0x0D, 0x0A) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment