2

I'm trying to run the command line utility PCLI.exe from C# and having no luck. I'm constructing a ProcessStartInfo object and have set process.StartInfo.RedirectStandardOutput = true, but when I try to read process.StandardOutput I get the following error:

Message=StandardOut has not been redirected or the process hasn't started yet.

I even tried just piping the output of my command to output.txt, and while the file gets created it's empty.

The process completes but doesn't really execute the intended file, so I'm trying to capture StandardOutput to see what's going on. Just for background purposes I'm trying to run a PVCS get command to get a file out of PVCS.

Here's a snippet of my code:

System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new     
System.Diagnostics.ProcessStartInfo();
process.StartInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.WorkingDirectory = "c:\\gitmover";
startInfo.FileName = "C:\\Program Files (x86)\\Serena\\vm\\win32\\bin\\pcli.exe";

Console.WriteLine("Password:?");
string password = Console.ReadLine();
for (int i = 0; i < revisionsArray.Count(); i++)
    {
       string fileName = "/" + file.Key.Substring(file.Key.IndexOf("Customers")).Replace('\\','/');
       startInfo.Arguments = "get -r" + revisionsArray[i] + " -id\"beng:" + password + "\" -prM:\\Engineering\\SOUP -o -ac:/gitmover -bp'/Customers' -z " + fileName + "> output.txt";
       process.StartInfo = startInfo;
       process.Start();
       string strOutput = process.StandardOutput.ReadToEnd();

       //Wait for process to finish
       process.WaitForExit();
    }
Ben_G
  • 770
  • 2
  • 8
  • 30

2 Answers2

1

Try wrapping your process in a using and use a StreamReader to read stdout.

var start = new ProcessStartInfo
            {
                FileName = _pathToPythonExecutable,
                Arguments = string.Format(" {0}", _pathToPythonCalibratorScript),
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardInput = true,
                RedirectStandardError = true,
                WorkingDirectory = _currentWorkingDirectory            
            };

using (Process process = Process.Start(start))
                {                  
                    using (StreamReader reader = process.StandardOutput)
                    {
                        result = reader.ReadToEnd();
                    }                  
                }
David Watts
  • 2,249
  • 22
  • 33
  • Entering the code above I get a compile error: The name 'start' does not exist in the current context. Also, if I'm initiating process in the using statement how do I assign the values in System.Diagnostics.ProcessStartInfo to that process? – Ben_G Feb 26 '15 at 18:26
  • Sorry, the code above is just an example, and was not meant to be a copy and paste solution. Process.Start takes your start options, that is what start is in the code above. – David Watts Feb 26 '15 at 18:35
  • @Ben_G I've updated my answer to show you the ProcessStartInfo. If this gives you what you need, please let me know and accept the answer if that is the case. – David Watts Feb 27 '15 at 09:03
  • @Ben_G did this end up solving your problem. Marking answers as accepted helps others with the same problem too . – David Watts Mar 05 '19 at 15:32
  • this post was from 4 years ago so I don't remember which answer worked. Sorry - I always mark answers that solved my problem. Not sure how I missed this one. – Ben_G Mar 05 '19 at 19:05
  • @Ben_G no worries man, I'm just going through some of my old questions/answers making sure I've accepted everything and prodding those that hadn't responded. – David Watts Mar 07 '19 at 10:17
  • @DavidWatts: I tried your code for fetching all the output but it doesn't work for me. I even tried, while (!myProcess.StandardOutput.EndOfStream) { line += myProcess.StandardOutput.ReadLine();} But I am not sure when EndOfStream getting true before fetching all the output and it just fetches "Unknown os = Windows NT (unknown)\r\n" result of both are same. I tried it to create a version label. – Amir Mar 18 '19 at 08:00
  • however @Ben_G problem was misplacing process.start. – Amir Mar 18 '19 at 08:03
  • @Amir That was not the original question, the original question was why wasn't STD OUT being read and how to read it instead.. Feel free to ask another if you need something else answered. – David Watts Mar 19 '19 at 10:21
  • @DavidWatts: have you tried your solution for label command? I am not sure why GET command result output appear for me but I can only fetch "Unknown os = Windows NT (unknown)\r\n" for LABEL command. My code is in below, can I have your advice? I tried your advice and the result was same for me. – Amir Mar 20 '19 at 11:14
  • @Amir I don't see anything wrong with your code for reading STD OUT in your example below. From what I can see,that should read the entirety of STDOUT for you. Are you sure your process is redirecting its output to STDOUT and not putting it somewhere else? – David Watts Mar 21 '19 at 12:07
  • 1
    @DavidWatts: I found that if PVCS exit code be something except 0, all the result will be redirect to StandardError. problem solved. – Amir Mar 22 '19 at 15:34
0

I wrote below code and it works fine for me. Please take note that only those commands with exit code 0 will appear in StandardOutput otherwise you need to check StandardError.

public class ProcessStarter
    {
        public static OutputEventArgs execAsync(string exe, string arguments)
        {
            OutputEventArgs oea = new OutputEventArgs();
            try
            {
                using (Process myProcess = new Process())
                {
                    ProcessStartInfo startInfo = new ProcessStartInfo();
                    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                    startInfo.RedirectStandardOutput = true;
                    startInfo.RedirectStandardError = true;
                    startInfo.UseShellExecute = false;
                    startInfo.CreateNoWindow = true;

                    startInfo.FileName = exe;
                    startInfo.Arguments = arguments;
                    myProcess.StartInfo = startInfo;
                    myProcess.Start();
                    oea.Data = myProcess.StandardOutput.ReadToEnd();
                    oea.ErrorMsg = myProcess.StandardError.ReadToEnd();
                    myProcess.WaitForExit();
                    oea.exitCode = myProcess.ExitCode;
                }
            }catch(Exception e)
            {
                oea.Data = e.Message;
                oea.ExceptionHappened();
            }
            return oea;
        }

    }

    public class OutputEventArgs
    {
        public int exitCode { get; set; }
        public OutputEventArgs() { Error = false; }
        public string Data { get; set; }
        public bool Error { get; set; }
        public bool ErrorMsg { get; set; }


        public void ExceptionHappened()
        {
            exitCode = int.MinValue;
            Error = true;
            Data = string.Empty;
        }

    }

How to use it?

 string arguments = "get -pr" + tbProjectDatabase.Text.Trim() +
                                           " -id" + tbUsername.Text.Trim() + ":" + tbPassword.Text.Trim() +
                                           " -a'" + pvcsFolder + "' -o -z '" + tbCurrentProjectLocation.Text.Trim() + zipItem.FullNameZip + "'";

                    oea = ProcessStarter.execAsync("pcli", arguments);
Amir
  • 1,919
  • 8
  • 53
  • 105