I have a button I click that executes a command. The command may prompt for some standard input and I need to respond to that input, the problem is the way the program runs may be different from day to day so I need to interpret the standard output and redirect standard input accordingly.
I have this simple piece of code that reads the standard output line by line and when it sees a prompt for password, it'll send standard input, however the program just hangs since it never sees the prompt for the password, but when I run the batch file the password prompt is there.
Here is the batch file I am calling to execute this test:
@echo off
echo This is a test of a prompt
echo At the prompt, Enter a response
set /P p1=Enter the Password:
echo you entered "%p1%"
Here is the output of that batch file when run from the command line:
C:\Projects\SPP\MOSSTester\SPPTester\bin\Debug>test4.bat
This is a test of a prompt
At the prompt, Enter a response
Enter the Password: Test1
you entered "Test1"
Here is the C# snippet I am using to call the batch file that is hanging:
var proc = new Process();
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "/c test4.bat";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
//read the standard output and look for prompt for password
StreamReader sr = proc.StandardOutput;
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
Debug.WriteLine(line);
if (line.Contains("Password"))
{
Debug.WriteLine("Password Prompt Found, Entering Password");
proc.StandardInput.WriteLine("thepassword");
}
}
sr.Close();
proc.WaitForExit();
Here is the debug standard output I see, notice that I never see the prompt for the password, why is this? it just hangs?
This is a test of a prompt
At the prompt, Enter a response
Is there a way I can watch the standard output for prompting and react to it accordingly?
Your main problem is that you are working through the stream reader using sr.ReadLine()
this is an issue because the prompt for a password halts until the user enters a new line (hits enter after typing the password).
So you need to read the stream 1 character at a time. This example should help you get started.
while (!sr.EndOfStream)
{
var inputChar = (char)sr.Read();
input.Append(inputChar);
if (StringBuilderEndsWith(input, Environment.NewLine))
{
var line = input.ToString();
input = new StringBuilder();
Debug.WriteLine(line);
}
else if (StringBuilderEndsWith(input, "Password:"))
{
Debug.WriteLine("Password Prompt Found, Entering Password");
proc.StandardInput.WriteLine("thepassword");
var line = input.ToString();
input = new StringBuilder();
Debug.WriteLine(line);
}
}
private static bool StringBuilderEndsWith(StringBuilder haystack, string needle)
{
var needleLength = needle.Length - 1;
var haystackLength = haystack.Length - 1;
if(haystackLength < needleLength) {
return false;
}
for (int i = 0; i <= needleLength; i++)
{
if (haystack[haystackLength - i] != needle[needleLength - i])
{
return false;
}
}
return true;
}