Skip to content

Windows Service

jarzynam edited this page Jul 16, 2017 · 34 revisions

This package provides methods for managing windows services.

How to start

Before you start see main prerequisites. Create shell instance:

var factory = new ContinuousManagementFactory();
    
var _shell = factory.WindowsServiceShell();

Available methods

Get service

IWindowsServiceShell

Get comprehensive information about service:

WindowsServiceInfo service = _shell.Get(serviceName);

where serviceName is windows service name. It will return null if service not found.

WindowsServiceInfo (v3.0)

Create new WindowsServiceInfo instance and fetch information about service:

WindowsServiceInfo service =  new WindowsServiceInfo(serviceName);

If service with provided serviceName is not existing the InvalidOperationException will occur.

Get all services

IWindowsServiceShell

Get list of all available windows services:

List<WindowsServiceInfo> services = _shell.GetAll();

Install service

IWindowsServiceShell

simple

Install service by providing only name and path to service file:

_shell.Install(serviceName, servicePath);

servicePath is full path to service executable file, like "C:\Test\bin\WindowsServcie.exe" If you provide wrong Path the FileNotFoundException will occur.

advanced

Install service by providing full service-options class:

var configuration = new WindowsServiceConfiguration()
{
    Name = "TestService2",
    Path = "C:\\CompiledTestService\\EmptyTestService.exe"
};
    
_shell.Install(configuration);

In the simplest usage of installing service with custom configuration you must provide at least Name and Path. Possible WindowsServiceConfiguration properties:

Parameter Description
Name Name of the service to install
Description Service description
DisplayName Display name of the service
Path Fully qualified path to the service binary file
AccountName Account name under which the service runs
AccountDomain Account domain. Local domain as default
AccountPassword Account password
DriverName Driver object name for kernel and system-level drivers
Type Type of process which will be invoking this service. OwnProcess as default
ErrorControl Severity of the error if the Create method fails to start
StartMode Start mode of the Windows base service. Auto as default
ServiceDependencies Collection of services names that must run before this service will start
InteractWithDesktop If true, the service can create or communicate with windows on the desktop. False as default

If Path not contains any file the FileNotFoundException will occur.
If AccountName or AccountPassword is invalid, the InvalidOperationException will occur.

Update service

IWindowsServiceShell

Update existing service:

var serviceName = "testService"; 
var configuration = new WindowsServiceConfigurationForUpdate
{          
    DisplayName = "changed display name",
    Type = WindowsServiceType.ShareProcess,
    ErrorControl = WindowsServiceErrorControl.Severe,
    InteractWithDesktop = true,
    StartMode = WindowsServiceStartMode.Disabled
};

_shell.Update(serviceName, configuration);

All fields from WindowsServiceConfigurationForUpdate with assigned value will be updated. Leave null if you do not want to update field.

Possible WindowsServiceConfigurationForUpdate properties:

Parameter Description
Description Service description
DisplayName Display name of the service
Path Fully qualified path to the service binary file
Type Type of process which will be invoking this service. OwnProcess as default
ErrorControl Severity of the error if the Create method fails to start.
StartMode Start mode of the Windows base service. Auto as default
ServiceDependencies Collection of services names that must run before this service will start
InteractWithDesktop If true, the service can create or communicate with windows on the desktop. False as default

It is not possible to update account (user) with this method. To update account, use _shell.ChangeAccount method.

If service with provided serviceName is not existing the InvalidOperationException will occur.
If Path not contains any file the FileNotFoundException will occur.

WindowsServiceInfo (v3.0)

It is possible to update all fields mentioned above (+ account properties) directly from WindowsServiceInfo instance:

var service = new WindowsServiceInfo(serviceName);      // create instance

service.Change()                                        // start update process
       .Description(newDescription)                     // set fields to update
       .DisplayName(newDisplayName)
       .Path(newPath)
       .Type(newType)
       .ErrorControl(newErrorControl)
       .StartMode(newStartMode)
       .ServiceDependencies(newServiceDependencies)
       .InteractWithDesktop(newInteractWithDesktop)
       .AccountName(newAccountName)
       .AccountPassword(newAccountPassword)
       .AccountDomain(newAccountDomain)
       .Apply();                                       // apply changes

It is very important to invoke Apply() at the end of the process to save all changes. Otherwise none of fields will be updated.
If Path not contains any file the FileNotFoundException will occur.
If service is not existing, the InvalidOperationException will occur.

Rollback on error
Update process contains two steps:

  1. Update Service
  2. Update Service Account

If step 2 throws error (and not executed), step 1 will be still executed, so changes from step 1 will be saved. To prevent this behavior you can invoke RollbackOnError() method during update process:

var service = new WindowsServiceInfo(serviceName);
    
service.Change()                         // start update proccess
       .AccountName("fakeAccount")       // set service account properties
       .AccountDomain("fakeDomain")               
       .Description("new description")   // set service properties
       .RollbackOnError()                // prevent from updating service on error
       .Apply();                         // apply changes

There is no need to invoke RollbackOnError() when you are not changing service and service account properties in the same time.

Uninstall service

IWindowsServiceShell

Uninstall process even if is running:

_shell.Uninstall(serviceName); 

if you provide wrong serviceName the InvalidOperationException will occur.

WindowsServiceInfo (v3.0)

Uninstall current instance of WindowsServiceInfo:

var service = new WindowsServiceInfo(serviceName);

service.Uninstall();

If service is not existing, the InvalidOperationException will occur.

Start service

IWindowsServiceShell

Start not-running service:

_shell.Start(serviceName);

Returns true when service was successfully started. If you try start already running service, method will return false as a result.
If service is not existing, the InvalidOperationException will occur.

WindowsServiceInfo (v3.0)

Start current instance of WindowsServiceInfo:

var service = new WindowsServiceInfo(serviceName);

service.Start(); // start service and wait for 'Running' state

If service is not existing, the InvalidOperationException will occur.
Start() method has default WaitForState parameter set to true. You can force not waiting for state behavior:

service.Start(false); // will not wait for 'Running' state 

Stop service

IWindowsServiceShell

Stop running service:

_shell.Stop(serviceName);

Returns true when service was successfully started. If you try stop already stopped service, method will return false.
If service is not existing, the InvalidOperationException will occur.

WindowsServiceInfo (v3.0)

Stop current instance of WindowsServiceInfo:

var service = new WindowsServiceInfo(serviceName);

service.Stop(); // Stop service and wait for 'Stopped' state

If service is not existing, the InvalidOperationException will occur.
Stop() method has default WaitForState parameter set to true. You can force not waiting for state behavior:

service.Stop(false); // will not wait for 'Stopped' state 

Pause service

IWindowsServiceShell

Pause running service:

_shell.Pause(serviceName);

Returns true when service was successfully paused. If you try pause not running service, method will return false.
If service is not existing, the InvalidOperationException will occur.

WindowsServiceInfo (v3.0)

Pause current instance of WindowsServiceInfo:

var service = new WindowsServiceInfo(serviceName);

service.Pause();  // pause service and wait for 'Paused' state

If service is not existing, the InvalidOperationException will occur.
Pause() method has default WaitForState parameter set to true. You can force not waiting for state behavior:

service.Pause(false); // will not wait for 'Paused' state 

Continue service

IWindowsServiceShell

Resume paused service:

_shell.Continue(serviceName);

If service is not existing, the InvalidOperationException will occur.
Returns true when service was successfully resumed. If you try resume not paused service, method will return false.

WindowsServiceInfo (v3.0)

Resume current instance of WindowsServiceInfo:

var service = new WindowsServiceInfo(serviceName);

service.Continue();  // resume service and wait for 'Running' state

If service is not existing, the InvalidOperationException will occur.
Continue() method has default WaitForState parameter set to true. You can force not waiting for state behavior:

service.Continue(false); // will not wait for 'Running' state 

Change service account

IWindowsServiceShell

Change account on which service is currently running:

_shell.ChangeAccount("serviceName", "accountName", "accountPassword", "accountDomain");

You can leave domain property empty or '.' to provide local domain.
If service is not existing, the InvalidOperationException will occur.

WindowsServiceInfo (v3.0)

Update account is also possible by updating process in current WindowsServiceInfo instance:

var service = new WindowsServiceInfo(serviceName);

service.Change()                         // start update proccess
       .AccountName("accountName")       // set properties
       .AccountPassword("accountName")
       .AccountDomain(".")
       .Apply();                         // apply changes

It is very important to invoke Apply() at the end of the process to save all changes. Otherwise none of fields will be updated.
If service is not existing, the InvalidOperationException will occur.

Get service state

IWindowsServiceShell

Get service current state, commonly known as status:

_shell.GetState(serviceName);

If service is not existing, the InvalidOperationException will occur.

WindowsServiceInfo (v3.0)

Check current WindowsServiceInfo instance state:

var service = new WindowsServiceInfo(serviceName);

WindowsServiceState state = service.State;

State (and other properties) will be updated after call service.Refresh() method.
If service is not existing, the InvalidOperationException will occur.

Refresh

WindowsServiceInfo (v3.0)

Refresh all fields in WindowsServiceInfo instance:

var service = new WindowsServiceInfo(serviceName);

service.Refresh();

If service is not existing, the InvalidOperationException will occur.

Wait for state

IWindowsServiceShell

Wait until service get expected state:

var serviceName = "testService";
var expetedState = WindowsServiceState.Running;
var timeout = TimeSpan.FromMilliseconds(1000);
    
_shell.WaitForState(serviceName, expectedState, timeout);

timeout parameter is optional and as default shell will wait 1000 milliseconds.
If service is not existing, the InvalidOperationException will occur.
If service is waiting too long, the TimeoutException will occur.

WindowsServiceInfo (v3.0)

Wait until current WindowsServiceInstance get expected state:

var service = new WindowsServiceInfo(serviceName);

service.WaitForState(WindowsServiceState.Running);

If service is not existing, the InvalidOperationException will occur.
If service is waiting too long, the TimeoutException will occur.

Check if service exists

IWindowsServiceShell

Quick check if service with provided name exists:

_shell.Exists(serviceName);

Returns true if service exist or false if not.

WindowsServiceInfo (v3.0)

Check if current WindowsServiceInfo instance is still existing (for example has not been uninstalled in the meantime):

var service = new WindowsServiceInfo(serviceName);

service.Exists();

Returns true if service exist or false if not.
If service is not existing during creating WindowsServiceInfo isntance, the InvalidOperationException will occur.

Execute command

IWindowsServiceShell

Send custom command signal to service:

int commandCode = 150; // range from 128 to 256
string serviceName = "testService";
    
_shell.ExecuteCommand(serviceName, commandCode);

If service is not existing, the InvalidOperationException will occur.
If commandCode is out of range, the ArgumentException will occur.

WindowsServiceInfo (v3.0)

Execute command on exinsting WindowsServiceInfo instance:

var service = new WindowsServiceInfo(serviceName);
int commandCode = 150; // range from 128 to 256
    
service.Execute(commandCode);

if commandCode is out of range, the ArgumentException will occur.
If service is not existing, the InvalidOperationException will occur.

Batch Operations

WindowsServiceInfo (v3.0)

It is possible to invoke multiple methods in one call:

var service = new WindowsServiceInfo(serviceName);

// stop service, change description, start service
service.Stop()
       .Change()
       .Description("new description")
       .Apply()
       .Start();

If service is not existing, the InvalidOperationException will occur.