文件不包含字符,它们包含字节。要从字节中获取字符,您需要应用一些编码。如果你对相同的字节应用不同的编码,那么你可以在结果中得到不同的字符。
以你的字节串为例:
PS> $ByteArray = [Byte[]]('24-4D-65-73-73-61-67-65-20-3D-20-5B-49-4F-2E-46-69-6C-65-5D-3A-3A-52-65-61-64-41-6C-6C-54-65-78-74-28-22-24-50-53-53-63-72-69-70-74-52-6F-6F-74-5C-F0-F3-F1-F1-EA-E8-E9-2E-74-78-74-22-2C-20-5B-53-79-73-74-65-6D-2E-54-65-78-74-2E-45-6E-63-6F-64-69-6E-67-5D-3A-3A-44-65-66-61-75-6C-74-29-0D-0A-24-4D-65-73-73-61-67-65' -split '-' | % { [Byte]::Parse($_, 'HexNumber') })
PS> [Text.Encoding]::UTF8.GetString($ByteArray)
$Message = [IO.File]::ReadAllText("$PSScriptRoot\�������.txt", [System.Text.Encoding]::Default)
$Message
PS> [Text.Encoding]::GetEncoding(1251).GetString($ByteArray)
$Message = [IO.File]::ReadAllText("$PSScriptRoot\русский.txt", [System.Text.Encoding]::Default)
$Message
PS> [Text.Encoding]::GetEncoding(1252).GetString($ByteArray)
$Message = [IO.File]::ReadAllText("$PSScriptRoot\ðóññêèé.txt", [System.Text.Encoding]::Default)
$Message
读取文件时使用正确的编码很重要。需要注意的一件重要事情是,您的脚本文件使用代码页 1251,而不是 UTF-8。另请注意,根据 UTF-8,字节序列 F0-F3-F1-F1-EA-E8-E9(在代码页 1251 中代表世界 русский)是无效的字节序列,因此您将获得七个替换字符(U+FFFD)。
由于 PowerShell Core 默认使用 UTF-8 并且您的脚本文件没有 BOM 来指示其他情况(尽管没有可以使 PowerShell 识别代码页 1251 的 BOM),PowerShell Core 使用 UTF-8 编码读取您的文件,因此它试图访问�������.txt(你没有)而不是русский.txt。
如果您将脚本更改为写入文件而不是读取文件,您可以自己轻松观察。
PS> $ByteArray2 = [Byte[]](91, 73, 79, 46, 70, 105, 108, 101, 93, 58, 58, 87, 114, 105, 116, 101, 65, 108, 108, 84, 101, 120, 116, 40, 34, 36, 80, 83, 83, 99, 114, 105, 112, 116, 82, 111, 111, 116, 92, 240, 243, 241, 241, 234, 232, 233, 46, 116, 120, 116, 34, 44, 32, 91, 68, 97, 116, 101, 84, 105, 109, 101, 93, 58, 58, 85, 116, 99, 78, 111, 119, 41)
PS> # Representing `[IO.File]::WriteAllText("$PSScriptRoot\русский.txt", [DateTime]::UtcNow)` in codepage 1251
PS> [IO.File]::WriteAllBytes("$(Convert-Path .)\write.ps1", $ByteArray2)
PS> .\write.ps1
现在您可以使用原始脚本读回文件:
PS> [IO.File]::WriteAllBytes("$(Convert-Path .)\asd.ps1", $ByteArray)
PS> .\asd.ps1
01/18/2019 17:13:15
使用 PowerShell Core 调用这两个脚本:
PS> pwsh -Command ".\write.ps1; .\asd.ps1"
01/18/2019 17:21:02
如您所见,您的脚本已在 PowerShell Core 中成功执行。如果您浏览当前目录,那么您可以看到,它同时包含русский.txt 和�������.txt,并且它们的内容匹配,即控制台上打印的内容。
实际上这个问题与读/写文件有关(脚本文件本身除外)。可以用简单的脚本来演示,只打印字符串文字的字符代码:
PS> $ByteArray3 = [Byte[]](40, 39, 240, 243, 241, 241, 234, 232, 233, 39, 46, 71, 101, 116, 69, 110, 117, 109, 101, 114, 97, 116, 111, 114, 40, 41, 32, 124, 32, 37, 32, 84, 111, 73, 110, 116, 51, 50, 32, 36, 110, 117, 108, 108, 32, 124, 32, 37, 32, 84, 111, 83, 116, 114, 105, 110, 103, 32, 88, 52, 41, 32, 45, 106, 111, 105, 110, 32, 39, 45, 39)
PS> # Representing `('русский'.GetEnumerator() | % ToInt32 $null | % ToString X4) -join '-'` in codepage 1251
PS> [IO.File]::WriteAllBytes("$(Convert-Path .)\test.ps1", $ByteArray3)
在 Windows PowerShell 中调用它会产生一个结果:
PS> .\test.ps1
0440-0443-0441-0441-043A-0438-0439
而 PowerShell Core 会产生不同的:
PS> pwsh -Command ".\test.ps1"
FFFD-FFFD-FFFD-FFFD-FFFD-FFFD-FFFD
解决此问题的一种方法是将 UTF-8 与 BOM 结合使用,以确保 Windows PowerShell 和 PowerShell Core 在读取脚本文件时使用相同的编码。
答案是假设 [Text.Encoding]::Default.CodePage 返回 1251,就像 OP 的情况一样。