I’ve encountered strange error with calling command from C# code using Process.Run().
I’ve some app and this app uses similar way of executing other commands without any issues.
Now I’m writing UnitTests using MSTest library and got strange problems with the same task.
I’ve copied this to new Console project to make sure it’s not something connected with Tests project only.
Working code in my app (main parts):
Factory:
private Process CreatePowershellProcess(string args) {
_systemInfo.Validate();
if(!args.StartsWith("-Command")) {
args = "-Command " + args;
}
return new Process {
StartInfo = new ProcessStartInfo {
FileName = _systemInfo.GetShellInterpreterName(),
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
},
EnableRaisingEvents = true
};
}
Usage:
public string? ExecCommand(string command) {
var proc = _factory.CreateShellProcess(command);
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
return output;
}
Note: ProcessFactory.CreateShellProcess(string command)
is an umbrella function that on Windows (by default or on Linux if config points app should use powershell) redirects to CreatePowershellProcess()
.
For development we use only Windows machines, but in Unit Tests we also want to test executing commands on Linux. So I make up using WSL to do so.
At the begining I’m trying to check whether there is WSL enabled:
private bool IsWSLInstalled() {
return RunWslProcess("--help");
}
private bool RunWslProcess(string args) {
try {
var proc = _processFactory.CreateShellProcess("wsl.exe " + args);
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
return proc.ExitCode == 0;
} catch(Exception exc) {
Debug.WriteLine(exc.ToString());
return false;
}
}
I’ve tried many modifications of this code and it freezes the app or do what I will describe below.
To debug it I’ve created over-simplified code in new Console app project:
internal class Program {
public static void Main(string[] args) {
Console.WriteLine("Started...");
bool status = CheckWslAvaliable();
Console.WriteLine("WSL Status: " + status);
}
public static bool CheckWslAvaliable() {
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "powershell",
Arguments = "-Command wsl --help",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
process.WaitForExit();
Debug.WriteLine(output);
Debug.WriteLine(error);
Debug.WriteLine(process.ExitCode);
return process.ExitCode == 0;
}
}
The behavior of this piece of code is exactly the same as the one in unit tests.
- the process always has ExitCode = 1
- standard error is empty which suggest the command execution went well
- standard output has strange encoding like:
"Copyright (c) Microsoft Corporation.[...]"
all letters are separated by nulls and to debug only C is being print. I’ve not experienced anything like that in other places calling Process.Run(). - If I cut this “” in notepad I got desired result – normal wsl –help output.
- It’s producing the same result if I just set
FileName = "wsl"
and Arguments=”–help” - For non existing wsl switch I also got ExitCode = 1 and empty error, but output contains appropriate error message (with same wrong encoding).
- If I call
powershell -C wsl --help
orwsl --help
from: powrshell window, cmd window or Ctrl+R manu, It works fine.
Why am I always getting status code 1?
Why output here is so messy?
Why error is always empty?