Having an issue with a program that is launched by a windows service.
The process flow is
exe launches
renames itself to *.bak
downloads the latest version of itself
calls Restart()
does a bunch of file and SQL operations (updating our main software suite)
then calls Restart()
Process flow starts again. IF there were no software updates for the main suite it does not restart
this all works perfect except for one customer site
On one site, the first Restart() works, but the second one always throws an exception.
System.ComponentModel.Win32Exception (0x80004005): No such interface supported
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at UpdateCompanionService.Program.Restart()
It is a WS2008 standard server.
public static void Restart()
{
try
{
var procPath = Path.Combine(Config.UpdateCompanionDirectory, "UpdateCompanionService.exe");
Logger.Debug("Starting procecss {0}", procPath);
var proc = new Process
{
StartInfo = {FileName = procPath, WorkingDirectory = Config.UpdateCompanionDirectory, Arguments = "/noupdate", UseShellExecute = true}
};
proc.Start();
Environment.Exit(-1);
}
catch (Exception e)
{
Logger.Fatal("Error restarting update companion", e);
}
}
Try using
UseShellExecute = false
Its been known to fix this problem
You can try to set UseShellExecute = false in your code.
I remember some own problems long ago, where I even recompiled the original .NET framework code to find out that setting this flags uses a completely different method of starting.
For me it seems you do not need UseShellExecute = true in your case.
If this does not work, you should check security context / GPO settings, e.g.
"Is this service running as SYSTEM or (domain) user ?"
Also be sure that your new EXE with all additional components is "ready" at the time where you try to restart it (maybe you use a background thread which did not complete).
I had similar issue with an executable which is called by a Web Application running on IIS. In my case the solution was to restart the Application Pool for to current Web Application.
Related
I have a web application that has to open a process and wait for exit.
This process is a .sh script that uses Cygwin.
I'm using the following code:
var process = new Process();
var string processFileLocation = #"C:\script.sh";
var string workingDirectoryLocation = #"C:\script";
var processInformation = new ProcessStartInfo(processFileLocation)
{
WorkingDirectory = workingDirectoryLocation,
UseShellExecute = true
};
process.StartInfo = processInformation;
process.Start();
process.WaitForExit();
If I run the application using IISExpress, everything works fine, the script is being callse.
When I add it to IIS, the process simply gets blocked, I never receive any answer from the request that should call the process.
I added "Full control" permission to that folder for the Application Pool that the website uses, but still no diference.
Any idea why it is behaving like this?
Whenever something stops running when put in IIS, there's a high likelihood that it's due to insufficient permissions. Start by running your pool with an administrator account. If it solves the issue, then you can work your way from there to find what permission you were missing.
I have a windows service that I would like to be automatically and silently updated. I started using wyBuild to implement this, but have had some issues with it, and decided to try to build my own. I've written a standalone exe that can be called to do the update procedure: checks for a new zip file with the update, downloads it, unzips, stop the windows service, copy files from the zip, then restart the service. This exe works fine when I run it from the commandline and wasn't really difficult to write.
However, now I would like the service (the same one being updated) to shell out to the updater exe to update itself. I first tried Process.Start:
var proc = Process.Start(pathToUpdaterExe);
proc.WaitForExit(60000);
This called the updater, but when the updater stops the service, the process is killed and the update stops. I did some searching and it sounds like the solution is to use a separate AppDomain. This is what I have now:
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence objEvidence = new System.Security.Policy.Evidence(baseEvidence);
AppDomainSetup setup = new AppDomainSetup();
var updateDomain = AppDomain.CreateDomain("updateDomain", objEvidence, setup);
updateDomain.ExecuteAssembly(updater);
AppDomain.Unload(updateDomain);
However, now I get the error System.IO.IOException: "The process cannot access the file 'C:\Program Files (x86)\Company\Service\Service.dll' because it is being used by another process" when attempting to copy over the new Service.dll
Again, I've stopped the service at this point. I've confirmed this with logging. I can't imagine what would have Service.dll still locked, so I added code to check to see what is locking it:
public static IEnumerable<Process> GetProcessesLocking(string filePath)
{
var result = new List<Process>();
result.Clear();
var processes = Process.GetProcesses();
foreach (Process proc in processes)
{
try
{
if (proc.HasExited) continue;
foreach (ProcessModule module in proc.Modules)
{
if ((module.FileName.ToLower().CompareTo(filePath.ToLower()) == 0))
{
result.Add(proc);
break;
}
}
}
catch (Exception ex)
{
Log(ex.ToString());
Log("There was an error checking " + proc.ProcessName );
}
}
return result;
}
However this code indicates that nothing has a lock on the dll (result is empty and nothing is logged indicating an error).
I suspect I'm running afoul of some UAC issue that is the real cause of the IOException. The windows service runs as LocalSystem. All that to ask: How should I be running the update exe from the windows service such that it has rights to copy files in c:\Program Files?
Update
As the comments and answer suggest, Process.Start can work, but there is some nuance. You have to start cmd.exe and use it to start the updater. I also found I could not use a full path for the updater exe and that I needed to set UseShellExecute=false. This is my final working code that launches the updater from the .NET service:
var cmd = "/c start updater.exe";
var startInfo = new ProcessStartInfo("cmd.exe");
startInfo.Arguments = cmd;
startInfo.WorkingDirectory = AssemblyDirectory;
startInfo.UseShellExecute = false;
var proc = Process.Start(startInfo);
I did this exact thing - using a simpler (some might say kludgy) approach. The service:
Produces a batch command,
Downloads the new executables to a staging location,
Starts a process: cmd.exe which, in turn, runs the batch script w/o waiting for it to complete, and then
Immediately terminates itself.
The batch command:
Pings 127.0.0.1 five times,
Copies the executables to the final location and,
Restarts the service.
Works like clockwork. The ping is a reliable 5 second delay - lets the service shutdown before copying the files.
Edit:
Just for completeness - I realized that by batch cmd is pinging 127.0.0.1 not 128.0.0.1 and so I edited this answer to reflect that. I suppose either works - but 128.0.0.1 pings timeout, where 127.0.0.1 resolves to "me". Since I'm only using it as a poor-man's delay, it serves the purpose either way.
I am trying to launch an external exe from a web application (running on Visual Studio development server). When I run the code below from a console application it works fine, but when I run it from a web page the application crashes. I presume this must be a permissions issue, but have tried a few things and not been able to get it working.
private void RunExe(string pythonOutputFileNameAndLocation)
{
var process = new Process { StartInfo = GetProcessStartInfo(pythonOutputFileNameAndLocation) };
// This is where the application crashes
process.Start();
// ...do some more things here
}
private ProcessStartInfo GetProcessStartInfo(string pythonOutputFileNameAndLocation)
{
var startInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
FileName = _exeFileLocation,
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = String.Format("--hideUI --runScript {0}", pythonOutputFileNameAndLocation)
};
return startInfo;
}
What I am asking is why this code would work from a console application, but not from visual studio web server?
I am using Windows 7 and Visual Studio 2010.
EDIT:
As requested here are the problem details being caught by Windows:
Problem Event Name: BEX
Application Name:
Application Version: 2.2.2.2909
Application Timestamp: 507bf285
Fault Module Name: MSVCR100.dll
Fault Module Version: 10.0.40219.325
Fault Module Timestamp: 4df2be1e
Exception Offset: 0008af3e
Exception Code: c0000417
Exception Data: 00000000
OS Version: 6.1.7601.2.1.0.256.48
Locale ID: 2057
Additional Information 1: c5a0
Additional Information 2: c5a0d9e876212c0d3929ba8445f002dc
Additional Information 3: 5e93
Additional Information 4: 5e93e44f8aa24f99d37e055f533d1658
I can't debug the external application as I don't have the code from it. Also I don't have a stack trace as I am not getting an exception. The external process is just crashing.
Thanks
Ronnie, you might be running into a UAC and security access issue. Try disabling UAC and trying again. Also, consider on a real webserver this process will be started with the ASP.NET or web user permissions. These accounts are limited on purpose for security reasons. This means the application you are trying to start may fail because it cannot access files it needs. For this reason starting an external exe from a web server is not recommended. However, you can check this stackoverflow question about running applications with admin credentials. How to run c# application with admin creds?
Probably security issue with permissions but it would be best if you could give us some more details about the exception.
Have you tried running this on IIS and checking how it works there?
The exception code c0000417 has the symbolic name STATUS_INVALID_CRUNTIME_PARAMETER. Googling for "python" and "STATUS_INVALID_CRUNTIME_PARAMETER" lead to various python issues around directory permissions. You can user Process Monitor to discover if there are any permission issues while trying to run your application.
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.
We have an internal page that I want to use to run an executable that updates some files on the server. In other words, rather than logging in to the server every time I need to manually run this executable, I would like to run it from the browser. The executable is self-contained on the server and does not interact with the user.
Here is my code:
try
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = Server.MapPath(#"\iPhoneXMLCreator.exe");
p.StartInfo.WorkingDirectory = Server.MapPath(#"\");
p.StartInfo.RedirectStandardOutput = false;
p.Start();
p.WaitForExit();
lblResult.Text = "Success!";
}
catch (Exception ex)
{
lblResult.Text = "Oops, there was a problem.<br><Br>" + ex.Message;
}
When I run it, the process shows up in Task Manager, but then exits within a few seconds without updating the files it is supposed to. There are no arguments to be passed, just a simple executable. Any ideas?
I would start by checking to see if the account which runs the web application has the appropriate permissions.
Most likely this is a permissions issue. Since it's the Asp.Net runtime that is executing this program, you need to ensure that the user account that the Asp.Net runtime uses has access to this executable, and to modify any resources (files, databases, etc) that get modified by the executable.
You can do this via impersonation, or by granting rights tot he appropriate accounts. The proper approach is to use impersonation.
http://msdn.microsoft.com/en-us/library/xh507fc5.aspx
Does the executable file run and process the XML when you run it manually on the server logged in as yourself?
Then it may be a simple permissions issue, since unless you are impersonating ...it's probably trying to run the exe under the ASPNET machine account, which most likely doesn't have rights to the folder the XML is in. Just a thought based on the info you provided.
2 things that you could do:
Run Process Monitor while you attempt to run the exe. I've used it many times to help to find security config problems (especially on web servers). It will log every io and registry access, and more importantly indicate success or failure. Get it here: http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx It requires no setup. Great tool!
Redirect stdout on your console exe. This will allow you to capture any error message that it is attempting to write to the console. Here's how to do it:
try
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = Server.MapPath(#"\iPhoneXMLCreator.exe");
p.StartInfo.WorkingDirectory = Server.MapPath(#"\");
// redirect stdout
p.StartInfo.RedirectStandardOutput = true;
var ConsoleOutput = new StringBuilder();
p.OutputDataReceived += (s, e) => ConsoleOutput.AppendLine(e.Data);
p.Start();
p.BeginOutputReadLine(); // if I remember correctly, you have to call Start() first or you get an exception
p.WaitForExit();
string output = ConsoleOutput.ToString();
lblResult.Text = "Success!";
}
catch (Exception ex)
{
lblResult.Text = "Oops, there was a problem." + ex.Message;
}
Rather than playing with website permissions for the Exe, one workaround that uses a level of indirection and puts a buffer between your web site and the Exe is to simply set a flag value into a text file on the web server when the Page representing the Exe is hit.
Set up a scheduled job on the server to check for that flag value every X hours, or minutes, or whenever and if the flag is seen, run the executable. Reset the flag/file when done. This opens up the possibility to check the flag via a webservice or other mechanisms, such that the target Exe doesn't even need to be on the same web server machine.
This is only viable if the exe does not need to run immediately when the page is hit.
Ok, figured it out. It was a data access issue. The .config file for the .exe had an invalid database connection string. Why it would work when logged in, I'm not sure, but it works now.