I am trying to restart a windows service from the same windows service with this code:
var psi = new ProcessStartInfo("net.exe", "stop " + serviceName);
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = true;
psi.WorkingDirectory = Environment.SystemDirectory;
var st = Process.Start(psi);
st.WaitForExit();
psi = new ProcessStartInfo("net.exe", "start " + serviceName);
psi.UseShellExecute = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.WorkingDirectory = Environment.SystemDirectory;
st = Process.Start(psi);
st.WaitForExit();
It is not working but is this even possible from the same service?
If it is possible then can anyone suggest why this does not work?
I don't believe there's a clean way of doing this. Once you stop the service, the process is no longer there to start it.
One slightly dirty solution:
You could configure the service to restart on error (e.g. at installation/registration time).
Then when you want to restart programmatically have your service exit with an error e.g. by calling:
Environment.Exit(-1)
or
Environment.FailFast("Service stopped because...")
Note: If there is a cleaner way of doing this programmatically the account the service is running under would require permissions to be able to restart the service.
It doesn't work because once you reach the middle, execution stops in since both parent and child process exit:
/* Running */ var psi = new ProcessStartInfo("net.exe", "stop " + serviceName);
/* Running */ psi.WindowStyle = ProcessWindowStyle.Hidden;
/* Running */ psi.UseShellExecute = true;
/* Running */ psi.WorkingDirectory = Environment.SystemDirectory;
/* st stops svc */ var st = Process.Start(psi);
/* both exit */ st.WaitForExit();
/* never reached */ psi = new ProcessStartInfo("net.exe", "start " + serviceName);
/* never reached */ psi.UseShellExecute = true;
/* never reached */ psi.WindowStyle = ProcessWindowStyle.Hidden;
/* never reached */ psi.WorkingDirectory = Environment.SystemDirectory;
/* never reached */ st = Process.Start(psi);
/* never reached */ st.WaitForExit();
Configure the service in windows to restart itself on failure and then do an unclean exit as #StevieB suggested.
Configure the service to restart itself with a 1000 ms delay on failure:
sc failure serviceName reset= 60 actions= restart/1000
You have a deadlock. net is waiting for your service to end, and you are using st.WaitForExit() to wait for net to end.
Eventually net gives up waiting and closes. Then you call net again. But your service never exited in the first place, so the second net invocation sees the service is already started and does nothing.
Finally you return the the main service event loop and see the stop request, and your service exits.
You should be able to write a batch file with the above commands, invoke it, and return to the event loop. Then the first net will wait until the service stops, and the second net will start it again.
Related
I have a WebAPI that works great but need to add the ability to call to an EXE on the server to run some tasks with Video, the server is our machine and running IIS to host the WebAPI.
I have tried it working with Process() and the calls make it to the cmd.exe file I have written but the issue is that the user is IUSER and this won't work as the Video processing needs to use system hardware so needs to be the current logged in Windows User.
I don't want to give the IUSER this privilege for obvious security reasons so I am looking for another way to call and pass data to the an EXE or background task (Short running <3seconds) and for that process to reply with the results.
It's all on the server which we have full control over.
Current Code:
string exeLoc = Environment.ExpandEnvironmentVariables(baseEXELocation);
using var process = new Process();
process.StartInfo.FileName = exeLoc;
process.StartInfo.Arguments = $"{command}";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, data) =>
{
if (!String.IsNullOrEmpty(data.Data))
{
Console.WriteLine(data.Data);
consoleData += data.Data;
}
};
process.Start();
process.BeginOutputReadLine();
var exited = process.WaitForExit(1000 * 10); // (optional) wait up to 10 seconds
Thanks
You could try to use the impersonation in iis:
<identity impersonate="true" />
https://support.microsoft.com/en-us/help/306158/how-to-implement-impersonation-in-an-asp-net-application
or assign the administrator permission to the application pool by using application pool advance setting -> identity to the custom account.
or You can try using the verb runas in Process.Start to execute the exe file as an Administrator.
ProcessStartInfo proc = new ProcessStartInfo();
proc.WindowStyle = ProcessWindowStyle.Normal;
proc.FileName = myExePath;
proc.CreateNoWindow = false;
proc.UseShellExecute = false;
proc.Verb = "runas"; //this is how you pass this verb
I made a launcher for my ARK Server where I can easily change my settings and start.
I start the server with this:
Process serverprocess = new Process();
serverprocess.StartInfo.FileName = Path.GetFileName(serverpath);
serverprocess.StartInfo.Arguments = launch;
serverprocess.StartInfo.UseShellExecute = false;
serverprocess.Start();
serverprocess.WaitForExit();
But when I press CTRL+C it doesn't wait until the ARK Server stops, it still runs in background while my app is killed.
I did some testing, the server recieves the shutdown signal and stops (which takes some time, espeically when the server isn't fully started). But when it takes time to stop the server is still running while my app already closed.
Doublepressing CTRL+C will kill the server but since the first press already brings me out of the console I'm unable to doublepress.
Any idea how I can prevent my app from beeing closed while still stopping the ARK server?
Adding Console.TreatControlCAsInput = true; will stop the server from even recieving the signal.
Thank you!
My test is ok
Process proc = new Process();
proc.StartInfo.FileName = "/bin/bash";//sh
proc.StartInfo.Arguments = "-c \" " + command + " && echo 'OK'\"";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
You should properly close your program for it to close properly your server. Here you go:
var serverProcess = Process.Start(new ProcessStartInfo
{
FileName = Path.GetFileName(serverpath),
Arguments = launch,
UseShellExecute = false
});
while (Console.ReadLine() != "exit")
{
Thread.Sleep(500);
}
serverProcess.Close();
I have a C# program that launches a child process and captures its output in a string. This works on most Windows machines (Windows 7 and newer), but when Kaspersky anti-virus is present, Process.StandardOutput.ReadToEnd() returns null. There is no error code or exception. The child process is a trusted console application. The process takes 5 or 6 seconds to run.
The code for launching the child process is as follows:
ProcessStartInfo psi = new ProcessStartInfo();
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.FileName = "icao.exe";
psi.Arguments = im_path + "image.jpg";
Process p = new Process();
p.StartInfo = psi;
p.Start();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
MessageBox.Show(error);
p.WaitForExit();
int exitCode = p.ExitCode;
MessageBox.Show(exitCode+"");
Why does output end up being null when Kaspersky is present?
My guess is that Kaspersky's heuristics are seeing that your program wants to execute another exe. Because nothing is telling Kaspersky that this is ok, it flags your program as possible malware, because it wants to interface with other programs that are developed by other companies. If you are able to I would try white listing your program with Kaspersky and see if that solves your issue.
I came across this question, which looked like it would resolve what I'm trying to do, and I'm trying to use similar code where a Process() object is created and the "sc" command is called from code.
static void SetRecoveryOptions(string serviceName)
{
int exitCode;
using (var process = new Process())
{
var startInfo = process.StartInfo;
startInfo.FileName = "sc";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
// tell Windows that the service should restart if it fails
startInfo.Arguments = string.Format("failure \"{0}\" reset= 0 actions= restart/60000", serviceName);
process.Start();
process.WaitForExit();
exitCode = process.ExitCode;
}
if (exitCode != 0)
throw new InvalidOperationException();
}
I've tried calling that code from a few locations (such as the committed event handler for the service installer, OnStart of the service itself, etc) but every time I get an exception as soon as the Process() object is created. The exception is: "operation is not allowed due to the current state of the object".
Any ideas what I'm missing here?
I am trying to restart a windows service from the same windows service with this piece of code
var proc = new Process();
var psi = new ProcessStartInfo();
psi.CreateNoWindow = true;
psi.FileName = "cmd.exe";
psi.Arguments = "/C net stop \"EmailService-3.1.0\ && net start \"EmailService-3.1.0\"";
psi.LoadUserProfile = false;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo = psi;
It is not working and I have no idea why, is there anything I can do to log or determine what is happening or get the output of what is happening when the net stop command is called?
You can redirect the output of the net stop command, but as per TomT's comment, this seems a very roundabout way to restart a service.
psi.Arguments = "/C net stop \"EmailService-3.1.0\" > C:\\svclog.txt "; //&& net start \"EmailService-3.1.0\"";
I can see a missing quotation mark after the name of your service in the stop command. Otherwise it can be a permission issue. Maybe the user with whom your service has logged in does not have enough privileges to stop a service.