Process not functioning on cloud after started by Windows Service - c#

We have a Windows Service that checks a configuration file, and based on those settings, starts a new Process (let's call this ClusterProcess) which connects to a database and does the actual functionality.
There is a test project, that cuts out the Windows Service's part in the play, and just provides ClusterProcess with the necessary settings.
For our current test environment, we have the database on a cloud and I would say, rather restricted permissions.
My problem is this: when I run the test project, ClusterProcess gets its settings and things happen on the database. However, when I run the Windows Service, nothing gets changed on the database.
I've been using log4net to try and see where things fall over, but it seems to fail silently.
So the Windows Service calls this:
_ClusterRunnner.StartAllClusters();
In this method mentioned above, this is (amongst other things) what happens, and I get both log statements:
_ClusterProcesses = new List<Process>();
log.Debug("Cluster Name: " + cluster.Name + " ConfigPath: " + _ConfigPath);
_ClusterProcesses.Add(Process.Start(startInfo));
log.Debug("After process spawn.");
Okay, so the Process that it should start is ClusterProcess.exe, and in the Main method of that project I don't get any of the log statements that should be given, for instance:
log.Debug("Going to Start Processing");
_ClusterProcessor = new ClusterProcessor(config);
_ClusterProcessor.StartProcessing();
log.Debug("Finished Processing");
With log4net I have a special logger for ClusterProcess.exe (two appenders, a RollingFileAppender and an AdoNetAppender) and similar appenders for the Windows Service. (The Windows Service process holds a lock to its RollingFileAppender, so I had to create a special one for ClusterProcess.exe. The AdoNetAppenders are for nicely formatted logs after the connection to the database has been made.)
But now, the test project just calls this directly:
ClusterProcessor x = new ClusterProcessor(config);
x.StartProcessing();
and it works! I get the log statements in StartProcessing() and the database is changed.
So any ideas?

From my experience with services they run with very limited rights.
So if your Test(possible windows application) runs perfectly then I guess it has something to do with user rights.
I guess you can't realy access the filesystem so if your logger writes to a place on the harddrive you should think about the windows event log --> Write to Windows Application Event Log without registering an Event Source
To try if it has something to do with user rights just open your service in the windows service settings and let it log on as your administrator account and see if it has something to do with this.

Related

Launch an executable from within a windows file watcher service

I have a file watch service, written in C#, that I need to launch an application when it detects the file drop. I am using notepad as a test application to launch. The file watcher is working fine, but I cant get notepad to launch. Any assistance with what I am missing would be great.
Code that fires when the file drop is detected:
public void FileCreated(object source, FileSystemEventArgs inArgs)
{
Process LaunchApp = new Process();
LaunchApp.StartInfo.FileName = ConfigurationManager.AppSettings["AppStartPath"];
LaunchApp.Start();
// Process.Start(ConfigurationManager.AppSettings["AppStartPath"]);
Log.WriteLine(" File added: " + DateTime.Now + " " + inArgs.FullPath);
}
Path reference from the app.config:
<add key="AppStartPath" value="Notepad.exe"/>
I also tried:
<add key="AppStartPath" value="C:\Windows\System32\Notepad.exe"/>
I have a file watch service,
Services run in a separate security context to processes in a user logon session.
This can be seen if you add the Session ID column to Task Manager's Processes tab, or – better, in Process Explorer.
Any processes the service launches will run in the service's own context: not the user. There are very good security reasons for this.
To perform interactive operations from a service you need a per user agent that is run in the user's context. Typically the service listens on a named pipe and the user agent is run from the startup group (or Run key in the registry). The agent connects to the named pipe and can respond to requests from the service (or the service from the user agent).

Finding which service has run an executable in C#

I was wondering if it were possible to find out which windows service has run an executable?
I've got two different services running from the same exe, doing different things. The main method of the program detects a command line parameter and will either start the console app (if running in Environment.UserInteractive), or start one of the two possible services. I can't find a good way to discern which service is running so I can choose the correct service to start in the code. Passing in .exe parameters in the image path of the windows service doesn't seem to work. The services are running on a server and starting automatically, so doing it manually isn't really an option.
I'd really like to avoid having to have two different projects with different executables, so any way I can notify the program of which service to run would be great.
You can pass arguments in the ImagePath. I know I have done it at some point using a .net windows service, but as I recall, I had to install the service using something other than the standard .Net installer.
The .Net installer adds quotes around whatever you pass, which makes ImagePath go from C:\test\test.exe -arguments to "C:\test\test.exe -arguments" when it should be "C:\test\test.exe" -arguments.
Check out WiX, sc.exe or CreateService to get the correct registry value.
To test, install your service as usual and browse in regedit to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\yourServiceName and edit ImagePath. For an example of how it should look, check out HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\seclogon.
You could create a Mutex in your service at the point it starts, using a name unique to the version it is running. If the mutex is obtained then you know it isn't running. If it can't be obtained then the service is already running.
You could then start your services through a new process that first tries to obtain the mutex for the first service and if it can't obtain it it starts the second.
So, you start ServiceRunner.exe -foo. A mutex called "foo" is obtained, so you release the Mutex and ServiceRunner.exe starts Service.exe -foo.
If the mutex is not obtained you then try to obtain a mutex called "bar" and follow the same process.
This is a nasty solution, and would require your to create a new exe that simply tries to start the services.
Have your service share its start state( temp file, registry key or other method, it could even write this as html to a web server... )
ServiceController yourService = new ServiceController( "YourServiceName" , "YourMachine" );
if( yourService.Status == ServiceControllerStatus.Stopped )
{
yourService.Start();
}

Windows service can't write to %LOCALAPPDATA%

I have built an app that works only when not run as a Windows service. Well, the service runs, but it doesn't do what it should. The service uses the Local Service account. So to kick off debugging, I thought I'd start with something simple: have it create a directory when it starts:
Directory.CreateDirectory(
Environment.SpecialFolder.LocalApplicationData + "\\MyService");
When I started the service, it stopped almost immediately and Windows reported that fact. When I commented out the above statement, recompiled and re-installed, the service ran without stopping.
Obviously the above line throws an exception of some sort. I have no way of logging the error because I can't write to the file system. Any ideas why Local Service can't create a directory in its own %LOCALAPPDATA%?
You should use GetFolderPath with LocalApplicationData like so:
string folderName = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData),
"MyService");
Directory.CreateDirectory(folderName)
I think this might be because there is no special folder. When running as the local service account you are running under that user, not the logged in user. so you are requesting a special folder that probably wont exist, as I don't think the local service has a profile. (I may be wrong) - I was wrong :p
Just in case anyone pops by:
C:\Windows\ServiceProfiles\LocalService
is the local service profile folder, so it will end up in there.
If you want to debug it surround that line with a try catch, and then write the error to a file:
try
{
Directory.CreateDirectory(Environment.SpecialFolder.LocalApplicationData + "\\MyService");
}
catch (Exception ex)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\MyServicelog.txt",true);
file.WriteLine(ex.Message);
file.Close();
}
At least then you can see whats causing the error
Martyn
I suggest you write the exception details to the event log. All user accounts have permission to write to the event log as long as the log and source names have already been created by an administrator (which you can do simply by running the app as yourself first).
As to the root cause of the error, it may be because LocalService doesn't normally get a full set of profile folders created by default. I'm not sure whether this is by design, or simply what I have observed on various machines.

Set service dependencies after install

I have an application that runs as a Windows service. It stores various things settings in a database that are looked up when the service starts. I built the service to support various types of databases (SQL Server, Oracle, MySQL, etc). Often times end users choose to configure the software to use SQL Server (they can simply modify a config file with the connection string and restart the service). The problem is that when their machine boots up, often times SQL Server is started after my service so my service errors out on start up because it can't connect to the database. I know that I can specify dependencies for my service to help guide the Windows service manager to start the appropriate services before mine. However, I don't know what services to depend upon at install time (when my service is registered) since the user can change databases later on.
So my question is: is there a way for the user to manually indicate the service dependencies based on the database that they are using? If not, what is the proper design approach that I should be taking? I've thought about trying to do something like wait 30 seconds after my service starts up before connecting to the database but this seems really flaky for various reasons. I've also considered trying to "lazily" connect to the database; the problem is that I need a connection immediately upon start up since the database contains various pieces of vital info that my service needs when it first starts. Any ideas?
Dennis
what your looking for is SC.exe. This is a command line tool that users can use to configure services.
sc [Servername] Command Servicename [Optionname= Optionvalue...]
more specificly you would want to use
sc [ServerName] config ServiceName depend=servicetoDependOn
Here is a link on the commandlike options for SC.EXE
http://msdn.microsoft.com/en-us/library/ms810435.aspx
A possible (far from ideal) code solution:
In you startup method code it as a loop that terminates when you've got a connection. Then in that loop trap any database connection errors and keep retrying as the following pseudo code illustrates:
bool connected = false;
while (!connected)
{
try
{
connected = openDatabase(...);
}
catch (connection error)
{
// It might be worth waiting for some time here
}
}
This means that your program doesn't continue until it has a connection. However, it could also mean that your program never gets out of this loop, so you'd need some way of terminating it - either manually or after a certain number of tries.
As you need your service to start in a reasonable time, this code can't go in the main initialisation. You have to arrange for your program to "start" successfully, but not do any processing until this method had returned connected = true. You might achieve this by putting this code in a thread and then starting your actual application code on the "thread completed" event.
Not a direct answer put some points you can look into
Windows service can be started Automatically with a delay. You can check this question in SO for some information about it.
How to make Windows Service start as “Automatic (Delayed Start)”
Check this post How to: Code Service Dependencies

UAC gives me fits!

The code I am currently working on runs on Windows Server 2003, but needs to be able to write to EventLogs on multiple machines. I am coding in C#, using VS2008 Pro, and .NET Framework 3.5.
The code itself is relatively simple (thanks to the framework):
using (EventLog remoteEvtLog = new EventLog(LogName, HostName, EventSource))
{
remoteEvtLog.WriteEntry(Body);
}
"LogName" is a string containing the name of the log to write to - in most cases "Application".
"HostName" is a string containing the NetBIOS Name of the machine where the log entry should be written.
"EventSource" is a string containing the name of the event sender (this is a utility used by multiple apps, so usually it will have the name of the consuming application).
"Body" is a string containing the text to be written to the event log.
In most cases this works fine, but when the machine being written to uses UAC, any write which creates a new EventSource fails. This occurs even though the Security credentials used are members of the Administrators group - and I have not been able to find a way to specify the elevated priviledge level. Apparently, members of the Administrators goroup get two tokens - one limited, and one elevated, but as far as I can tell, the only way to specifiy the elevated token is through the UI - which is obviously a problem when remotely accessing the Logs.
Any ideas out there?
Your code is not supposed to create new event sources (the legacy auto-create behavior is unfortunate, but still wrong). If you need a separate event source for your application, then the installer for that application - which runs with elevated administrative privileges - should create it.

Categories

Resources