Triggering an application from a windows service cannot find file? - c#

Background:
I created a service that will trigger the execution of an application when certain conditions have been met. This service is setup to run under the same windows user account that is used to log on to the system via RDP. I also created the .NET application that is trigger via this service. This application looks for a configuration file on disk (found in the ProgramData folder for the application) uses the settings found in the configuration file to affect the output of this application.
Problem:
When the application is ran by the user interactively the application runs great. However when the service triggers the application to run it appears that the application is not loading the correct values from the configuration files. It's almost as though the application when ran from a service has its own configuration file, and is not using the one found in ProgramData.
I'm just looking for some insight to why this may be happening. I have seem some odd behavior from Windows 7 and Windows 2008 R2 when running applications via scheduled tasks or as a service. It's almost like interactive applications and service applications have different environments on the same system running as the same user...
Note: The service executable is also found in the same folder as the triggered application. I would expect that the working directory by default would be the services running directory.
public int ExecRun()
{
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo
{
FileName = "C:\\Program Files\\TEST\\runme.exe",
Arguments = "/DS:TEMP"
};
proc.Start();
proc.WaitForExit();
return proc.ExitCode;
}

Try adding the working directory info:
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo
{
FileName = "C:\\Program Files\\TEST\\runme.exe",
WorkingDirectory="C:\\Program Files\\TEST",
Arguments = "/DS:TEMP"
};

It sounds like the service that triggers the execution of the application also needs to set the working directory. If you're using the Process class, you'll need to set the StartInfo.WorkingDirectory property the path where your application resides.

This has been solved.
Unfortunately, I think I wasted all your time with this question. The users is running this service on a second system (other than the one they claimed was having this issue). They copied the same configuration to both systems which would've been fine if they had setup both systems the same way, but alas they did not. The file did not exist on the system throwing the error, but both systems were setup to log exceptions to the same location.
The user had to disable the second service, or setup the configuration file correctly.

Related

How to fix DirectoryNotFoundException while using Process in Web App

I'm using Pdf2Text in an ASP.NET web app. The web interface allows PDF files to be uploaded and converted to text. To convert to text, I use the C# function below, which relies on running the Pdf2Text program via the Process library.
void ExtractOCR(string input, string output)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = true;
startInfo.FileName = Server.MapPath("ocr/Pdf2Text.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = input + " " + output;
Process exeProcess;
using (exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
I've double-checked that the input and output paths are all valid. However, when I run the web app, I get the following error.
I've tried the Just-In-Time debugger but it won't even run for some reason. The Pdf2Text is a precompiled file, I don't have it's source code. I believe this is the file's download site, but not 100% sure. I've checked online to find solutions to similar errors but none has worked.
Thank you #GraDea for suggesting to look into the pool's permissions into the web app directory, this was the solution.
The web app was located at a custom location (not the default ASP server directory of inetpub\wwwroot). After the suggestion, I tried adding the pool user to the web app's custom location, but that didn't seem to work. Next, I moved the web app to the inetpub\wwwroot location and added the pool user to the folder, restarted the site via IIS and everything is now back to normal.
For future reference to anyone, easiest fix to a similar problem is to make sure your web app is in the default IIS server directory, and that your site pool's username is added to the application folder's security permissions. I've not tried the fix for a custom location because it's not so important for me, but I'm guessing it will most likely also involve adding the necessary IIS default pool users (e.g. IIS_IUSRS) and the site pool's user.

c# run application as another user fails with System.ComponentModel.Win32Exception

I work with emergency services and they have an application that uses map files to let them know where they need to go and it uses GPS to let them know where they are. We have to update the map files as things change and before I started here they were being done through VB scripts which started to fail. I decided to code my own app in C# to do this which works fine.
I created a package in SCCM 2012 that caches all of the files locally and then it compares the files in the cache to what is on the machine and then replaces any older files. This all works fine but the application they use called MobileCAD locks the files so I have to kill this process and then do the file copy and start the application again. We never know when an emergency happens so this update may start when they are on the road so it is important that it starts the application again as soon as possible. If it does not start the application then the emergency services people may try to do so manually but if core files are being updated then it may not start or cause issues.
I coded my application which uses an app manifest to force it to run as an administrator for the file copy. This application is run through SCCM which uses the local 'System' account to do all of the work and killing MobileCAD and copying files which works great. What I originally found was that it does start MobileCAD but it does so under the System account and the process would be there but it was not visible. I think this is the same problem they were originally having so the emergency services people would need to reboot the computer and wait for it to log back in and then start the wireless service so they could get back into MobileCAD.
To address this issue I did research and found that I could use the ProcessStartInfo in .NET and force it to use another account. As we use an automatic logon for these machines the users name, password, and domain are all in the registry so it was easy to pull it out and inject it into the code. Awesome, looks like it is easy enough so I code it up and sure enough it works perfectly when run under my admin account. In my basic testing everything worked perfectly until I try the same in SCCM, now it fails with the following error message.
System.ComponentModel.Win32Exception (0x80004005): Access is denied
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at UpdateFDM.Program.StartProcess(String processName)
I am sorry for all of the words but I believe it helps if you have a good understanding of the issue and what I am trying to do. I have also hard coded the user information into the code instead of pulling it from the registry but I get the same error. Again, this works fine under my admin account but fails when it is pushed through SCCM and it is only launching MobileCAD that fails.
This is the code I am using for launching MobleCAD, do you see where my issue may lie? I know SCCM confuses it but SCCM basically runs things just as you would from the command line but it uses the local System account.
Thanks for any help.
// Declares the new start instance
ProcessStartInfo process = new ProcessStartInfo();
// Gets the process to start
process.FileName = processName;
// Maximizes the process windows at start-up
process.WindowStyle = ProcessWindowStyle.Maximized;
// Gets the user name from the autologon information
process.UserName = GetDefaultUserInfo("DefaultUserName");
// Gets the domain for the user
process.Domain = GetDefaultUserInfo("DefaultDomainName");
// Holds the password for the default user
SecureString password = new SecureString();
// Gets the raw password from the registry
string rawPassword = GetDefaultUserInfo("DefaultPassword");
// Copies the password in a secure string
foreach (char ch in rawPassword)
{
password.AppendChar(ch);
}
// Sets the password
process.Password = password;
// Needed to launch the app as the logged on user
process.LoadUserProfile = true;
process.UseShellExecute = false;
// Starts the process
Process.Start(process);
// Process started, return true
return true;

Scheduling C# app throughts Webclient exception

I have developed a c# application to download a zip file from a site, when manually run the app, it does its job normally and exits, But when i schedule it to run automatically using task scheduler in Windows, it throws web client exception error. Please help me regarding this
The part of code for downloading the file is
WebClient wc = new WebClient();
wc.DownloadFile(<site>, "feed.zip");
System.Diagnostics.ProcessStartInfo pinfo = new System.Diagnostics.ProcessStartInfo("extract.bat");
System.Diagnostics.Process process = new Process();
pinfo.CreateNoWindow = true;
pinfo.WorkingDirectory = Directory.GetCurrentDirectory();
process.StartInfo = pinfo;
process.Start();
process.WaitForExit();
The batch file extracts the zip file.
I see these possible problems:
If you run your application Directory.GetCurrentDirectory() could result in a different path. Directory.GetCurrentDirectory() will be set to your bin-folder, but in your production environment, it can point every, depending how your process is executed (for example: if you create a shortcut on your desktop, you can also modify the Start in-folder.
If your current directory is configured wrong, the application would also not be able to find extract.bat.
While you are debugging you have some rights on your outputfolder. But when your application is executed as a batch process, it runs under a different account. Does this account have to rights to write to your output folder?
The website your are accessing might require a valid account. You possibly have a valid account. But the account your application is running from in production, might not be valid account for that website.
You are possibly behind a proxy. Perhaps you need to configure some extra settings for getting past that proxy. In your account, these settings are configured inside Internet Explorer. Perhaps the production account does not have these settings configured.

Automatically restart a self hosted wcf service on crash

I have a self hosted wcf service that is using legacy c++ code via dll import and pinvoke. There are some instances in the old code where exceptions arise from the functions (that were handled in the old app, but not in the service) and when they occur my service is stopping. The exceptions are rare; however, I do not want my service just randomly stopping as a result of a crash in another assembly. The exceptions are not bubbling up to the service so I cannot try/catch them in the service. Is there a way to automatically have the service restart on crash?
It is self hosted, not through IIS.
Thanks in advance!!
On the machine where the service is running, you can open up the Services management console (start > run > services.msc). Find your service, right-click it and choose Properties. In the popup, click on the Recovery tab. Set First, Second, and Subsequent failures all to Restart the Service.
If you are using WIX to install your project, you can also set these properties using the util:ServiceConfig element.
If you're using a standard ServiceInstaller, these options aren't built in. I'd recommend having a look at the ServiceInstaller Extension class which exposes properties through a standard service installer interface.
Well I'm assuming that you are creating a Windows Service project for what you are doing. Go into your ProjectInstaller and find the "AfterInstall" method. Here you will need to add code to execute a command on the Service Controller to set recovery options. Unfortunatly, even though .NET has a ServiceController you will need to execute the command through a process start.
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;
process.Close();
}
Note: I stole this code from another question

How to start the bat-file at Asp.net web server side?

I need to call a console application to load data into another desktop application on the remote server that located within the corporate domain.
Users will enter the web page and upload data to asp.net web server, which after transformation should call that console application. Users are located remotely and do not have any other access except the web server.
I decided to lower the security web application context and let the asp.net working process to start the console application on the current IIS 6.0 web server
What I have done:
I changed the security account for the application pool for Local System;
I added ASPNET Account and IIS_WPG IIS Process Account to Administrators group;
I added “Allow service to interact with desctop” for “IIS Admin Service” and “World Wide Web Publishing Service” processes and restarted the machine;
I tried to start BAT-file at server side through the test page code-behind, but failed:
protected void btnStart_Click(object sender, EventArgs e)
{
Process process = new Process();
process.StartInfo.FileName = #”C:\run.bat”;
process.StartInfo.UseShellExecute = false;
process.Start();
process.WaitForExit();
}
The error was access denied.
Please help me to find any workable idea how to start the bat-file at web server side.
Thanks
Try setting UseShellExecute to true instead of false. After all, batch files run in a shell - so you need a shell to execute it. (Another option is to run cmd.exe and pass the name of the batch file in as an argument, e.g. "cmd.exe /k c:\run.bat")
You might also want to try creating a simple .NET app which just (say) creates a file with a timestamp in. That way you can test the "can I start another process" bit separately from the "can I get the batch file to work" bit.
Put that particular batch file in your application itself.
string str_Path = Server.MapPath(".") + "\\run.bat";
ProcessStartInfo processInfo = new ProcessStartInfo(str_Path);
processInfo.UseShellExecute = false;
Process batchProcess = new Process();
batchProcess.StartInfo = processInfo;
batchProcess.Start();
Take a look at this example: Run Interactive Command Shell or Batch Files From ASP.NET
It uses little different approach. They suggest running cmd.exe and executing command line by line.

Categories

Resources