Im currently trying to run openVPN from a CMD that is programatically created.
Below is the code that I have created:
private void btnRunVpn_Click(object sender, EventArgs e)
{
string openVpnDir = #"""C:\Program Files\OpenVPN\bin\openvpn.exe""";
string myDir = #"""C:\Users\Jeremy\Desktop\OpenSource Rat\easyRDPClient\TutClient\bin\Debug\NewServerClient.ovpn""";
string configCommand = " --config ";
string command = openVpnDir + configCommand + myDir;
System.Diagnostics.Process.Start("CMD.exe", "/K " + command);
MessageBox.Show(command);
}
The message box displays the correct Command:
"C:\Program Files\OpenVPN\bin\openvpn.exe" --config "C:\Users\Jeremy\Desktop\OpenSource Rat\easyRDPClient\TutClient\bin\Debug\NewServerClient.ovpn"
However the command prompt is returning:
'C:\Program' is not recognized as an internal or external command, operable program or batch file.
The command is deffinatly correct because the message box that displays the command is correct, also when i copy what is in the message box into the command prompt it works perfectly.
wondering if it is anything to do with the two strings created that both have #"""message""" to display the message correctly. Wondering if that is the issue.
I can't seem escape the double quotes properly because it is a directory. So Im forced to use the #"""test""" to display a command like this "test"
Wondering if anyone understands this a little more than I do.
Would be great help.
Thankyou in advance!
I believe this will do what you are hoping to accomplish. It should leave the command line open, and correct the issue where the quotes are removed.
In the sample below, I added quotes around the command variable in the Start command.
private void btnRunVpn_Click(object sender, EventArgs e)
{
string openVpnDir = #"""C:\Program Files\OpenVPN\bin\openvpn.exe""";
string myDir = #"""C:\Users\Jeremy\Desktop\OpenSource Rat\easyRDPClient\TutClient\bin\Debug\NewServerClient.ovpn""";
string configCommand = " --config ";
string command = openVpnDir + configCommand + myDir;
System.Diagnostics.Process.Start("CMD.exe", "/K " + "\"" + command + "\"");
MessageBox.Show(command);
}
What I believe is happening is the CMD /K is expecting 1 argument. Since you are passing multiple, it is only looking at the first one (and removes the quotes when it does). This leaves it with:
C:\Program Files\OpenVPN\bin\openvpn.exe
It then cannot locate the application because of the space in the path.
By wrapping the entire command in quotes, it forces CMD to treat it as a single argument. It then removes the outer quotes and processes the desired command.
I tried it with Notepad in VB.NET, so hopefully I adjusted it correctly for your scenario.
Related
Plan
The plan is to disable and subsequently enable a device from inside a windows forms application. To test the first building block of my plan, I open cmd with admin privileges and the following works perfectly:
> devcon hwids =ports
> devcon hwids *VID_10C4*
> devcon disable *VID_10C4*
> devcon enable *VID_10C4*
I can see the device being disabled and enabled again in device manager.
I can also achieve all of this by putting the commands into a batch file and running it from cmd with admin privileges. The above tells me that my plan is essentially good.
Application
However, what I actually want to do is achieve the same thing from inside a windows forms application:
I've set the following in the app manifest:
requestedExecutionLevel level="requireAdministrator" uiAccess="false"
For the sake of baby steps, I have checked this, just to ensure that there are no stupid mistakes in paths and whatnot. And it works just fine. The log file shows me the expected output from the dir command.
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && dir " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
However, this does not work. It always returns an empty log file and does not change the device as expected:
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && devcon hwids =ports " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
Error from cmd window is :
'devcon' is not recognized as an internal or external command,
operable program or batch file.
What's going on?
The above has me stumped. I've proved the commands work. I've proved my C# code works. But when I join the 2 together, it doesn't work...
NB: My C# program is running on my D: drive, if that makes any difference...
Updates Based on Comments
#Compo
Using your code, it does exactly the same as with mine. I see an empty log file & no changes made to the device. I've altered the /c to /k so I can see what going on the cmd terminal and I see this:
I've even tried your code C:\\Windows\\System32\\devcon hwids =usb pointing directly at devcon. Also tried \devcon.exe for completeness. The inexplicable error is :
I can see the flipping devcon.exe file sitting right there in the folder! Is there any reason it would not recognise it?
Also, with the command as you wrote it, the log file name is actually named logFileEnablePrt.txt'. I agree that your command looks right, so don't ask me why this happens!
#Panagiotis Kanavos
using your code, I get the following error:
This is at the line p.Start();. I tried putting in devcon.exe, and even the whole path (I checked the folder was in my PATH, and it is). Can't get past this. I actually stumbled on that answer you shared and arrived at this brick wall already.
Here is the code works for me, I don't have ports devices so I change it to usb.
public static void Main()
{
string prodPath = #"c:\devcon\x64";
// Build String
string strCmdText =
"/c \"cd /d " + prodPath +
" && devcon hwids =usb " +
" > log.txt \"";
// Run command
var p = new Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
}
Worked through a few steps and think I may have an answer...
Just specifying devcon fails as expected...windows cant find the exe as the folder it is in is not in the %PATH% variable in windows..
IF I specify the full path however it works...
It wasnt clear from your original code but if your copy of devcon is sitting in either System32 or Syswow directories you may be hitting an emulation issue as well...see here....
EDIT1:: A way to prove this would be to do Direcory.GetFiles(directory containing devcon) and see if the results line up with what you expect
As for passing arguments through to devcon I'd try something like this as opposed to trying to concatenate one giant cmd line..
A similar example but with netstat:
EDIT 2::Another example but with devcon:
The target platform here for the build was x64
EDIT3::
With my application build set to x86:
After working through the answers and comments above, I seem to have something that reliably works, which obviously I'd like to share back for scrutiny and future use.
So, my function ended up looking like this:
private int enablePort(string action)
{
while (true)
{
// Command Arg
string devconPath = #"c:\Windows\SysNative";
string strCmdText =
"'/c \"cd /d \"" +
devconPath +
"\" && c:\\Windows\\SysNative\\devcon " + action + " *VID_10C4* " +
"> \"" + prodPath + "\\logs\\logFileEnablePrt.txt\"\"";
// Process
var p = new Process();
var psi = new ProcessStartInfo()
{
Arguments = strCmdText,
Verb = "runas",
FileName = "CMD.exe",
UseShellExecute = true
};
p.StartInfo = psi;
p.Start();
p.WaitForExit();
// Grab log output
string logPath = prodPath + "\\logs\\logFileEnablePrt.txt";
Console.WriteLine("logPath = " + logPath);
string tempFile = System.IO.File.ReadAllText(logPath);
System.Console.WriteLine("Contents of WriteText.txt = \n{0}", tempFile);
// Check if it worked
var success = false;
if (tempFile.Contains(action))
{
success = true;
return 0;
}
// Error -> Allow user to try again!
if (MessageBox.Show("Was unable to " + action + " Test Jig COM port. Unlug & Replug USB. Check COM port is enabled if not working.", "COM Port Problem", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return -1;
}
}
}
And the calling code was:
this.enablePort("disable");
int milliseconds = 3000;
await Task.Delay(milliseconds);
this.enablePort("enable");
As you can see in the code above, I've logged everything to see what was going on... Stepping through with the debugger, I can now see after the disable:
USB\VID_10C4&PID_EA60\0001 : Disabled
1 device(s) disabled.
And then after the enable:
USB\VID_10C4&PID_EA60\0001 : Enabled
1 device(s) are enabled.
The one extra thing I need to stress is that during testing, I thought I could hook a serial peripheral onto the port and determine whether it could disable and enable successfully by checking the connection. THIS DOES NOT WORK. The above code only works when the port is idle. Perhaps someone who understands the underlying software could hazard an explanation of why this is.
I would like to execute a cqlsh copy command from c# source code. I would like to execute a Python script, which exists under the folowing path:
C:\Program Files\DataStax Community\python\python.exe" "C:\Program Files\DataStax Community\apache-cassandra\bin\cqlsh.py
That will give me this screenshot:
Once in cqlsh, I can then run the command "copy emp to emp.csv"
The idea, is that I would like to execute all this from c# code. Here is what I did:
try
{
Process p = new Process(); // create process (i.e., the python program
p.StartInfo.FileName = #"C:\Python27\python.exe";
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false; // make sure we can read the output from stdout
p.StartInfo.Arguments = #"C:\Program Files\DataStax Community\apache-cassandra\bin\cqlsh.py" + " " + "-e copy key_space.emp to 'D:/emp.csv'"; // start the python program with two parameters
p.Start(); // start the process (the python program)
p.WaitForExit();
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
string strError = ex.Message;
}
There is no exception caught but also there is nothing happened in term of result.
Any help would be appreciated .
I'm pretty sure your problem is with this line:
bin\cqlsh.py" + " " + "copy emp to D:/emp.csv";
If you were to run this from the command line, cqlsh would require the -e flag to execute a command. In Windows it'd look something like this (assuming a keyspace name of "your_keyspace":
python bin\cqlsh.py -e "copy your_keyspace.emp to d:\emp.csv"
So to actually call that from your process, you would either have to escape the double quotes or just use single quotes:
bin\cqlsh.py" + " " + "-e 'copy your_keyspace.emp to d:\emp.csv'";
I want to write a command like pushd \172.x.x.x\something\something using c#. I just want to map the network path on the local machine using pushd. If I am doing the same by explicitly open the cmd n typing the pushd command , it is connecting the network path on the local machine. I want to do it by using c#.Any help would be appreciated. Below is my code :
private void button2_Click(object sender, EventArgs e)
{
string strCmdText;
strCmdText = "pushd" + #"\172.x.x.x\something\something";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
}
There's a space missing between 'pushd' and the second argument.
Change it to something like this:
strCmdText = "pushd" + " " + #"\172.x.x.x\something\something";
Does it help specifying /C or /K first in strCmdText?
Does it help using double backslash: \\172.x.x.x
I have definitely done something like this before, but something is not working right and I'm not 100% sure what it is.
I have an executable executable.exe that takes a file, does some magic and outputs a second file somewhere else. So when I run this executable via CMD, all I need to do is pass "path1" and "path2". I put the paths in quotations because they may have spaces.
Anyway, so what I'm doing in my c# application is something like:
public void methodToRunExecutable()
{
var exePath = "\""+ "C:\\SomePathToAnExecutable" + "\"";
var firstFilePath = "C:\\PathToFirstFile\\NameOfFile.txt"
var secondFilePath= "C:\\PathToSecondFile\\NameOfFile.txt"
Process.Start(exePath, "\""firstFilePath + "\" \"" + secondFilePath+"\"")
}
However, I notice when I'm debugging is that the "\"" is actually showing up as \", like the backslash isn't escaping the quotation mark.
To be clear, when I run the CMD exe all I have to do is:
"C:\\PathToFirstFile\\NameOfFile.txt" "C:\\PathToSecondFile\\NameOfFile.txt"
and it works great. Any Ideas on what I'm doing wrong? Is it because the " is not being escaped?
Escaping is ugly and error prone. Use # and you won't need to escape:
var firstFilePath = #"C:\PathToFirstFile\NameOfFile.txt"
It might also be easier to use Process this way:
using (Process process = new Process())
{
process.StartInfo.FileName = exePath;
process.StartInfo.Arguments = ""; // args here
process.Start();
}
I want to merge all the files in a directory into one. However I tried several versions but none of them seem to work. I am getting an error saying that the file was not found. Here is what I was trying:
String outputFile = this.outputTxt.Text;
String inputFolder = this.inputTxt.Text;
String files = "";
String command;
foreach (String f in Directory.GetFiles(inputFolder))
{
files += f+"+";
}
files = files.Substring(0, files.Length - 1);
command = files + " " + outputFile;
Process.Start("copy",command);
sample of what I want to obtain:
copy a.txt+b.txt+c.txt+d.txt output.txt
And the error I get is:
An unhandled exception of type 'System.ComponentModel.Win32Exception' occurred in System.dll
Additional information: The system cannot find the file specified
Try starting cmd rather than "start" with process.
Process.Start("cmd", "copy " + command);
'copy' is a command in the command prompt, aliased to... something, and not an actual file itself that windows knows how to run (outside of the command prompt).
There are properties of the Process class that you can use to suppress the window that the shell pops up if you don't want it on the screen while the program is running.
Should you not be using command instead of files for your second parameter to Process.Start?
Process.Start("copy", command);
UPDATE:
Ok, so it was a typo. How about your inputFolder text? Is it using double back-slashes for the directories (escaping the back-slashes)? As in all \ characters should be \\.
You need to call cmd.exe with the copy command and your arguments (as was mentioned by #Servy). Here is a cleaned up version of your code to do what you need:
String outputFile = this.outputTxt.Text;
String inputFolder = this.inputTxt.Text;
StringBuilder files = new StringBuilder();
foreach (String f in Directory.EnumerateFiles(inputFolder))
{
files.Append(f).Append("+");
}
files = files.Remove(file.Length-1, 1); // Remove trailing plus
files.Append(" ").Append(outputFile);
using (var proc = Process.Start("cmd.exe", "/C copy " + files.ToString()))
{
proc.WaitForExit();
}
You need to dispose of the Process (thus the using statement) and since you are concatenating a lot of strings (potentially a lot of strings anyway), you should use a StringBuilder.