how to change interface metrics of network adapters using c#? - 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.

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.

“StandardIn has not been redirected” 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.

Issue Seperate Arguments to Exe in one construct

I'm currently trying to pipe multiple parameters to the adb.exe file in the google sdk. an example of my inputs are:
adb shell getprop ro.build.version.release
adb shell getprop ro.product.brand
which are outputting correct from my application. Though, the problem is I want to populate a list view of information, the problem that i'm currently encountering though, is the method to pipe commands to get desired output. I've currently got:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Resources/adb.exe",
Arguments = "devices",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
string Output = proc.StandardOutput.ReadToEnd().ToString();
This currently returns as expected, but i'm wishing to get multiple results from piping something like:
Arguments = "devices ro.build.version.release ro.product.brand"
This provides no avail, even when piping directly into command prompt.
adb shell getprop devices ro.build.version.release ro.product.brand
empty, I have come around with a (assumingly) load heavy solution, which is to move the initialization of the executional into it's own function to be called multiple times. See code below:
public string GetInfo(string CommandArg)
{
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Resources/adb.exe",
Arguments = CommandArg,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
return proc.StandardOutput.ReadToEnd().ToString();
}
public void SetDefineInformation()
{
AndroidVersion = decimal.Parse(GetInfo("ro.build.version.release"));
DeviceModel = GetInfo("ro.product.device");
...
}
To me, this seems like a load heavy task with constantly opening a single executable for it to close then re-open until the task is complete. Is there an overall work around, which might allow one to pipe multiple parameters to an executional and get the desired results?
adb can start a shell so you could create the shell with adb shell then redirect stdin and stdout to write to it directly
No measurable performance gain would come from the "optimization" you are proposing. The adb code is pretty efficient. The overhead it introduces is very minimal. Specially in the client part. Most of the delay comes from waiting for the device's response anyway.
So stop overcomplicating things and just run multiple adb shell sessions. If loading the adb binary bothers you so much - just use sockets to talk to the adb server directly. Take a look at the Mad Bee library code to see how to do it in c#. Or just use the library.
As for optimizing querying multiple system properties - just use adb shell getprop command to pull all properties at once.

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();
}

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