J'essaie d'utiliser Process.Start
avec les E/S redirigées pour appeler PowerShell.exe
avec une chaîne et pour obtenir la sortie, le tout dans UTF-8 . Mais je ne semble pas être capable de faire ce travail.
Ce que j'ai essayé
-Command
Console.OutputEncoding
dans mon application de console et dans le script PowerShell$OutputEncoding
dans PowerShellProcess.StartInfo.StandardOutputEncoding
Encoding.Unicode
au lieu de Encoding.UTF8
Dans tous les cas, lorsque j'inspecte les octets qui me sont attribués, ma chaîne d'origine reçoit des valeurs différentes. J'aimerais vraiment une explication quant à pourquoi 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);
}
}
J'ai trouvé que si je fais ce script:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Write-Host "Héllo!"
[Console]::WriteLine("Héllo")
Puis invoquez-le via:
ExecuteCommand("PowerShell.exe", "-File C:\\Users\\Paul\\Desktop\\Foo.ps1",
Environment.CurrentDirectory, DumpBytes, DumpBytes);
La première ligne est corrompue, mais la seconde n'est pas:
H?llo! 48,EF,BF,BD,6C,6C,6F,21
Héllo 48,C3,A9,6C,6C,6F
Cela me suggère que mon code de redirection fonctionne correctement; Lorsque j'utilise Console.WriteLine
dans PowerShell, je reçois le format UTF-8, comme je l’attendais.
Cela signifie que les commandes Write-Output
et Write-Host
de PowerShell doivent faire quelque chose de différent avec la sortie et ne pas simplement appeler Console.WriteLine
.
J'ai même essayé ce qui suit pour forcer la page de codes de la console PowerShell à UTF-8, mais Write-Host
et Write-Output
continuent de produire des résultats cassés tant que [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
C'est un bogue dans .NET. Lorsque PowerShell est lancé, il met en cache le descripteur de sortie (Console.Out). La propriété Encoding de ce rédacteur de texte ne sélectionne pas la propriété ValueOutputEncoding.
Lorsque vous le modifiez depuis PowerShell, la propriété Encoding de l'enregistreur de sortie mis en cache renvoie la valeur mise en cache, de sorte que la sortie est toujours encodée avec l'encodage par défaut.
En guise de solution de contournement, je suggère de ne pas modifier le codage. Il vous sera renvoyé sous forme de chaîne Unicode. Vous pourrez alors gérer vous-même l'encodage.
Exemple de mise en cache:
102 [C:\Users\leeholm]
>> $r1 = [Console]::Out
103 [C:\Users\leeholm]
>> $r1
Encoding FormatProvider
-------- --------------
System.Text.SBCSCodePageEncoding en-US
104 [C:\Users\leeholm]
>> [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
105 [C:\Users\leeholm]
>> $r1
Encoding FormatProvider
-------- --------------
System.Text.SBCSCodePageEncoding en-US
Pas un expert en encodage, mais après avoir lu ces ...
... il semble assez clair que la variable $ OutputEncoding affecte uniquement les données acheminées vers des applications natives.
Si vous envoyez un fichier depuis PowerShell vers un fichier, le codage peut être contrôlé par le paramètre -encoding
de la cmdlet out-file
, par exemple.
write-output "hello" | fichier "enctest.txt" codant utf8
Rien d’autre que vous ne puissiez faire sur le front PowerShell alors, mais le post suivant pourrait bien vous aider:.
Définissez le [Console]::OuputEncoding
comme encodant ce que vous voulez et imprimez-le avec [Console]::WriteLine
.
Si la méthode de sortie powershell a un problème, ne l'utilisez pas. Ça fait un peu mal, mais ça marche comme un charme :)
J'ai passé du temps à chercher une solution à mon problème et j'ai pensé que cela pourrait être intéressant. J'ai rencontré un problème en essayant d'automatiser la génération de code à l'aide de PowerShell 3.0 sous Windows 8. La cible IDE était le compilateur Keil utilisant MDK-ARM Essential Toolchain 5.24.1. Un peu différent de OP, car j'utilise PowerShell de manière native lors de l'étape de pré-construction. Quand j'ai essayé d'inclure # le fichier généré, j'ai reçu l'erreur
erreur fatale: la marque d'ordre d'octet UTF-16 (LE) a été détectée '..\GITVersion.h' mais l'encodage n'est pas supporté
J'ai résolu le problème en modifiant la ligne qui a généré le fichier de sortie à partir de:
out-file -FilePath GITVersion.h -InputObject $result
à:
out-file -FilePath GITVersion.h -Encoding ascii -InputObject $result