C# process cannot run on IIS - c#

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.

Related

Starting a process

As part of SharePoint automation testing, I am trying to open Internet Explorer as another user by using the System.Diagnostics.Process . Here is the following C# code
System.Diagnostics.Process p = new System.Diagnostics.Process();
// Domain and User Name:
p.StartInfo.Domain = "MYDOMAIN";
p.StartInfo.UserName = "myusername";
// Command to execute and arguments:
p.StartInfo.FileName = "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
p.StartInfo.Arguments = "http://url/AllItems.aspx";
// Build the SecureString password...
System.String rawPassword = "thepassword";
System.Security.SecureString encPassword = new System.Security.SecureString();
foreach (System.Char c in rawPassword)
{
encPassword.AppendChar(c);
}
p.StartInfo.Password = encPassword;
// The UseShellExecute flag must be turned off in order to supply a password:
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = false;
p.Start();
When I run this automated test Visual Studio returns informing me that the test was successful, however Internet Explorer does not open.
Is there something in my code I am missing in order for a window to appear? There is no iexplore process running prior to the test being run.
putting double quotes around the file path (since it contains spaces) may help:
p.StartInfo.FileName = "\"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\""
^^ ^^
In addition, if your intention is to start this from a service process or dll running in a service such as "SharePoint", then this code will probably not launch the process in the desktop desired. You'll need to set the desktop to "winsta0\\default" in the startup info.
To run a process the worker process should have high privileges and this is not an ideal case in any web application. If your purpose is to use IE for unit testing then I would consider using something like WaitIN. If your purpose is for application logic to access a URL and do something then consider using HttpWebRequest. If you still need a process to be started then create a Windows Service and then expose a web call so in Share Point you can just make a call and your Windows Service can run on local account or some other high privilege account.
Hope this helps and please provide the scenario why you want to start the IE and that can give you a better answer in the forum.

How to start an exe from a .NET Windows Service for updating the service

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.

Permission issue running .exe from ASP.NET web application

We have a .exe which we need to execute at the time an order is placed on a website. When
we test this locally it works fine using IIS Express. When we move it to IIS, it fails. We assume this is a permissions error as if we set the App Pool to run as the administrator then the script works again. The question we have is how do we execute the .exe as the administrator whilst the App Pool is ApplicationIdentity? We are using the following code:
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = executablePath,
Arguments = argumentList,
Domain = domain,
UserName = userName,
Password = securePassword,
UseShellExecute = false,
LoadUserProfile = true
}
};
process.Start();
process.WaitForExit();
process.Close();
The .exe is trying to write to the Users AppData folder which is why it fails. It is a 3rd party app so we cannot change the source code.
EDIT: Just to clarify also, when we specify the username and password in procmon it still appears to run from ISUR.
We fixed this by enabling User profile on IIS AppPool and setting permission for the IIS user on the folder it was trying to write to.
We sue ProcMon to find where the program was failing and the folder it was trying towrite to was C:\Windows\System32\config\systemprofile
i dont remember actually, but one of them is working 100% ( i had this issue before)
just let me know ehich one of them is the correct one.

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.

Run exe from webpage

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.

Categories