Sortie UTF-8 de PowerShell
je suis en train d'utiliser Process.Start
avec I/O redirigé vers call PowerShell.exe
avec une chaîne, et pour obtenir la sortie arrière, le tout dans UTF-8. Mais je ne semble pas être en mesure de faire ce travail.
Ce que j'ai essayé:
- passer la commande pour exécuter via le
-Command
paramètre - Écrit le script PowerShell en tant que fichier sur le disque avec l'encodage UTF-8
- Écrit le script PowerShell en tant que fichier sur le disque avec de l'UTF-8 avec BOM encodage
- Écrit le script PowerShell en tant que fichier sur le disque avec de l'UTF-16
Console.OutputEncoding
dans mon application console et dans le script PowerShell$OutputEncoding
dans PowerShellProcess.StartInfo.StandardOutputEncoding
- le Faire avec
Encoding.Unicode
au lieu deEncoding.UTF8
dans tous les cas, quand j'inspecte les octets qui m'ont été donnés, j'obtiens des valeurs différentes de ma chaîne originale. J'aimerais vraiment un explication des raisons pour lesquelles cela ne fonctionne pas.
Voici mon code:
static void Main(string[] args)
{
DumpBytes("Héllo");
ExecuteCommand("PowerShell.exe", "-Command "$OutputEncoding = [System.Text.Encoding]::UTF8 ; Write-Output 'Héllo';"",
Environment.CurrentDirectory, DumpBytes, DumpBytes);
Console.ReadLine();
}
static void DumpBytes(string text)
{
Console.Write(text + " " + string.Join(",", Encoding.UTF8.GetBytes(text).Select(b => b.ToString("X"))));
Console.WriteLine();
}
static int ExecuteCommand(string executable, string arguments, string workingDirectory, Action<string> output, Action<string> error)
{
try
{
using (var process = new Process())
{
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = workingDirectory;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
using (var outputWaitHandle = new AutoResetEvent(false))
using (var errorWaitHandle = new AutoResetEvent(false))
{
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error(e.Data);
}
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
outputWaitHandle.WaitOne();
errorWaitHandle.WaitOne();
return process.ExitCode;
}
}
}
catch (Exception ex)
{
throw new Exception(string.Format("Error when attempting to execute {0}: {1}", executable, ex.Message),
ex);
}
}
mise à Jour de 1
j'ai trouvé que si je fais ce script:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Write-Host "Héllo!"
[Console]::WriteLine("Héllo")
puis l'invoquer via:
ExecuteCommand("PowerShell.exe", "-File C:UsersPaulDesktopFoo.ps1",
Environment.CurrentDirectory, DumpBytes, DumpBytes);
la première ligne est corrompue, mais la seconde ne l'est pas:
H?llo! 48,EF,BF,BD,6C,6C,6F,21
Héllo 48,C3,A9,6C,6C,6F
ceci me suggère que mon code de redirection fonctionne très bien; quand j'utilise Console.WriteLine
en PowerShell J'obtiens UTF-8 comme je m'y attendais.
Cela signifie que Powershell's Write-Output
et Write-Host
les commandes doivent faire quelque chose de différent avec la sortie, et pas simplement appeler Console.WriteLine
.
mise à Jour 2
j'ai même essayé ce qui suit pour forcer la page de code de la console PowerShell à UTF-8, mais Write-Host
et Write-Output
continuer à produire des résultats brisés tout en [Console]::WriteLine
fonctionne.
$sig = @'
[DllImport("kernel32.dll")]
public static extern bool SetConsoleCP(uint wCodePageID);
[DllImport("kernel32.dll")]
public static extern bool SetConsoleOutputCP(uint wCodePageID);
'@
$type = Add-Type -MemberDefinition $sig -Name Win32Utils -Namespace Foo -PassThru
$type::SetConsoleCP(65001)
$type::SetConsoleOutputCP(65001)
Write-Host "Héllo!"
& chcp # Tells us 65001 (UTF-8) is being used
4 réponses
ceci est un bug .NET. Lorsque PowerShell se lance, il cache la poignée de sortie (Console.Hors.) La propriété Encoding de cet auteur de texte ne prend pas la propriété Value StandardOutputEncoding.
lorsque vous le Modifiez depuis PowerShell, la propriété Encoding du rédacteur de sortie en cache renvoie la valeur en cache, de sorte que la sortie est toujours encodée avec l'encodage par défaut.
comme solution de contournement, je suggérerais de ne pas changer l'encodage. Il sera retourné à vous en tant que chaîne Unicode, à ce moment vous pouvez gérer l'encodage vous-même.