Redirecting standard error out - c#

So what i am doing is calling java.exe and making a call to a jar file with some arguments. If everyting is fine and the command works, then the arguments are printed out to a richtext box.
The issue I am having is when the command isn't correct. So in once instance, say the user types in the wrong password that's passed into txtPassword. Stanadard out is not being redirected. If i run the exact same command in a Dos console, the message "Error: Auth fail", is being presented. How do i redirect that error to the rich text box? I thought redirecting stdout would do it, but apparently not.
Any help would be apprecaited. Please see the code below.
//Declare and instantiate a new process component.
System.Diagnostics.Process process1;
process1 = new System.Diagnostics.Process();
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.CreateNoWindow = true;
process1.StartInfo.FileName = "java.exe ";
toLoad = lstBarToLoad.Items[i].Text;
process1.StartInfo.Arguments = "-Xmx512M -jar Deploy.jar" + txtPassword;
process1.StartInfo.Arguments += toLoad;
Console.WriteLine(process1.StartInfo.Arguments);
process1.Start();
process1.OutputDataReceived += (s, a) => myMethod(a);
process1.BeginOutputReadLine();
//myMthod
private void myMethod(DataReceivedEventArgs e)
{
if (e.Data != null)
{
Action action = () => rchsdtOut.Text += "\r\n" + e.Data.ToString();
rchsdtOut.BeginInvoke(action, null);
Console.WriteLine(e.Data.ToString());
}
}//end of private

As well as using
process1.StartInfo.RedirectStandardOutput = true;
You also need to use
process1.StartInfo.RedirectStandardError = true;
Gets or sets a value that indicates whether the error output of an application is written to the Process.StandardError stream
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandarderror.aspx
You can then read out the error and do with it as you please:
string error = process1.StandardError.ReadToEnd();

You can use RedirectStandardError property same way as you use the RedirectStandardOutput property.

Related

Update a WPF text box with stdout redirected from another process [duplicate]

This question already has answers here:
How to asynchronously read the standard output stream and standard error stream at once
(4 answers)
Closed 11 months ago.
I have a WPF application in which I am starting a Powershell process and redirecting the standard output to a textbox. I am facing a problem in which when the Powershell process is started, the Powershell window opens up but stays blank. The process is executing in the background however, the textbox is only updated when the Powershell window is closed. I would like for the text box to update and the process to move forward simultaneously.
How can I achieve this? My code is like this:
private async void btnStartPowershell(object sender, RoutedEventArgs e)
{
string powershellPath = #"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
Thread psThread = new Thread(() =>
{
string cOut = OpenPowershell(powershellPath, Installer, logPath, "Config Builder");
if (cOut.Contains("error"))
{
ErrorStatusStack.Visibility = Visibility.Visible;
}
Action action = () => doUIUpgrade(cOut, logPath);
this.BeginInvoke(action);
});
psThread.Start();
txtboxCompletedProcess.Text = $"Powershell Scripts Completed. Please see the logs for details.";
}
private void doUIUpgrade(string cOut, string logPath)
{
PSOutputTextBlock.Text = cOut;
if (cOut.Contains("OCMS INSTALLATION STARTED"))
{
Console.WriteLine("YES");
}
InstallationStartedTextBlock.Text = $"Installation started. Please do not close this window. More details can be found at {logPath}";
}
private string OpenPowershell(string path, string script)
{
try
{
bool is64 = IntPtr.Size == 8;
var ENV = "Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* "
+ (is64 ? ",HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*" : "")
+ " | Select-Object DisplayName";
ProcessStartInfo startPowershell = new ProcessStartInfo(path, ENV);
startPowershell.UseShellExecute = false;
startPowershell.Arguments = script;
startPowershell.RedirectStandardOutput = true;
startPowershell.EnvironmentVariables.Add("RedirectStandardOutput", "true");
startPowershell.EnvironmentVariables.Add("RedirectStandardError", "true");
startPowershell.EnvironmentVariables.Add("UseShellExecute", "false");
startPowershell.EnvironmentVariables.Add("CreateNoWindow", "true");
Process psProcess = Process.Start(startPowershell);
string output = psProcess.StandardOutput.ReadToEnd();
psProcess.WaitForExit();
return output;
}
catch (Exception error)
{
MessageBox.Show(error.Message);
return error.ToString();
}
}
I have tried doing string output = psProcess.StandardOutput.ReadLine(); instead of string output = psProcess.StandardOutput.ReadToEnd(); but I still only get the text box updated when the entire script is completed and not before.
I'll appreciate any help here.
you should create another thread for your psProcess's getting stdout and update by timers. it could helps you

How do I hide the CMD window that is created as a result of this process?

I am trying to run an executable file as part of my program which will be repeatedly called as the within an event handler.
At the moment, the first and last lines which are commented out run the executable as they should, the issue I am having is trying to make it so that the user has the option to hide this executable as it pops up (done with a radio button)
Console.WriteLine("Generated Instruction: " + arguments);
//var proc = System.Diagnostics.Process.Start(chartLocation + #"\MODUS CHaRT CMD.exe", arguments ); // Run Command Line instruction
Process myProc = new Process();
if (hideChartStatus) /* make the process invisible */
{
try
{
myProc.StartInfo.CreateNoWindow = true;
myProc.StartInfo.UseShellExecute = false;
Console.WriteLine("Invisible CHART window generated");
}
catch
{
Console.WriteLine("Could not hide CHaRT window");
}
}
else
{
myProc.StartInfo.CreateNoWindow = false;
}
myProc.StartInfo.WorkingDirectory = chartLocation;
myProc.StartInfo.FileName = "\\MODUS CHaRT CMD.exe";
myProc.StartInfo.Arguments = arguments;
myProc.Start();
//myProc = myProc.Start(chartLocation + #"\MODUS CHaRT CMD.exe", arguments);
//proc.WaitForExit();
myProc.WaitForExit();
This is what I've got so far but I'm getting the error
" System.ComponentModel.Win32Exception: 'The system cannot find the file specified' "
at myProc.start();
I'm guessing it's something to do with how I'm using filename and working directory?
Anyone know the right syntax for this?
Ignore me everybody, I'm an idiot.
Basing it more accurately on what is done here:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.start?view=netframework-4.7.2
The correct use is:
//myProc.StartInfo.WorkingDirectory = chartLocation;
myProc.StartInfo.FileName = chartLocation + #"\MODUS CHaRT CMD.exe";
myProc.StartInfo.Arguments = arguments;
myProc.Start();

Execute a command line utility in ASP.NET

I need some advice regarding the use of a command line utility from a C#/ASP.NET web application.
I found a 3rd party utility for converting files to CSV format. The utility works perfectly and it can be used from the command line.
I have been looking on the web for examples on how to execute the command line utility and found this example.
The problem is this is not very good. When I try to us the example code with my utility, I get a prompt asking me to install the utility on the client machine. This is not what I want. I do not want the user to see what is going on in the background.
Is it possible to execute the command server side and processing the file from there?
Any help would be greatly appreciated.
I've done something like this several times in the past, and here's what's worked for me:
Create an IHttpHandler implementation (easiest to do as an .ashx file) to handle a convert. Within the handler, use System.Diagnostics.Process and ProcessStartInfo to run your command line utility. You should be able to redirect the standard output to the output stream of your HTTP response. Here's some code:
public class ConvertHandler : IHttpHandler
{
#region IHttpHandler Members
bool IHttpHandler.IsReusable
{
get { return false; }
}
void IHttpHandler.ProcessRequest(HttpContext context)
{
var jobID = Guid.NewGuid();
// retrieve the posted csv file
var csvFile = context.Request.Files["csv"];
// save the file to disk so the CMD line util can access it
var filePath = Path.Combine("csv", String.Format("{0:n}.csv", jobID));
csvFile.SaveAs(filePath);
var psi = new ProcessStartInfo("mycsvutil.exe", String.Format("-file {0}", filePath))
{
WorkingDirectory = Environment.CurrentDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using (var process = new Process { StartInfo = psi })
{
// delegate for writing the process output to the response output
Action<Object, DataReceivedEventArgs> dataReceived = ((sender, e) =>
{
if (e.Data != null) // sometimes a random event is received with null data, not sure why - I prefer to leave it out
{
context.Response.Write(e.Data);
context.Response.Write(Environment.NewLine);
context.Response.Flush();
}
});
process.OutputDataReceived += new DataReceivedEventHandler(dataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(dataReceived);
// use text/plain so line breaks and any other whitespace formatting is preserved
context.Response.ContentType = "text/plain";
// start the process and start reading the standard and error outputs
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
// wait for the process to exit
process.WaitForExit();
// an exit code other than 0 generally means an error
if (process.ExitCode != 0)
{
context.Response.StatusCode = 500;
}
}
}
#endregion
}
The command is running server side. Any code is running on the server. The code in the example that you give works. You just need to make sure that the utility is set up properly on the server and that you have permissions to the directory/file.

Question on returning values from VBScript to .NET

i'm trying to set up an application capable of running VBScript files from .NET (See here), and have most of it set up fine, but I want to test this out, so I need to be able to return data from my VBScripts. I've found that I can use WScript.Quit([ErrorCode]) to get back an integer value, but what about returning strings? Is it possible to feed them out to the DataReceivedEventHandler? Or do I need to look at a different method? Thanks.
You can write to the standard output (which will redirect it to the event handler). I believe in VBScript this is WScript.Stdout.
If you have multiple lines written out you may consider using something like a StringWriter to capture them all, ie
var p = new Process()
{
StartInfo = new ProcessStartInfo("netstat")
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
}
};
var outputWriter = new StringWriter();
p.OutputDataReceived += (sender, args) => outputWriter.WriteLine(args.Data);
var errorWriter = new StringWriter();
p.ErrorDataReceived += (sender, args) => errorWriter.WriteLine(args.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
if (p.ExitCode == 0)
{
Console.WriteLine(outputWriter.GetStringBuilder().ToString());
}
else
{
Console.WriteLine("Process failed with error code {0}\nMessage Was:\n{1}", p.ExitCode
, errorWriter.GetStringBuilder().ToString());
}

Certain Python commands aren't caught in Stdout

I've written a simple program that captures and executes command line Python scripts, but there is a problem. The text passed to a Python input function isn't written to my program despite my program capturing stdout.
For example:
The Python script:
import sys
print("Hello, World!")
x = input("Please enter a number: ")
print(x)
print("This work?")
Would write "Hello, World!" then stop. When I pass it a number it would continue on writing "Please enter a number: 3". What is going on? Any solutions? My C# is as follows:
public partial class PyCon : Window
{
public string strPythonPath;
public string strFile;
public string strArguments;
private StreamWriter sw;
public PyCon(string pythonpath, string file, string args)
{
strPythonPath = pythonpath;
strFile = file;
strArguments = args;
InitializeComponent();
Process p = new Process();
p.StartInfo.FileName = strPythonPath;
p.StartInfo.Arguments = "\"" + strFile + "\" " + strArguments;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
sw = p.StandardInput;
}
private void p_OutputDataReceived(object sendingProcess, DataReceivedEventArgs received) {
if (!String.IsNullOrEmpty(received.Data)) {
AppendConsole(received.Data);
}
}
private void p_ErrorDataReceived(object sendingProcess, DataReceivedEventArgs received) {
if (!String.IsNullOrEmpty(received.Data)) {
AppendConsole(received.Data);
}
}
private void AppendConsole(string message) {
if (!txtConsole.Dispatcher.CheckAccess()) {
txtConsole.Dispatcher.Invoke(DispatcherPriority.Normal, (System.Windows.Forms.MethodInvoker)delegate() { txtConsole.AppendText(message + "\n"); });
} else {
//Format text
message = message.Replace("\n", Environment.NewLine);
txtConsole.AppendText(message + "\n");
}
}
private void txtInput_KeyUp(object sender, KeyEventArgs e) {
if (e.Key != Key.Enter) return;
sw.WriteLine(txtInput.Text);
txtInput.Text = "";
}
}
Edit: After a lot of research and help from this thread, I've come to the conclusion that the problem is with the Python input command not calling the C# DataReceivedEventHandler. There may not be a solution to this besides scripting changes. If that is the case, I'll make the answer containing those changes as accepted. Thanks for the help, guys!
Smells like the Python i/o is line buffered, i.e. waits for a CRLF then sends a whole line at once. You could try turning that off (python -u myscript.py, or set the PYTHONUNBUFFERED environment variable) or work around it with something like this:
print("Hello, World!")
print("Please enter a number: ")
x = input()
print(x)
It's difficult to tell because I'm using python 2.6 and you appear to be using 3.x, and I also have not programmed in c# for quite awhile but my guess is that this line:
sw.WriteLine(txtInput.Text);
Is sending "3" plus a windows new line character.
Try:
sw.Write(txtInput.Text + "\n")
sw.Flush()
This will just send a normal newline instead of a windows carriage return which may be the issue. Make sure you always Flush when dealing with complicated stream communication like this!
One more thing, make sure you can just redirect this at the command prompt. Too often programmers try to do everything at the same time and get stuck:
./stdintest.py < input.txt
If it doesn't work there, it's not going to work in C#. Good luck

Categories