Process.Start without creating a child process (port handle inheritance)? - c#

I have a WCF service in a self hosted application using TCP bindings. If I start an external process "commandLineApp" from the application, that continues even after my application has closed, I run into problems next time the WCF service is started by my application.
WCF says that the address/port is already in use. If I close the external application (that isn't using WCF or any sockets at all) before restarting my application, the WCF service starts just fine.
It looks like that the socket handles from my application is somehow inherited by the new process "commandLineApp", and not released until that process has exited.
How do I prevent the other process from inheriting the handles (or becoming a child process?) from my main application? Currently I'm using Process.Start to launch the other process, using UseShellExecute set to False because I need to set both EnvironmentVarables and RedirectStandardOutput/Error.
I think the child process setup is prevented if I set UseShellExecute = true, but then I don't get all features I need.
Are there any way around this problem? See example code below.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "commandLineApp.exe";
psi.Arguments = "/someParameter";
psi.EnvironmentVariables.Add("...", "...");
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
Process process = new Process();
process.StartInfo = psi;
process.Start();
// Monitor if process with PID = process.Id is running
// ...
Edit - Additional information:
Doing "netstat -noa" indicates that the port is used with state LISTEN by the previous PID of the main application, but there is no process with that PID anymore. As soon as I close "commandLineApp", the port isn't listed by the netstat command anymore.
WCF services are closed like this before the main application exit:
try
{
serviceHost.Close(TimeSpan.FromSeconds(4));
}
catch (Exception)
{
serviceHost.Abort();
}

I was wrong in the above comment: SO_REUSEADDR would only apply if the handle had been closed, but it seems like socket handles truly are inherited by child processes and there is no easy way to prevent this. This seems like a very stupid design decision, particularly since some places noted that the handle can't be used in the child if any LSPs are installed.
If you had more control over the call to WSASocket, you might be able to pass the WSA_FLAG_NO_HANDLE_INHERIT flag, but this is going to be hard to accomplish inside WCF. Here's a couple other options:
Option #1: Call CreateProcess yourself and pass FALSE for bInheritHandles.
Option #2: Create a helper process before you set up WCF (or any other sockets). Communicate with it via named pipes. Start the child process from this helper instead of from the main process.

Related

Start cmd process call in a .NET MVC web project on IIS web server (not working!)

Hi fellow software developers
So I need to start a CMD process in my .NET MVC web project. This is my function that I pass the command I need to call:
private void ExecuteCommandSync(string command)
{
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
// Hide the CMD window:
procStartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
// The following commands are needed to redirect the standard output.
procStartInfo.UseShellExecute = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
}
The command calls a program that starts a linear programming framework that solves a problem which takes 20 seconds to finish.
The problem is that nothing happens when this function is called! It works fine outside the IIS, but not in IIS. The IIS web server runs on a Windows Server 2012. My web project is called from outside of our local network, where the web server is running, does some work, calls my synchronous method and waits for it to finish and ends by returning the result of the call as a JSON object.
This question suggests that it might have something with user privileges. In the Application Pools for the web project in Advanced Settings -> Identity I have tried to change from ApplicaitonPoolIdentity to Local System (which has high privileges) but no luck (as explained here).
Does anyone have any suggestions to how I can solve this problem? Any advice would be greatly appreciated.
you must run project pool under user have privilege's to execute exec.

Pass arguments to a Process after its started

Is there a way to start a Process argument and then after its been called, pass arguments to it (and read the output)?
Process process
void CalledOnStart()
{
process = new Process();
process.StartInfo.UseShellExecute = true;
process.StartInfo.FileName = "cmd.exe"; //or anything, really
process.Start();
}
void UserInput(string input)
{
process.passArgument(input); //does this exist?
}
Thanks
No, there is no generic way to pass arguments to running process.
Options depend on what process you trying to communicate with:
for command line processes sending to process' standard input/reading standard output may be an option (need to capture both when starting)
(Windows only) some processes are COM "automation servers" like Office, IE,.. you may be able to attach to existing process using ROT or start one via automation and control via corresponding automation interfaces.
(Windows only) some support old DDE protocols
some support other ways of IPC (inter-process communication) - sockets, named pipes,...
some support reading updates from config files...
To pass arguments to your Process upon invocation, you should do it using the Start method, for example:
Process.Start("someArg");
For passing it later on, when it is already running, I would recommend using Named-Pipes Stream for example.
From MSDN:
Named pipes provide interprocess communication between a pipe server
and one or more pipe clients.

Process.Start does not work when called from windows service

On Windows 8 I am running a windows service. This service is supposed to start a program by
Process.Start(exePath);
But the process exits immediately - even first line in the Main procedure is not executed. Before, when running the same process in same service on Windows 7, everything worked fine.
How can I make it work again? How to properly start a process from a windows service?
Found the solution. Process has to be started like this:
ProcessStartInfo info = new ProcessStartInfo(exePath);
info.CreateNoWindow = true;
info.UseShellExecute = false;
Process.Start(info);
For some reason there are problems with priviledges when creating a shell window in the background of the SYSTEM.
Use WaitForExit method on your Process instance will instruct to wait until the time elapsed or the process has exited.
See this MSDN link for more.

Process.Start() not spawning new process under the same user

I was always under the impression that when you're running a process as (domain\user) mydomain\myuser, when using Process.Start() it would start this new process using the same credentials - mydomain\myuser.
The issue I'm having is that my Process.Start() call seems to be creating a process under the SYSTEM account which is causing me permission issues in the started process (which must run under an admin account due to the work it does). If it changes things - I'm spawning this process (a custom built exe) from within a windows installer.
Any suggestions? I've read about windows group policies (possibly) having an impact on this, but if I'm honest, it's lost on me.
EDIT: a little snippet:
Where exename and commandLine are parameters for this method body:
ProcessStartInfo procInfo = new ProcessStartInfo(exeName, commandLine);
procInfo.WorkingDirectory = workingDirectory;
procInfo.UseShellExecute = false;
procInfo.CreateNoWindow = true;
Process process = Process.Start(procInfo);
Process.WaitForExit();
return process.ExitCode;
Either set procInfo.UseShellExecute to true, or execute cmd as a process with your exe as a parameter to the cmd command. When UseShellExecute is set to false, here are a lot of interesting side effects: UseShellExecute
Your impression is true. Process.Start() will always start the new process under current user's credentials - unless you provide alternative credentials in the ProcessStartInfo or use one of the overloads that take credentials.
There must be another problem - share a snippet of your code.
UPDATE
OK! You did not mention anything about installer. All MSI installers will be running under system since they will be run by "Windows Installer" which you can check and they run under SYSTEM.

Windows Service Application Controller

Here is the premise:
I have a desktop that I need to be able to start up and stop applications on, but cannot get remote access to. What I had in mind is setting up a service on the machine that will start/stop a list of applications as told. This windows service will periodically pole a web service for new commands and execute them accordingly.
These are my questions.
1) Is this the easiest solution? What else would you recommend?
2) How hard is it to run an exe from a windows service? How about stopping one?
This isn't for a project or anything, just something I am interested in implementing (mostly for fun). Any answers or even thoughts are appreciated. General discussion is also welcome (feel free to leave comments).
As for creating the Windows service itself in C#, see my post here.
The polling mechanism would work, but in general, I prefer event-driven processes instead of polling processes. You didn't mention what version of .NET you were using, but if it is .NET 3.0/3.5, I would suggest using WCF. When the command is posted to the web service, the web service could send the command to the Windows service to be executed. Pretty straightforward. Juval Lowy, the author of Programming WCF Services, offers a bunch of WCF examples/libraries that are free to use at his website.
So I guess PsExec is out of question?
Other than that, it's not hard to implement running of programs inside a Win service. Simply use the .NET Process class to do it, sample from my code:
ProcessStartInfo processStartInfo = new ProcessStartInfo (programExePath, commandLineArgs);
consoleLogger.WriteLine (log, Level.Debug, "Running program {0} ('{1}')", programExePath, commandLineArgs);
processStartInfo.CreateNoWindow = true;
processStartInfo.ErrorDialog = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
using (Process process = new Process ())
{
process.StartInfo = processStartInfo;
process.ErrorDataReceived += new DataReceivedEventHandler (process_ErrorDataReceived);
process.OutputDataReceived += new DataReceivedEventHandler (process_OutputDataReceived);
process.Start ();
process.BeginOutputReadLine ();
process.BeginErrorReadLine ();
if (false == process.WaitForExit ((int)TimeSpan.FromHours(1).TotalMilliseconds))
throw new ArgumentException("The program '{0}' did not finish in time, aborting.", programExePath);
if (process.ExitCode != 0)
throw new ArgumentException ("failed.");
}
I have done a service that starts other exe files. There are some things to consider: As a service you have no visual desktop -> no direct interaction is possible. Also, the program must be designed to run a long while.
Stopping an exe is to kill the process. Consider the usual side-effects.
It wouldn't be too difficult - you can just have it poll some webservice for a list of "banned" applications every so often, and then on another timer, have it check for a banned application that's running and kill it if it is. Here's some code to get a list of processes, and you can use the methods on the process class to launch or kill something:
http://www.vbdotnetheaven.com/UploadFile/prvn_131971/machineprocessvb11182005001454AM/machineprocessvb.aspx
The timers could run independently as well - it can check the webservice once/day for a new add/prohibited list, but then check the processes running on the computer every 2 minutes, for example.
I'll answer question 2 first:
To start or stop programs, you just need to use the System.Diagnostics.Process object, and the example code is right in the MSDN library.
For question 1:
You could have it poll a web service periodically if you want to do that.
As an alternate, you can set up the service for remoting and have it just listen on a tcp port for function calls, then write a Windows app that can use remoting to call the service. I've had to do this for a legitimate business app and it works very well.
However, I would be very irresponsible if I didn't include this warning:
Either way, setting up a computer so that it can execute arbitrary code is a bad idea and should be done very carefully. Just because it can be done doesn't mean it should be done. If you go the web service route, how are you going to ensure that someone doesn't tamper with the web service and get malicious code to execute? How do you know someone won't mess with your app.config and point the app to their own web service? In the remoting scenario, how to you ensure that some other .Net developer doesn't just create a proxy of their own?
In all honesty, I'm amazed that Microsoft even allows the System.Diagnostocs.Process to be used in a .Net application. You can literally do anything you want with it, including launching the cmd shell and executing system commands. Therefore, I'd urge you to seriously consider if this is truly necessary to do. You may be better served installing vnc or using remote desktop, or another app for remote access.
One other question you need to answer is "should the application be visible to the user on that remote machine?" If so, then you need to ensure that the service is set up to run under that user's context. otherwise, you could, for example, launch Word using the local system account, and it would never be visible to the person logged into that machine.

Categories