Input Username to cmd Process
In my Winform app, I execute a exe file using cmd Process. The exe file needs to input username and passowrd on line "Enter Username" & "Enter Password". I am not able to input the username and password, somehow the process gets exited only and doesn't work out only. I added checking of ThreadState and WaitReason also, but there are no threads in process.Threads. I also need the output. If I type output before input process, then it doesn't reach till input and if I put input before output, then also the input is not accepeted or so. Just receive the output same all time. Here is the code :
public bool StartOpenVPN()
{
bool installed = false;
ProcessStartInfo processInfo = null;
Process process = null;
try
{
string command = "files\\openvpn --config files\\client.ovpn";
Console.WriteLine("Command = " + command);
processInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
processInfo.UseShellExecute = false;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = true;
Console.WriteLine("Opening cmd");
process = new Process();
process.StartInfo = processInfo;
process.Start();
StreamWriter sw = process.StandardInput;
sw.WriteLine("foo");
sw.WriteLine("*baa");
sw.Flush();
sw.Close();
process.BeginOutputReadLine();
process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
Console.WriteLine("Finished cmd");
}
catch (Exception e)
{
Console.WriteLine("Errror Installing Tap Adapter : " + e.Message);
Console.WriteLine(e.StackTrace);
}
finally
{
processInfo = null;
if (process != null)
{
process.Close();
process = null;
}
}
return installed;
}
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
string d = e.Data;
if (!string.IsNullOrEmpty(d))
{
Console.WriteLine("Line = " + d);
}
}
The only output I get is :
Line = Wed Mar 09 12:33:00 2011 OpenVPN 2.1.1 开发者_如何学编程i686-pc-mingw32 [SSL] [LZO2] [PKCS11] built on Feb 17 2010
Line = Wed Mar 09 12:33:00 2011 ERROR: could not read Auth username from stdin
Line = Wed Mar 09 12:33:00 2011 Exiting
Why it doesn't accept the input or even show the line "Enter Username" in output ? I can't makeout where am I going wrong, but it seems am going wrong somewhere. Kindly help me with this issue am stuck badly and have tried many times and things and have spent lots of time after this.
Any help is highly appreciated.
Thanks
@Fun Mun : here is the updated code. It just goes to process_Exited on getting any stream input/output :
private void initProcess()
{
processInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
processInfo.UseShellExecute = false;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = true;
processInfo.WindowStyle = ProcessWindowStyle.Normal;
process = new Process();
process.StartInfo = processInfo;
process.Exited += new EventHandler(process_Exited);
return;
}
void process_Exited(object sender, EventArgs e)
{
Console.WriteLine("Into process_Exited....");
processInfo = null;
if (process != null)
{
sw = null;
process.Close();
process = null;
}
}
public bool StartOpenVPN()
{
bool installed = false;
try
{
Console.WriteLine("Command = " + command);
Console.WriteLine("Opening cmd");
initProcess();
process.Start();
sw = process.StandardInput;
Console.WriteLine("Has Exited after SW = " + process.HasExited.ToString()); // RETURS FALSE BUT GOES TO process_Exited & for next line results is NullPointerException
sw.WriteLine("foo");
sw.WriteLine("*baa");
//sw.Flush();
//sw.Close();
//process.BeginOutputReadLine();
//process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
while (process.HasExited == false)
{
string d = process.StandardOutput.ReadLine();
Console.WriteLine("Line = " + d);
}
process.WaitForExit();
Console.WriteLine("Finished cmd");
}
catch (Exception e)
{
Console.WriteLine("Errror Opening : " + e.Message);
Console.WriteLine(e.StackTrace);
}
return installed;
}
Untill process.BeginOutputReadLine(); & output handler was not removed, it kept waiting (may be for entry)like hanged out. The moment removed those 2 output lines and added while loop, process just gets exit on any stream call i.e. process.StandardOutput; OR StandardInput whichever comes the next and throws NullPointerException. Have I made any mistake in the code as instructed by you ?
@Fun Mum : Even after using and updating your edited version of the code, I end up the same. I updated your code, modified it a bit seeing that after 1st line output the openvpn asks for username and then passowrd, then their is no input. I get proper console outputs but the results not as expected. Here is the code :
public bool StartOpenVPN()
{
bool installed = false;
int lineNo = 0;
try
{
Console.WriteLine("Command = " + command + "\nOpening cmd");
initProcess();
process.Start();
sw = process.StandardInput;
Console.WriteLine("Has Exited after SW = " + process.HasExited.ToString());
//sw.WriteLine("123b5df33f");
//sw.WriteLine("*3FgYxyt");
//Console.WriteLine("Has Exited after writing data = " + process.HasExited.ToString());
while (process.HasExited == false)
{
string d = process.StandardOutput.ReadLine();
Console.WriteLine("Line = " + d);
lineNo++;
if (lineNo == 1)
{
Console.WriteLine("Writing Details");
sw.WriteLine("foo");
sw.Flush();
Console.WriteLine("Wrote Username");
sw.WriteLine("*baa");
sw.Flush();
Console.WriteLine("Wrote Password");
}
}
process.Close();
process = null;
Console.WriteLine("Finished cmd");
}
catch (Exception e)
{
Console.WriteLine("Errror Installing Tap Adapter : " + e.Message);
Console.WriteLine(e.StackTrace);
}
return installed;
}
The output is :
Command = files\openvpn --config files\client.ovpn
Opening cmd Has Exited after SW = False Line = Fri Mar 11 18:10:06 2011 OpenVPN 2.1.1 i686-pc-mingw32 [SSL] [LZO2] [PKCS11] built on Feb 17 2010 Writing Details // AFTER 1ST LINE IT IS TRYNG TO WRITE Wrote Username Wrote Password Line = Fri Mar 11 18:10:06 2011 ERROR: could not read Auth username from stdin Line = Fri Mar 11 18:10:06 2011 Exiting Line = Finished cmd
Couldn't make out if application is not able to throw input to stdin properly or openvpn is not able to accept it. I also tried sw.WriteLine("foo" + ConsoleKey.Enter);, that also produced same results. Was wondering & trying to see the cmd window on while executing/debugging to know the exact results, but couldn't see that also.
If we run openvpn via command prompt normally, we get is :
D:\>files\\openvpn --config files\\client.ovpn
Fri Mar 11 18:03:48 2011 OpenVPN 2.1.1 i686-pc-mingw32 [SSL] [LZO2] [PKCS11] bui lt on Feb 17 2010 Enter Auth Username:
Puzzled out with this, really.
You actually close your process in the finally
block. Try adding process.WaitForExit();
before Console.WriteLine("Finished cmd");
Alternatively, you may replace process.BeginOutputReadLine();
with:
while (!process.HasExited)
{
string d = process.StandardOutput.ReadLine();
Console.WriteLine("Line = {0}", d);
}
An even better approach is to put make process
a member variable rather than a local variable. Simple move the code in the finally
block to the process exited handler:
void process_Exited(object sender, EventArgs e)
{
// Code from finally here
}
But you must remember to add the exited handler:
process.Exited += new EventHandler(process_Exited);
On another note, closing the input stream may cause some problem. Try removing the following 2 lines to see what happens
sw.Flush();
sw.Close();
The following is an edited version of your code:
private void initProcess()
{
processInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
processInfo.UseShellExecute = false;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = true;
processInfo.WindowStyle = ProcessWindowStyle.Normal;
process = new Process();
process.StartInfo = processInfo;
//process.Exited += new EventHandler(process_Exited); // Actually no longer required, since HasExited will test for it
// return; // return not required
}
// No longer need Exited, since HasExited checks for it
/*
void process_Exited(object sender, EventArgs e)
{
Console.WriteLine("Into process_Exited....");
processInfo = null;
if (process != null)
{
sw = null;
// Do not close here. Closing here will prevent "process.WaitForExit()" and "process.HasExited" from working
//process.Close();
//process = null;
}
}
*/
public bool StartOpenVPN()
{
bool installed = false;
try
{
Console.WriteLine("Command = " + command);
Console.WriteLine("Opening cmd");
initProcess();
process.Start();
sw = process.StandardInput;
Console.WriteLine("Has Exited after SW = " + process.HasExited.ToString()); // RETURS FALSE BUT GOES TO process_Exited & for next line results is NullPointerException
sw.WriteLine("foo");
sw.WriteLine("*baa");
//sw.Flush();
//sw.Close();
//process.BeginOutputReadLine();
//process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
while (process.HasExited == false)
{
string d = process.StandardOutput.ReadLine();
Console.WriteLine("Line = " + d);
}
// process.WaitForExit(); // Not required, since HasExited already check whether process has exited
// Added here from Exited, so that it only close after exit
process.Close();
process = null;
Console.WriteLine("Finished cmd");
}
catch (Exception e)
{
Console.WriteLine("Errror Opening : " + e.Message);
Console.WriteLine(e.StackTrace);
}
return installed;
}
Instead of trying to pass the username and password via the command line use OpenVPN's --auth-user-pass [file] switch, where [file] is all two lines:
user secretPassword
I've never tried it, but its what the docs say.
So you opening line would be something like:
string command = "files\\openvpn --config files\\client.ovpn --auth-user-pass files\\TEMP-AUTH";
Just remember to delete TEMP-AUTH as soon as you're done with it.
This query has been unresolvable for me as openvpn didn't support accepting stdin from the application.
Thanks for everybody help and ideas and suggestions.
Thanks.
精彩评论