I'm having a bit of trouble with an application i'm developing.
Here's the scenario: I have two Windows Services (Service A and Service B) written in C#.
Service A is responsible to transfer data between two applications (using WebServices, FTP connections, etc). It's also responsible to update Service B.
Service B is responsible to update Service A and update a Web Application.
The basic operation of updates is (lets say this is the process to update service A, done by Service B):
Check for updates through WebServices
If there is a new version, stop the service (using C# ServiceController).
Backup current files of the service (so I can do a Rollback if something goes wrong)
Uninstall the service (using sc delete command)
Download the updated files of the service (using FTP connection)
Execute some SQL Server scripts, if exist
Install the Windows Service (using sc create command)
Start Service (using C# ServiceController)
Everything runs smoothly until step 7. I figured that the problem is that the user doing the update (the user that runs Service B) does not have permissions to create new windows services, so SC Create always returns something like "[SC] OpenSCManager FAILED 5: Access is denied"
Note that I had both services running with LocalSystem Account. So, I figured that this account cannot create new Windows Services (correct me if I've assumed wrong).
After this I've created a new Windows User, just to run the services. The idea was to give this user the necessary permissions (to network shared, files and create services). However, this user still can't create the service.
Here's what I've tried:
Give the user cmd.exe and sc.exe permissions (using CACLS).
Use PsExec to run cmd (with -i -s) instead of cmd.exe directly.
Using the SubInAcl command so the user has permissions to the both Windows Service. But here's the thing, at the time I don't have any Service, so it doesn't work.
Some remarkes:
This Windows Services don't have any installer.
The SC command is run using C# ProcessStartInfo.
The SC command specifies the user and password of the Windows User that I've created.
I really don't want the Windows Services to be run under a user account with Administrative Privileges.
I know that this thread is similar to some already here Auto-update a Windows Service, however I cannot find any working solution anywhere.
Sorry for the long text
I think your basic design is brittle and flawed. You should not be deleting and creating services as part of normal service operation.
What I would do would be to arrange that any service that needs updating in place was capable of doing it by itself. Basically put all the code that is subject to update in a DLL. The code in the service EXE is just a thin host in charge of loading the main DLL and invoking it's main processing loop. When the EXE determines that it is time to update it downloads the new DLL, presumably checking via a hash that it downloaded correctly. Next the processing loop is terminated, the old DLL is unloaded, the new DLL is loaded and the processing loop started again.
This approach is much less intrusive and avoids all permission and rights issues. You can write a single service host EXE and have multiple DLLs containing the logic.
Related
I want to create one small application for the kill particulate exe in all user login .
I have a server in this we are create one local domain and i create more then 100 users and that all are login with domain user like. (domain)\userid : xyz\josep
Now my point is that I want to kill eg.paint.exe from all users task manager.
How to possible in c# I don't know how to start work.
Process proc = Process.GetProcessesByName("paint");//?? How get process from another user?
proc.Kill();
Hellp sir ,
My que is not a duplicate. sorry for that I am not proper explain question. I want to kill particular exe to all employee's machine. so how can do this. this kill process method used fro own machine but i want to kill user's machine exe
OK, here's an outline of how to do this:
You need a service application that does the actual work, i.e., kills all processes running the target executable on the local machine. Once this is done the service should stop. If it fails, the service should stop with an error code.
From your application, copy the service application to the target machine.
Install the service using CreateService and related functions. Note that the OpenSCManager function allows you to specify a remote machine.
Launch the service using StartService and related functions. Note that StartService allows you to pass arguments to the service, e.g., the name of the executable to target.
You can use QueryServiceStatus to poll until the service has stopped, and to retrieve the error code. Or you could use some suitable choice of IPC between your application and the service.
Once the job on the target machine is done, you can uninstall the service with DeleteService and then delete the copy of the service application on the target machine.
Some notes:
There are presumably .NET methods that you can use in place of the Win32 API functions if you prefer. I know you can write a service application in .NET, though I've never done so myself.
For bonus points the service application and the main application can be contained within the same executable, or the service application executable can be stored as a resource inside the main application executable. I'm not sure whether that's plausible in .NET though.
Obviously, the user running the main application must be an administrator on the target machine, and the target machine firewall must be configured to allow connections. (I'm not sure offhand exactly which exceptions need to be enabled on the firewall, but at a minimum the file sharing exception.)
This all assumes that you can't install the service on the target machine ahead of time. If you can, that makes things somewhat simpler. It also means the user running the main application doesn't necessarily need to be an administrator, and gives you the option of listening on a TCP/IP port of your choosing and only creating a firewall exception for that particular port.
You'll want to use Process.Kill(), something like:
try
{
Process proc = Process.GetProcessesByName("paint");
proc.Kill();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
I have written a C# console application that uses the Interop.domino.dll assembly to interact with domino / notes to create, update and delete documents. The application runs successfully when running it manually through a cmd prompt or through Visual Studio. However, when we try to set the application up as a scheduled task (running under a domain service account) it fails with the following error:
System.Runtime.InteropServices.COMException: Retrieving the COM class factory for component with CLSID {29131539-2EED-1069-BF5D-00DD011186B7} failed due to the following
error: 80004005 Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL)).
The error occurs as soon as we try to use an object from the Interop.domino.dll, specifically when try to create an instance of the NotesSession object as per the following:
ISession notesSession = new NotesSession();
After some investigation I found that the interop assembly requires a desktop to interact with and that if we ran the scheduled task with the service account logged into the machine that the scheduled was running on the scheduled task would run successfully. While logged in as the service account you could see that the application would bring up a svchost.exe window while the application was running and that is the reason it requires the desktop.
However, having the service account logged into the machine all the time is not an acceptable solution as it means that the account has to be logged in again each time the server restarts. There are also some security concerns around having about allowing a service account to login to machines.
So, I was wondering if anyone had any suggestions on how to get around this issue? Is there a way to suppress any UI that the assembly tries to show? Alternatively, can anyone suggest an alternate to a scheduled task which would achieve a similar result. What we need to do is:
Have the application run at a set interval (IE - once a day / once an hour)
Ideally, have it run under a domain service account (as opposed to a local system account)
Run without requiring the service account to be logged into the machine / UI elements from the Interop.domino.dll suppressed
We have thought about writing a similar application making use of the notes web services rather than the Interop assmebly and will go down that path if we can't get the console app running as a scheduled task. However, we would like to make use of what I have already written if possible.
Update 01/05/12
I have tried etting the NOTESNTSERVICE OS environment variable as per #dna-man solution. However, this did not solve the issue.
For now we have set the application up as a windows service running under the local system account and with interactivity with the desktop allowed. This is not ideal as it does not allow us to schedule it as easily and it is not running under a domain service account, but the application does work so we will go with this approach for now.
There was an answer that suggested this approach, but it seems to have been removed so I can't mark it as correct. I might leave the question open a bit to see if anyone else has any suggestions.
If your code is running on a Domino server you must make sure the OS environment variable NOTESNTSERVICE=1 is set. You can find out more abou this environment variable in the Lotus C API documentation, but it applies to the COM API as well when running as a service. I had created way back in 2003 a VB.NET application that had to run as a service, and setting this environment variable was the key. If it wasn't set, the service would stop working as soon as I logged off the machine. To make sure somebody didn't forget to set this environment variable when installing the service in the future I simply had my service manager start code set this environment variable directly on startup using the VB.NET call to SetEnvironmentVariable. It had to be set before creation of the Domino session object.
It's hard to say exactly why, but I believe it's failing to read the registry information for the Lotus interop classes. Obviously the entries are there, otherwise it would not work while running manually. So let's consider other possibilities.
I don't even know if this is possible, but os your application running as 32 bit when run manually, but 64 bit when scheduled? IBM doesn't support the Domino COM classes on Win64, and I'm pretty sure that the first symptom of that is that the registry l
A more mundane possibility is that the service account just doesn't have access to read the registry entries for the Notes/Domino install on the machine, possibly because the software was installed under a specific user account.
I ended up modifying the application slightly to set it up as a windows service running under the local system account and with interactivity with the desktop allowed. This is not ideal as it does not allow us to schedule it as easily and it is not running under a domain service account. However, this approach does allow the application to run without requiring an account to always be logged in and does allow for the interop UI elements to be shown (thus avoiding the error).
To schedule the windows service to perform the task at a set interval (which I set at once a day) I used the Timer solution proposed here.
I have a web app and want to transfer data from client's machines to us every day. Assume there is a common API on every client machine to extract data from. To make this work, I have to create:
An API to receive data from clients - using WCF, seems ok at this point
An application that's installed on client machines
The client app needs to store info from the user (eg username/password to access our API - encrypted with DPAPI). The app needs to run daily (probably with a random Sleep() command so our API isn't overloaded all at once). It also needs to be easy to install.
I've created a console app which talks with the client API and our own API. I've used Visual Studio's Settings.settings with a user scope to save the persistent settings - if parameters are provided then it stores these settings, if no parameters it uses the stored settings.
How can I make this usable for the end user? I'm thinking a separate installer/configuration program that installs the exe file (and its dependencies) and asks the user to enter the settings to be stored (which can also be read by the client app). It would have to set up the scheduled task and also offer the ability to change the configuration (the stored shared variables).
Hoping someone can help architect this solution?
Thanks so much!
I think that your idea about an installer is correct since you will most likely have dependencies or prequisites to install.
However, rather than building the settings logic into the installer, I would recommend that you build a UI for this in your application so that the user can adjust it post-installation if needed.
For example, if the user changes their password, in your current design, the user will have to uninstall and reinstall the app. Also, if the scheduled time is incompatible with some other operations on their machine, then they will need to adjust the time without uninstalling and reinstalling.
You could build the UI and API interface into a single application: just change the behavior (runtime or configuration) with a command line switch (for example, only use a /runtime command line switch for the scheduled task).
I have a Windows service which I want to periodically execute an external program. I'm currently doing this the usual way
Process program = Process.Start(#"C:\mpewatch\db_parameters\DBParameters.exe");
This doesn't seem to be working. I'm executing this from a separate thread which is started in my service's OnStart handler. Is there any conceptual problem with this? Is it not possible to execute external programs from a service like this?
You can execute external programs from a service, but there are security issues. For example, your service may be running under an account which does not have read access to the folder where the external program resides, even if your interactive account does have that access.
For test purposes, try to configure the service to run under your interactive account. If the program is invoked as expected, then the problem with the original account is that it does not have sufficient privileges to run the program.
Your question didn't indicate the operating system.
On Windows XP, you can configure your Windows service to interact with the desktop by opening the service control panel, double-clicking your service, selecting the Log On tab, configuring the service to run as local system, and checking the checkbox. It's pretty straightforward. You might try testing with something like Notepad.exe just to see if you can get it working.
On Vista (and presumably Windows 7), however, you may be out of luck. I have read that the ability for Windows services to interact with the desktop has been removed in Vista. I forget what the terminology is, but basically services will run in "shell 0," whereas users will occupy "shell 1". User applications will be able to communicate with services and vice versa using technology like WCF, but services will not be able to communicate directly with the desktop. For example, any error boxes that pop up will have to be dealt with by swapping to "shell 0." Again, this is based on something I read a few months ago, and I haven't gone looking at it again. For me, I've structured my Windows service to be configured using WCF via a front-end app.
I'm sorry I don't have a link for you, but if your service will eventually have to migrate to a newer OS (or you are already there), this is something to check on.
Another critical consideration with Windows Services is that there is no GUI. Technically, there is an option to allow the service to interact with a local GUI, but you will not see it. This is due to services running as the Local System user.
Within a service, any modal dialog box (OK, Cancel, etc) is considered an error.
Currently I have an application used to update my software, this is a standalone executable that's only job is to perform software updates.
When it is launched it copies itself from a \Binary\ to \Running\ folder and then executes itself in \Running\ to perform the work (so the copy in \Binary\ is never locked or in-use), in the case where it needs to update itself it simply updates the copy under \Binary\ so next time it is run the newer copy is executed and there is no issues. This process has worked fine for years ...
Now I need to make a change, I need to move this process to a SERVICE (so it can perform software updates as LocalSystem where it has Admin rights) - can I use the same model? Can a service, when it starts, copy itself from \Binary\ to \Running\ and run from the \Running\ folder at all times?
Otherwise, any suggestions on how I could update Service.exe?
Any advice, help, suggestions would be greatly appreciated.
Thanks,
On a project in the past, we used a two-phase update:
first, a very very small simple program called Stub would check for updates to the actual updater (called CopyFiles). If CopyFiles was newer on the server, it would get copied down.
then, Stub would launch CopyFiles and terminate itself.
CopyFiles could then update Stub if needed as well as all the main application files.
CopyFiles would then launch the main application executable.
For your scenario, I can forsee two services running - one which is your actual application and another which monitors your \Binary folder. That service, having Admin rights, can shut down the actual application service, copy the updates to \Running and then start the app service back up again.
What if you create a separate Windows service that invokes your existing app? As long as your app doesn't have a GUI and doesn't assume its running under a user account (e.g. doesn't access HKCU registry keys), then that should work. Under Windows a child process inherits the security context of the parent process, so the standalone exe invoked from the service should run under the service account configured.