“StandardIn has not been redirected” C# - c#

Below is my code. We get exception when we try to write to command line.
Process ourProc = Process.GetProcessById(id);
ourProc.StandardInput.WriteLine("echo %PATH%");
I added the below code to make redirect standadrd input true but still it does not worked.
ourProc.StartInfo.RedirectStandardInput = true;
Any help on this will be appreciated.

According to the spec, you must also set UseShellExecute = false. Also it might not work with already running processes -- it is start information that should be set before process is started.

Related

Process.Start("microsoft-edge:") throws Win32Exception in dot net core

When I execute the following line of code:
Process.Start("microsoft-edge:");
Or
Process.Start("microsoft-edge:http://localhost");
It gives me this error:
System.ComponentModel.Win32Exception: 'The system cannot find the file specified.'
When I run microsoft-edge: using Win+R it works.
When I run the same code in .net framework it works.
I'm using .netcore 3.0.0-preview6-27804-01
Any idea why this is happening?
Edit:
These are not working either:
Process.Start(#"c:\Windows\System32\LaunchWinApp.exe:http://localhost");
Process.Start(#"http://localhost");
All other executables on my system work.
Also this is working too but I can't open a specific webpage with it:
Process.Start("explorer", #"shell:Appsfolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge");
You cannot simply open a url with the expected call Process.Start("url");
You have to create a ProcessStartInfo and pass your browser and url as arguments:
Process.Start(new ProcessStartInfo("cmd", $"/c start microsoft-edge:http://localhost") { CreateNoWindow = true });
(edit) The use of ProcessStartInfo is required because we need to set its CreateNoWindow = true to prevent cmd window from showing up.
But as this code not only can be run on a Windows machine, i'd consider using something more cross-platform specific like this (https://brockallen.com/2016/09/24/process-start-for-urls-on-net-core/):
public void OpenBrowser(string url)
{
try
{
Process.Start(url);
}
catch
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
else
{
throw;
}
}
}
And call it with OpenBrowser("http://localhost");
The exact root cause is indicated here: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.useshellexecute?view=netframework-4.8
"The default is true on .NET Framework apps and false on .NET Core apps."
This means the direct solution is to set UseShellExecute. The following is basically the same as the original except making an explicit Process object to modify a setting.
Process pWeb = new Process();
pWeb.StartInfo.UseShellExecute = true;
pWeb.StartInfo.FileName = "microsoft-edge:http://localhost";
pWeb.Start();
Credit to #Lex Li and #Bizhan for their comments leading to this solution.
This variation seems to do the job as well:
Process.Start(new ProcessStartInfo("msedge") {
UseShellExecute = true,
Arguments = "http://localhost" });
It avoids the strangeness of the microsoft-edge:<url> syntax thus allowing for more chrome arguments to be passed in the usual way.
If anyone knows of a reason to avoid this, feel free to speak up :)
Windows Run window (Win+R) know how to resolve "microsoft-edge:" to the Path Of Executable. When you call it through Run window, it first resolves to the path. Then the actual executable from that path is executed.
With Process.Start, there is no this resolution of path. It only look for some paths like application path or PATH variables. Obviously, it does not find the executable to run and hence the error.
If you have a path variable declared in your system using quotes, you must fully qualify that path when starting any process found in that location. Otherwise, the system will not find the path. For example, if c:\mypath is not in your path, and you add it using quotation marks: path = %path%;"c:\mypath", you must fully qualify any process in c:\mypath when starting it.
Source
Note that command line parameters are not allowed by this overload:
This overload does not allow command-line arguments for the process. If you need to specify one or more command-line arguments for the process, use the Process.Start(ProcessStartInfo) or Process.Start(String, String) overloads.

Process.Start leaves streams empty

I have the code to run a console command/utility, monitor the live output using 'Debug.WriteLine' and write the final output to a log file when needed.
Edit: It does not work for Praatcon.exe an analysis command line utility. It can be downloaded from here . Just invoke praatcon.exe without argument, it should write on 'stdout' about the Usage. The code wont catch it.
The issue is, it works good for certain utilities and I can see the debug output as well as log in the file. But for certain utilities, I see empty commands, even though when I run those commands through a CMD window, I see the output. I am capturing both the streams Output and Error.
Can someone help me with this ?
Full code can be found here
Here is how I am trying to do it
Initialization of ProcessStartInfo
var info = new ProcessStartInfo(command, parameters)
{
WorkingDirectory = workingDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
Running the process and initializing the string builders for output and error streams.
var process = Process.Start(info);
var output = new StringBuilder();
var error = new StringBuilder();
Starting the tasks for Reading Streams
var errorTask = process.StandardError.ReadLineAsync();
var lineTask = process.StandardOutput.ReadLineAsync();
Here is my while loop to monitor the progress and write output to the Debug Output window when there is any available.
while (process.HasExited == false)
{
if (lineTask.IsCompleted)
{
output.AppendLine(lineTask.Result);
Debug.WriteLine(lineTask.Result);
lineTask = process.StandardOutput.ReadLineAsync();
}
if (errorTask.IsCompleted)
{
error.AppendLine(errorTask.Result);
Debug.WriteLine(errorTask.Result);
errorTask = process.StandardError.ReadLineAsync();
}
errorTask.Wait(TimeSpan.FromMilliseconds(100.0));
lineTask.Wait(TimeSpan.FromMilliseconds(100.0));
}
After this, I am reading the streams further to see if there is anything left in there.
I get empty strings in output and error for one command. The only thing I get correct is the 'ExitCode'.
Please tell me if there is anything I am doing the wrong way.
As discussed on IRC, there was a possibility that the program you're calling may have been writing to a stream other than standard out or standard error. There are also streams with numbers 3-9 on Windows.
This was not the case with the process you were calling. It was actually using the Win32 call 'WriteConsole', which seems to access the console directly.
It would be possible to move the output back to stderr by preloading a DLL (DLL injection) but this is hackish, so as the source of the program is available, it's perhaps better to 'fix' it or submit a patch to the authors.
Your question is borderline too broad, in that it's missing details, and "anything I am doing the wrong way" is fairly open-ended.
That said, you are doing the reading of the streams the wrong way, in the sense that you should not be polling. I don't see any specific reason that would cause the behavior you've (vaguely) described. But just in case, I offer this correct implementation of the reading:
async Task ConsumeStream(StreamReader reader, StringBuilder builder)
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
builder.AppendLine(line);
Debug.WriteLine(line);
}
}
Then call that method like this:
var errorTask = ConsumeStream(process.StandardError, error);
var lineTask = ConsumeStream(process.StandardOutput, output);
// Technically superfluous, since you'll also wait on the tasks,
// but won't hurt.
process.WaitForExit();
Task.WaitAll(errorTask, lineTask);
// error and output StringBuilders will be valid here
If that doesn't help, you'll need to post a better code example, which will allow others to reproduce the actual problem. See https://stackoverflow.com/help/mcve

OS Command Injection from Process.Start

My application is using Process.Start for opening another application to run. VeraCode [a security software scanning tool] reported this command as OS Command Injection Vulnerable. I would like to get some comment. I have found a lot of information on the web regarding to filter the input or to constraint the program name; however, I am curious to see if there's any other alternatives of using Process.Start?
Edit:
Thanks for the comment, here is one of the sample, and yes, it is getting input from users:
public static void Run(string fileName, string arguments, bool waitForExit)
{
Process p = Process.Start(fileName, arguments);
if (waitForExit)
p.WaitForExit();
}
Thanks!
This is a command injection vulnerability because you have not filtered out the users input from the function and directly appended to the process.start()
Due to this, the tool has marked it as a vulnerability.
To avoid this issue you should use regex method to filter out the bad characters and depending on what that function is going to do when it gets run.
for eg. you function is created only to check from this path c:/users/docs.txt
then that function should not get executed for c:/admin/docs.txt.
This is how you need to validate before sending the user data directly into the process.
For more information refer this awesome link : https://dotnet-security-guard.github.io/SG0001.htm
or
https://www.veracode.com/security/dotnet/cwe-78
The Process class is nothing else then a Managed wrapper class the the Native Create Process and its Variations like Create Process As User .
Process MSDN
Process
SourceCode
I don't think that there is another way to start a process than this, because every other solution would also call the WinAPI function. ( because this function (or its overloads and Variations) is the only way to start a process in Windows).
Personally, I have not heard anything about a problem with Process.Start please clarify the problem
regards
I ran into this as well. You need to set the UseShellExecute property to false. Then Veracode will not consider it a vulnerability.
using (WinProcess myProcess = new WinProcess())
{
myProcess.StartInfo.FileName = "notepad.exe";
myProcess.StartInfo.Arguments = Path.GetFileName(fullPath);
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(fullPath);
myProcess.StartInfo.RedirectStandardOutput = false;
myProcess.Start();
}

how to change interface metrics of network adapters using c#?

In relation to the link below
https://stackoverflow.com/questions/5577406/enable-both-lan-intranet-and-usb-internet
Is there a way to do it using a c# programmatically ?
Here is a Code Project article that shows you how to do it:
http://www.codeproject.com/KB/IP/winnetstat.aspx
Basically, you use the IP Helper API and the SetIpForwardEntry method to accomplish this.
Here is an article that walks you through how to implement it (with accompanying code):
http://www.developer.com/ws/pc/article.php/10947_3415521_2/IP-Helper-API-ARP-Routing-and-Network-Statistics.htm
Though the question was answered about 7 years ago, I found a VERY easy way to do this in C# using netsh.exe.
This only works if you are running your program as administrator.
The command is:
netsh.exe interface ipv4 set interface "myNICsName" metric=20
To set the metric to 'Automatic' just set it to 0.
The high limit is 9999, but if you use something higher, it will just set it to 9999 for you.
To do this programatically, just use Process.Start in the following way:
System.Diagnostics.Process p = new System.Diagnostics.Process
{
StartInfo =
{
FileName = "netsh.exe",
Arguments = $"interface ipv4 set interface \"{nicName}\" metric={metric}",
UseShellExecute = false,
RedirectStandardOutput = true
}
};
bool started = p.Start();
if (started)
{
if (SpinWait.SpinUntil(() => p.HasExited, TimeSpan.FromSeconds(20)))
{
Log.Write($"Successfully set {nicName}'s metric to {metric}");
Log.Write($"Sleeping 2 seconds to allow metric change on {nicName} to take effect.");
Thread.Sleep(2000);
return true;
}
Log.Write($"Failed to set {nicName}'s metric to {metric}");
return false;
}
The above code also does some error checking to make sure the process indeed started and puts in a short delay so that the metric change can have a chance to take effect. I found that I had some problems in my code when I didn't include the delay.

Getting output from one executable in an other one

I'm currently trying to get the output of an executable console-app into an other one. To be exact, a little overview of what I'm trying to do:
I have one executable which I cannot edit and neither see it's code. It writes some (quite a bunch to be honest) lines into the console when executed.
Now I want to write another executable that starts the one above and reads the things it writes.
Seems simple to me, so I started coding but ended up with an error message saying that StandardOut has not been redirected or the process hasn't started yet.
I tried it using this kinda structure (C#):
Process MyApp = Process.Start(#"C:\some\dirs\foo.exe", "someargs");
MyApp.Start();
StreamReader _Out = MyApp.StandardOutput;
string _Line = "";
while ((_Line = _Out.ReadLine()) != null)
Console.WriteLine("Read: " + _Line);
MyApp.Close();
I can open the executable and it also does open the one inside, but as soon as it comes to reading the returned values, the app crashes.
What am I doing wrong?!
Take a look at the documentation for the Process.StandardOutput property. You will need to set a boolean indicating that you want the stream redirected as well as disabling shell execute.
Note from the documentation:
To use StandardOutput, you must set ProcessStartInfo..::.UseShellExecute to false, and you must set ProcessStartInfo..::.RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception
You would need to change your code a little bit to adjust for the changes:
Process myApp = new Process(#"C:\some\dirs\foo.exe", "someargs");
myApp.StartInfo.UseShellExecute = false;
myApp.StartInfo.RedirectStandardOutput = false;
myApp.Start();
string output = myApp.StandardOutput.ReadToEnd();
p.WaitForExit();
you could try setting processStartInfo.RedirectStandardOutput = true;
As noted above, you can use RedirectStandardOutput as here.
Another, dirtier way is something like
using (Process child = Process.Start
("cmd", #"/c C:\some\dirs\foo.exe someargs > somefilename"))
{
exeProcess.WaitForExit();
}
And then read its output from somefilename

Categories