Self-installing a service that executes with parameters - c#

I have a console application that will optionally self-install itself as a service. This works fine, but I'd like to embed some arguments into the service startup - similar to (for example) Google's Update Service (which has the parameter /medsvc)
So let's say I'd like my service to start
MyService.exe RUN Test1
.. so that'd start up MyService.exe with the parameters RUN and Test1.
I can install the service fine, using
ManagedInstallerClass.InstallHelper(new[] {Assembly.GetExecutingAssembly().Location});
However, there's no parameters on the service. So if I try:
ManagedInstallerClass.InstallHelper(new[] {Assembly.GetExecutingAssembly().Location +" RUN Test1"});
I get a FileNotFoundException. Giving that it's a array, I thought I'd try:
ManagedInstallerClass.InstallHelper(new[] {Assembly.GetExecutingAssembly().Location,"RUN","Test1"});
.. which gives the same exception, except that it's trying to find the file RUN now.
I can't find any specific documentation on how to achieve this - does anyone know if it is possible to embed parameters in with the service executable path? As another example, here's Google's Update Service with parameters - I'd like to ultimately achieve the same.

It took me a while to find this out, I hope it's still useful to someone.
First I found out, that you are not supposed to run ManagedInstallerClass.InstallHelper according to MSDN docs:
This API supports the product infrastructure and is not intended to be
used directly from your code.
Then I found out I could just use my own ProjectInstaller (a component class I added containing a Service Installer and a Service Process Installer) to install the service like this:
ProjectInstaller projectInstaller = new ProjectInstaller();
string[] cmdline = { string.Format("/assemblypath={0} \"/myParam\"", Assembly.GetExecutingAssembly().Location) };
projectInstaller.Context = new InstallContext(null, cmdline);
System.Collections.Specialized.ListDictionary state = new System.Collections.Specialized.ListDictionary();
projectInstaller.Install(state);
Be sure to encapsulate your parameters in quotes and escape the quotes, otherwise your parameters will become part of the executable path and fail to start.
The end result will be a new service with the specified properties in your Service Installer and Service Process Installer, and a path just like in your screenshot (with the /medsvc parameter for example).

I use a console application inside my windows service. The Main method in Program.cs processes the command line args. The OnStart method starts the console application. It works great.
Windows Service to Run Constantly
HybridService Easily Switch Between Console Application and Service

Only parameters before location are being passed into the context for the installer.
Try this:
args = new[] { "/ServiceName=WinService1", Assembly.GetExecutingAssembly().Location };
ManagedInstallerClass.InstallHelper(args);
Reference from another answer: Passing Parameter Collection to Service via InstallHelper

Related

Process.Start() does nothing when called from a C# written service

I have created a service that works good, except for this section that don't do what I want
shutdownProcess.StartInfo.RedirectStandardError = true;
shutdownProcess.StartInfo.WorkingDirectory = #"C:\Program Files (x86)\Siemens\Automation\WinCC RT Advanced";
shutdownProcess.StartInfo.FileName = #"C:\Program Files (x86)\Siemens\Automation\HmiRtmShutdown.exe";
shutdownProcess.Start();
string errors = shutdownProcess.StandardError.ReadToEnd();
eventLog1.WriteEntry(errors, EventLogEntryType.Error, eventId++);
The problem is that the process is not executed;
as you can see I tried to record errors in a log, but the log records a empty string so it seems that there is no error;
This application works perfectly when I call it from cmd.exe; I also tried to use process.start() with cmd.exe passing the path as argument, but it did not work;
I installed the service as LocalSystem to give it maximum privileges;
I also tried to put the service into same folder and call only the .exe to exclude errors in writing the path; nothing
please help!
You cannot execute applications or executables which try to render a User Interface or are designed to require interactive login from a Windows Service which runs in background in UI less mode ( Session 0 from Vista onwards as others have comemnted ).
try to wite some unit tests and run your code from the unit tests in Visual Studio, if all works fine but then from the Windows Service does not work, then the problem is exactly the one explained above.

c# service: I am unable to pass a pass a parameter on service startup

I am writing an c# services in VS 2015 and I need to pass a parameter when the service starts. I entered the parameter like this:
enter image description here
and my code in the service looks like this
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
try
{
base.OnStart(args);
WriteToFile("args = " + args[0].ToString());
When I start the services I get the following error: "Index was outside the bounds of the array" which tells me that the argument is not read. Where am I going wrong.
thanks;
The key thing to know is that a process can contain more than one service.
The arguments passed to Main are typically used to instruct the process to do things like install itself, uninstall itself, perform maintenance tasks, or enter the service control loop (i.e. to call ServiceBase.Run).
The arguments passed to OnStart on the other hand come from the Service Control Manager, not from the command line. They are typically used to instruct the process which process to start (if there is more than one service managed by the process).
The Main parameters are configured as part of the "path to executable".
The OnStart parameters are configured as "Start parameters" in the service settings.
You need to pass the arguments otherwise args[0] is null .. in debug mode goto project settings pass the build arguments,check how it's working

Windows service pass parameters

I'm using this method: How to make a .NET Windows Service start right after the installation?
The post starts with "posted a step-by-step procedure". How can I pass parameters to the OnStart function without using registry?
I can pass parameters on this method Main(string[] args). I'm calling myapp.exe -install.
I want to call myapp.exe -install path="c:/bla bla".
And also move the path parameter to "OnStart". My OnStart exist on the YourService object in the example.
From http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.onstart.aspx...
The arguments in the args parameter array can be set manually in the
properties window for the service in the Services console. The
arguments entered in the console are not saved; they are passed to the
service on a one-time basis when the service is started from the
control panel. Arguments that must be present when the service is
automatically started can be placed in the ImagePath string value for
the service's registry key
(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\).
You can obtain the arguments from the registry using the
GetCommandLineArgs method, for example: string[] imagePathArgs =
Environment.GetCommandLineArgs();.
Using your example, you'd want to put -install path="c:/bla bla" in the Services console, but this is hardly satisfactory since it's not going to be saved, i.e., you'd have to do it every time your service started. You could go the registry route, but you said you don't want to do that. The only other option that comes to mind is some kind of service configuration file.
you would pass the application name
myapp.exe /i then in your params check check to see if /i was in the command line args within that code you assign the application path you could propbably pass the path as well surrounded by " " do a google search on passing params to a console application.. same theory applies..

How to Start multiple windows Services from asp.net web application?

I want to restart a set of windows services which are running on my local computer.
I want to restart all these services at once when i click a button in my asp.net application ?
I would appreciate if any one can help me out .
As of now i am able to implement the scenario for restarting a single windows service by using
Service Controller Class.
Just put a loop in iterating through each service name. Create a ServiceController for each service name and restart it there.
List<string> serviceList = //however you get all of the services you want to start, put them in here.
foreach(string serviceName in serviceList)
{
ServiceController controller = new ServiceController(serviceName);
....
controller.Restart();
}
To use a batch file use:
System.Diagnostics.Process.Start(pathToBatchFile);
You can manage the process by using intellisense and a little curiosity. Also, here is an msdn article I found for you.
http://blogs.msdn.com/b/csharpfaq/archive/2004/06/01/146375.aspx
To hide the command prompt and have more control over the process, use the System.Diagnostics.ProcessStartInfo class and pass its object to the Process.Start method. You can even catch the output from the batch file inside your program.

The RunInstaller attribute in a WMI provider assembly

I am creating a decoupled WMI provider in a class library. Everything I have read points towards including something along these lines:
[System.ComponentModel.RunInstaller(true)]
public class MyApplicationManagementInstaller : DefaultManagementInstaller { }
I gather the purpose of this installation is because the Windows WMI infrastructure needs to be aware of the structure of my WMI provider before it is used.
My question is - when is this "installer" ran? MSDN says that the installer will be invoked "during installation of an assembly", but I am not sure what that means or when it would happen in the context of a class library containing a WMI provider.
I was under the impression that this was an automated replacement for manually running InstallUtil.exe against the assembly containing the WMI provider, but changes I make to the provider are not recognised by the Windows WMI infrastructure unless I manually run InstallUtil from the command prompt. I can do this on my own machine during development, but if an application using the provider is deployed to other machines - what then?
It seems that this RunInstaller / DefaultManagementInstaller combination is not working properly - correct?
As I understand, DefaultManagementInstaller is ran by installutil.exe - if you don't include it, the class is not installed in WMI. Maybe it is possible to create a 'setup project' or 'installer project' that runs it, but I'm not sure because I don't use Visual Studio.
[edit]
for remote instalation, an option could be to use Installutil with /MOF option to generate MOF for the assembly and use mofcomp to move it to WMI.
I use something like this to call InstallUtil programmatically:
public static void Run( Type type )
{
// Register WMI stuff
var installArgs = new[]
{
string.Format( "//logfile={0}", #"c:\Temp\sample.InstallLog" ), "//LogToConsole=false", "//ShowCallStack",
type.Assembly.Location,
};
ManagedInstallerClass.InstallHelper( installArgs );
}
Call this from your Main() method.
-dave
Thanks Uros. It does look like all that RunInstaller and DefaultManagementInstaller do is enable you to run InstallUtil successfully against the assembly. This is strange because I'm almost certain that I didn't know about InstallUtil at the point where I'd compiled and played with my first WMI provider.
I will look in to using the MOF file and for my own use I can just run the InstallUtil command line as a post build event in VS.

Categories