Attach Console to (java) process from WPF app - c#

I currently start a bunch of java processes from my WPF app using Process, normally those would run in their own window. However when I want to send commands to the java app from my WPF app it requires me to run it with
StartInfo.UseShellExecute = false; which causes the process to run without a console.
I've tried to look for answers here on SO (How to open/close console window dynamically from a wpf application?) and a few others but most seem to be for the app to be either ran in console mode or in UI mode. Nothing about attaching a console to a System.Diagnostics.Process
This version would open a Console
namespace MMSG.Instances
{
public abstract class JavaServer : Process
{
protected JavaServer(string workingDir)
{
StartInfo.FileName = "java";
StartInfo.UseShellExecute = true;
StartInfo.RedirectStandardInput = true;
StartInfo.WorkingDirectory = workingDir;
StartInfo.CreateNoWindow = false;
StartInfo.ErrorDialog = true;
EnableRaisingEvents = true;
}
protected JavaServer(string ram, string workingDir, string jarLocation) : this(workingDir)
{
StartInfo.Arguments = $"-Xms{ram} -Xmx{ram} -jar \"{jarLocation}\"";
}
}
}
however when trying to send input to the Processusing javaServer.StandardInput.WriteLine("stop");
I get this error: System.InvalidOperationException: The Process object must have the UseShellExecute property set to false in order to redirect IO streams. And as stated before setting that to false removes the Console window altogether.
Expected result: allow sending of commands to the process while still having a Console window.
Actual result: Either no commands or no Console

Related

Issue executing command line command in .NET c#

Attempting to run ntdsutil from a C# executable and encountering an error. In case anyone is wondering, this is for a automated auditing process as part of a managed service provider - not trying to create a trojan/malware.
The command is: ntdsutil "ac i ntds" "ifm" "create full c:\audit" q q
This is Windows server specific, am running on Windows 2016.
I am using System.Diagnostics.Process and have tried various combinations of properties but getting same result. The following is an example, there is a standard output redirect so can see results of execution:
Process process = new System.Diagnostics.Process();
ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.FileName = #"C:\Windows\System32\ntdsutil.exe";
startInfo.Arguments = "\"ac i ntds\" \"ifm\" \"create full c:\\audit\" q q";
//Set output of program to be written to process output stream
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError= true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
// Get program output
string strOutput = process.StandardOutput.ReadToEnd();
//Wait for process to finish
process.WaitForExit();
File.WriteAllText("out.txt", strOutput);
The output looks like this:
C:\Windows\System32\ntdsutil.exe: ifm
ifm: create full c:\audit
error 0x80042302(A Volume Shadow Copy Service component encountered an unexpected error. Check the Application event log for more information.)
ifm: q
C:\Windows\System32\ntdsutil.exe: q
Have checked event logs as mention (nothing obvious) and done various searches on error but nothing useful appears. Running the command on command line works fine.
It is running a Administrator level user. Is it possible related to app.manifest priveleges?
Any help is appreciated.

Process.Start() only works when started as release build within VisualStudio

I'm trying to do execute an external .bat by pressing a button.
The intention is to call some XCOPY instructions. Therefore I execute "sync.bat" using Process.Start(startInfo).
The output of that .bat is redirected to my App and shown in a dialog box. My code waits until the external call has finished.
echo "Batch SYNC started."
pause
xcopy "e:\a\*" "e:\b\" /f /i /c /e /y
pause
echo "Batch SYNC finished."
OK:
When I build my program as "release" and start it within VisualStudio2013, everything works fine (I see the Results, have to press ENTER in the black window, files are copied).
FAIL:
When I start my app by double-click (in file-explorer or from the desktop) or a debug build within the VisualStudio, I see the ECHO and the PAUSE output, but the batch did not stop and I see no results from XCOPY. Seems as if the PAUSE and XCOPY are killed immediately.
I got no exception and no entry in Windows-log.
I have tried to make DEBUG and RELEASE configuration identical (with no success).
Does anybody have an idea what I may do to get this simple function work outside the IDE?
Here is the code of the function called when the button is pressed:
private void ProcessSync_bat()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.FileName = "sync.bat";
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.Arguments = "";
startInfo.ErrorDialog = true;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
dlgFKSyncMessageBox.AddLine("----------sync.bat started-----------");
dlgSyncMessageBox.AddLine("===============Result================");
while (!exeProcess.StandardOutput.EndOfStream)
{
dlgSyncMessageBox.AddLine(exeProcess.StandardOutput.ReadLine());
}
dlgSyncMessageBox.AddLine("===============ERRORS================");
while (!exeProcess.StandardError.EndOfStream)
{
dlgSyncMessageBox.AddLine(exeProcess.StandardError.ReadLine());
}
exeProcess.WaitForExit();
}
}
catch (Exception exp)
{
dlgSyncMessageBox.AddLine("========EXCEPTION========");
}
}
Solution:
If I additionally set
startInfo.RedirectStandardInput = true;
then it works. I may redirect input from dialog window to the Process. Since I do not need any input for the intended XCOPY, this solution works for me without catching chars from the Dialog window and Forward to the process.
I can't see the logic, why I have to Redirect input too, but I'm glad that my Software now does what I need.

How to redirect standard output when spawning a process

I've built a webservice for an internal server that I want to send a command to and have it launch a process. So I want to send a command to it like this:
http://machine:999/execute?path=c:\scripts\dostuff.exe&args=-test
The endpoint would then do something like this:
public ActionResult(string path, string args)
{
var proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = path;
proc.StartInfo.Arguments = args;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
proc.StartInfo.RedirectStandardOutput = true;
//Hook into all standard output here
//Block until process is returned - Async Controller action
return Content(output.ToString())
}
I want to be able to capture all the error messages and standard output generated by the executable. The executable could be anything like a console application or a powershell script. What's the best approach for doing something like this?
Use proc.StandardOutput.ReadToEnd() to read the redirected output stream to the end, and return that.
You may also want to set RedirectStandardError to True and do the same thing with proc.StandardError to get the error messages. You can spawn a background thread to synchronously read standard error alongside the reading of standard output in the main thread.

Hide Command Window in C# Application

Before you say its a duplicate question, please let me explain (as I've read all similar threads).
My application has both of these settings:
procStartInfo.CreateNoWindow = true;
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
and is also has WindowsApplication as the output type.
The black window STILL comes up when I call a command line command. Is there anything else I can do to hide the window? It doesn't happen for all commands, XCOPY is a situation where it the black window does flash up. This only happens though when the destination I'm XCOPYing too already contains the file and it's prompting me if I want to replace it. Even if I pass in /Y it will still flash briefly.
I'm open to using vbscript if that will help, but any other ideas?
The client will call my executable and then pass in a command line command ie:
C:\MyProgram.exe start XCOPY c:\Test.txt c:\ProgramFiles\
Here's the full code of the application:
class Program
{
static void Main(string[] args)
{
string command = GetCommandLineArugments(args);
// /c tells cmd that we want it to execute the command that follows and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe", "/c " + command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = procStartInfo;
process.Start();
}
private static string GetCommandLineArugments(string[] args)
{
string retVal = string.Empty;
foreach (string arg in args)
retVal += " " + arg;
return retVal;
}
}
The problem is that you're using cmd.exe. Only its console window will be hidden, not the console window for the process you ask it to start. There's little point in using cmd.exe, unless you are trying to execute some of the commands it implements itself. Like COPY.
You can still suppress the window if you need cmd.exe, you'll have to use the /B option for Start. Type start /? at the command prompt to see options. Not that it helps, you can't use START COPY.
There's a specific quirk in xcopy.exe that might throw you off as well. It does not execute if you don't also redirect the input. It just fails to run without diagnostic.
i see that you are calling cmd and then passing the command as parameters. Instead call the command directly
e.g.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.DiagnosticsProcessStartInfo("xcopy", "<sourcedir> <destdir> <other parameters>");
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
You can try adding
process.StartInfo.UseShellExecute = false;
to your process
If you are calling cmd.exe in your C# code and passing the commands to it via standard input.WriteLine and you don't want your CMD window to pop up every time you run your code, you can simply write this command:
test.StartInfo.FileName = "cmd.exe";
test.StartInfo.CreateNoWindow = true;
By setting create no window to false, we are running the command sent to the CMD in the background and the output is not being displayed to the user. By setting it to false, the CMD window pops up.
I had a similar task - It is possible to hide the window after creation via an API call.
(In your case you maybe need a helper thread.)
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
If you know the handle of the new Window you can call
ShowWindow(hWnd, 0);
0 hides the window, 1 shows the window
To get the handle of the Window take a look at:
pinvoke.net enumwindows(user32)

Process.WaitForExit() on Console vs Windows Forms

I have a console app and a win forms app that both need to call out to a remote server for some data, they make a call to the command line part of Putty, plink.exe, to run a remote command over SSH.
I created a tiny class library for both to share, running the following:
public static string RunCommand(string command, string arguments) {
ProcessStartInfo startInfo = new ProcessStartInfo {
FileName = command,
Arguments = arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true
};
string output = null;
using (Process p = new Process()) {
p.StartInfo = processStartInfo;
p.Start();
output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
return output;
}
Under the console application everything works fine, under the win forms it doesn't error, it seems that WaitForExit() just doesn't wait. I get an empty string for output. I've confirmed from the remote server the user logged in, so it seems the command has run.
Any ideas?
Under Windows Console applications have STDIN, STDOUT, and STDERR. Windowed applications do not. When you create a process under a Console application the STDIN etc. are inherited by the child application. This does not happen in the Windowed application.
The RedirectStandardInput=true works because it makes the system create a Writer for the STDIN that you can use to send input to the child process. In your case the child doesn't need the input it just needs the presence of the input. YMMV.

Categories