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.
Related
I wrote a .NET console application that needs to be scheduled trough Windows scheduler. Such console performs some network and database activities and write a logfile. The application work if run on Desktop/Command prompt but if I try to run it trough the scheduler it refuse to start. Another issue I faced is the write access to the app folder. Even if I set permissions to the folder containing application binaries to be wrote by 'Everyone' the app seems unable to create the log file and/or append data to it. The problem fixes if I run the application with Administrator priviledges (on desktop) but if I define the Activity in the scheduler to Run with higher privildegs this will not fix it anyway.
Best course of action is to create a Service account with admin privileges and schedule the task under such account and select the option to run whether the user is logged on or off.
This approach is even more relevant where Active Directory is in place.
Hope this helps,
Apex
I found the issue... http://support.microsoft.com/kb/2452723
It seems that the "Start In" parameter of the Action should not contain quotes.
Of course the folder should be 'writetable' for the user assigned to the task.
TL;DR: I have a service, a gui, and a tray icon. I want to know how to get the tray icon to run on user login/start-up and be able to stop the service and start the gui
Some Background Info:
I have a windows service I've made that uses a xml file to collect
files from other computers on my network and store them on the local
pc (running the service). the xml has some structures called
'profiles' which have info like FileDestination, LocationToTakeFrom,
FileTypeToTake, and IsProfileActive...
The service basically takes all the active profiles and every hour
scans the location for files created within a 1hr window of the
current date/time on local PC.
My GUI allows the user to make profiles / modify profiles, as
well as determine which profile(s) should be active for collection. I
dont want this gui running at all times, so I plan to have a
systemTrayIcon to allow this GUI to be opened and shutdown.
I'm using Visual Studio 2010 .NET 4.0 everything is in C#, I have 1 solution with separate projects(gui and service)
I'm wondering about the following things as far as the System Tray Icon goes:
1) how do I have the icon start on user login (note that this will be distributed via an installer, not just my personal use. so It has to be done via code)
2) Stop a service via sysTrayIcon
3) where to place the SysTrayIcon... do I make a 3rd project? add it in the GUI project? not quite sure here.
4) if SysTrayIcon IS in a seperate project how can I have it create instances of the GUI?
ie how can I start the GUI application from code in a different project
the project requirements are:
-upon installation the GUI must start, after that the Gui should only be accessed through the tray icon.
-user should be able to stop the service any time via system tray icon
Start the client
There are plenty of ways to start an application on Login under Windows. Just grab SysInternals AutoRuns to get an idea. The obvious ones are (a) the good ol' Startup group and (b) one of the
\SOFTWARE\Microsoft\Windows\CurrentVersion\Run*
keys under HKCU and/or HKLM. That's the typical task of an setup utility, which makes sense since you have to install the service anyway. To do it in code:
Registry: Open the reg key, add the entry, close the reg key.
Startup: determine the value of CSIDL_STARTUP or CSIDL_COMMON_STARTUP using SHGetFolderPath, then create a Shell Link in that folder.
Service communication & control
The GUI part implements the TrayIcon and communicates through some channnel with your service. Again, there are plenty of possibilities how to do this, like disk files or memory mapped files, named pipes, even sockets. It would be too broad to list all the ways here, so I'd suggest to decide for one way and ask again if you have specific questions on that one.
To stop your service from code, use the ControlService() function and pass SERVICE_CONTROL_STOP as the dwControl parameter. To start a service, there's another function named (big surprise) StartService() to achieve that. Note that you may need to start an elevated copy of your app to control services. A quick & dirty way is to simply launch net start/stop MyService elevated with the necessary args.
I am implementing a file system watcher, my requirement is to watch for a given local folder on a machine and then do a small task (for example open a certain page in web browser). The file(s) in the given directory would be generated randomly sometimes every two hours or four etc. This tool should be automated in the sense that a user does not have to start it. So my question is, Should I implement this in a windows service which always will be running or in a console application.Preference is to do it in a console application but then it would need to started by a user right? Please advice
You can automatically call any type of application (Console, Windows, etc.). What it gets down to with a Windows Service is whether you want it to be running before anyone logs in.
Only a Windows service runs while no one is logged in. A console application (while it can be set to run on login) must have someone log in in order to run.
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.
Background
I've written a small C#/.NET 4.0 application that syncs various settings from a game installed in Program Files to and from other copies of the same game on different machines (think Chrome bookmark sync, but for this game). The sync itself is a relatively simple affair, dealing with files stored inside the game's Program Files folder.
On my machine, this works fine without having to elevate my application through UAC. Windows 7 makes the game use Program Files virtualisation and my application works fine with that.
However, on a lot of tester's machines, I'm getting reports that the application either can't work with the files and in come cases can't even see the game's folder! Having the user right-click and "Run as Administrator" solves the problem in every case.
So, we just set the application's manifest to require admin privileges, right? That's fine (although not ideal) for when the user manually invokes the application or the sync process because they'll be interacting with the application and ready to accept a UAC request.
However, one of the features of my application is a "Sync Automatically" option, which allows the user to "set and forget" the application. With this set, the application puts itself into the registry at HKCU\Software\Microsoft\Windows\CurrentVersion\Run to be run at startup and sits in the system tray syncing the settings in the background as needed.
Obviously, I need to be smarter here. Presenting a UAC prompt as soon as the user logs in to their account or at random intervals afterwards isn't the way forwards.
So, my question!
What's the best way to approach a situation where I'd need to run an application at startup that needs administrator privileges? Is there a way to have the user authorise an installation that causes the system to automatically run the application with the correct privileges without a prompt at startup/login?
Update Just to be clear, this must be achievable in code.
You should consider making your Sync functionality exist within a Windows Service.
This is the preferred method for running 'background' functionality on Windows.
The Service can either run under the user's account (assuming they have permissions to modify the files), or you can use another account which does. Worst case, you can run as SYSTEM (although, this isn't best practice).
If you've already got your background process functionality working, then this should be a simple process to convert over to a Service.
There's a sample project here that will set you on the right path: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx
Since you mentioned running at startup, why not use a scheduled task instead of what you're doing with the registry? You can set them up from code - there's a project on CodePlex that is basically a managed wrapper to save you having to do the PInvokes yourself. You run your little "set up the startup task" app elevated, and it specifies that the app should launch elevated, and the user won't even be prompted. I believe that's the answer to the question in your last paragraph.
I would use Security namespace and check inline for the user roles.
using System.Threading;
using System.Security.Principal;
namespace StackOverflow_Demo
{
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal currentPrincipal = (WindowsPrincipal) Thread.CurrentPrincipal;
if (currentPrincipal.IsInRole("Administrators"))
{
// continue programm
}
else
{
// throw exception/show errorMessage - exit programm
}
}
}
}
The currentUser may start your application and will get an info message if he is not member of admininistrator role!
Hope this may help!