private void DoCreateService(ServiceControlManager serviceControlManager, ServiceDefinition serviceDefinition, bool startImmediately) { using (ServiceHandle svc = serviceControlManager.CreateService(serviceDefinition.ServiceName, serviceDefinition.DisplayName, serviceDefinition.BinaryPath, ServiceType.Win32OwnProcess, serviceDefinition.AutoStart ? ServiceStartType.AutoStart : ServiceStartType.StartOnDemand, serviceDefinition.ErrorSeverity, serviceDefinition.Credentials)) { string description = serviceDefinition.Description; if (!string.IsNullOrEmpty(description)) { svc.SetDescription(description); } ServiceFailureActions serviceFailureActions = serviceDefinition.FailureActions; if (serviceFailureActions != null) { svc.SetFailureActions(serviceFailureActions); svc.SetFailureActionFlag(serviceDefinition.FailureActionsOnNonCrashFailures); } if (serviceDefinition.AutoStart && serviceDefinition.DelayedAutoStart) { svc.SetDelayedAutoStartFlag(true); } if (startImmediately) { svc.Start(); } } }
private static void InstallService(string ServiceName, string DisplayName, string Description, ServiceStartType StartType, bool Immediate, ServiceFailureActions FailureActions, Win32ServiceCredentials Credentials) { ServiceInstaller host = new ServiceInstaller(ServiceName); int i; switch (i = host.Install(DisplayName, Description, StartType, Immediate, FailureActions, Credentials)) { case 0: Console.Out.WriteLine("Service successfully installed. Service start is pending."); break; case 1: Console.Out.WriteLine("Service successfully installed and started."); break; case 2: Console.Out.WriteLine("Service registration successfully updated. Service start is pending."); break; case 3: Console.Out.WriteLine("Service registration successfully updated. Service started."); break; default: throw new Exception("Unexpected installation result: " + i.ToString()); } }
/// <summary> /// Installs the service. /// </summary> /// <param name="DisplayName">Service display name.</param> /// <param name="Description">Service description.</param> /// <param name="StartType">How the service should be started.</param> /// <param name="StartImmediately">If the service should be started immediately.</param> /// <param name="FailureActions">Service failure actions.</param> /// <param name="Credentials">Credentials to use when running service.</param> /// <returns> /// Return code: /// /// 0: Installed, not started. /// 1: Installed, started. /// 2: Updated, not started. /// 3: Updated, started. /// </returns> /// <exception cref="Exception">If service could not be installed.</exception> public int Install(string DisplayName, string Description, ServiceStartType StartType, bool StartImmediately, ServiceFailureActions FailureActions, Win32ServiceCredentials Credentials) { string Path = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".exe"); try { using (ServiceControlManager mgr = ServiceControlManager.Connect(null, null, ServiceControlManagerAccessRights.All)) { if (mgr.TryOpenService(this.serviceName, ServiceControlAccessRights.All, out ServiceHandle existingService, out Win32Exception errorException)) { using (existingService) { existingService.ChangeConfig(DisplayName, Path, ServiceType.Win32OwnProcess, StartType, ErrorSeverity.Normal, Credentials); if (!string.IsNullOrEmpty(Description)) { existingService.SetDescription(Description); } if (!(FailureActions is null)) { existingService.SetFailureActions(FailureActions); existingService.SetFailureActionFlag(true); } else { existingService.SetFailureActionFlag(false); } if (StartImmediately) { existingService.Start(throwIfAlreadyRunning: false); return(3); } else { return(2); } }
public static extern bool ChangeServiceFailureActions(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref ServiceFailureActions lpInfo);
protected async override Task RemoteConfigureAsync(IRemoteOperationExecutionContext context) { if (this.Template == null) { throw new InvalidOperationException("Template is not set."); } this.LogDebug($"Looking for service \"{this.Template.Name}\"..."); bool userWasChanged = false; using (var service = GetOrCreateService(!context.Simulation)) { if (this.Template.Exists) { if (service == null) { // simulation this.LogInformation($"{this.Template.Name} service does not exist."); return; } if (this.Template.DisplayName != null && this.Template.DisplayName != service.DisplayName) { service.DisplayName = this.Template.DisplayName; } if (this.Template.Description != null && this.Template.Description != service.Description) { service.Description = this.Template.Description; } if (this.Template.Path != null && this.Template.Path != service.FileName) { service.FileName = this.Template.Path; } if (this.Template.StartMode != null && this.Template.StartMode != service.StartMode) { service.StartMode = this.Template.StartMode.Value; } if (this.Template.DelayedStart != null && this.Template.DelayedStart != service.DelayedStart) { service.DelayedStart = this.Template.DelayedStart.Value; } if (this.Template.UserAccount != null && this.Template.UserAccount != service.UserAccountName) { userWasChanged = true; service.SetUserAccount(this.Template.UserAccount, this.Template.Password); } if (this.Template.Dependencies != null && !this.Template.Dependencies.ToHashSet().SetEquals(service.Dependencies)) { service.SetDependencies(this.Template.Dependencies.ToList()); } if (FailureActionsChanged(service)) { var timeDelay = this.Template.RestartDelay != null?TimeSpan.FromMinutes(this.Template.RestartDelay.Value) : TimeSpan.Zero; var newFailureActions = new ServiceFailureActions( resetPeriod: this.Template.RestartDelay, rebootMessage: this.Template.RebootMessage, command: this.Template.OnFailureProgramPath, actions: new[] { new ServiceControllerAction(this.Template.OnFirstFailure ?? ServiceControllerActionType.None, timeDelay), new ServiceControllerAction(this.Template.OnSecondFailure ?? ServiceControllerActionType.None, timeDelay), new ServiceControllerAction(this.Template.OnSubsequentFailures ?? ServiceControllerActionType.None, timeDelay) }); service.FailureActions = newFailureActions; } if (this.Template.Status != null) { if (!IsPending(this.Template.Status.Value)) { await this.EnsureServiceStatusAsync(service.Name, this.Template.Status.Value); } else { this.LogWarning($"Specified service status \"{this.Template.Status.Value}\" is invalid, therefore the service's status will not be modified."); } } } else { if (service == null) { this.LogWarning("Service doesn't exist."); return; } this.LogDebug("Service exists. Stopping before deleting..."); await this.EnsureServiceStatusAsync(service.Name, ServiceControllerStatus.Stopped); this.LogDebug($"Deleting {service.Name} service..."); service.Delete(); } } if (userWasChanged && this.Template.Status == ServiceControllerStatus.Running) { this.LogDebug("The service user was changed, therefore the service will be restarted."); await this.EnsureServiceStatusAsync(this.Template.Name, ServiceControllerStatus.Stopped); await this.EnsureServiceStatusAsync(this.Template.Name, ServiceControllerStatus.Running); } }
private void WhenATestServiceIsCreatedOrUpdated(string testServiceName, bool autoStart, bool startImmediately, ServiceFailureActions serviceFailureActions = null, bool failureActionsOnNonCrashFailures = false) { sut.CreateOrUpdateService(testServiceName, TestServiceDisplayName, TestServiceDescription, TestServiceBinaryPath, TestCredentials, serviceFailureActions, failureActionsOnNonCrashFailures, autoStart, startImmediately, TestServiceErrorSeverity); }
private void OnCommitted(object sender, InstallEventArgs args) { IntPtr handleManager = IntPtr.Zero; IntPtr handleService = IntPtr.Zero; IntPtr handleDatabase = IntPtr.Zero; IntPtr buffer = IntPtr.Zero; try { // Open the service control manager handleManager = OpenSCManager(null, null, ManagerAllAccessFlag); if (handleManager.ToInt64() <= 0) { throw new InvalidOperationException("Error accessing service control manager."); } // Lock the Service Database handleDatabase = LockServiceDatabase(handleManager); if (handleDatabase.ToInt64() <= 0) { throw new InvalidOperationException("Error locking service database."); } // Open the service handleService = OpenService(handleManager, _serviceInfo.Name, ServiceAllAccessFlag); if (handleService.ToInt64() <= 0) { throw new InvalidOperationException("Error opening service '" + _serviceInfo.Name + "'"); } // define actions int countActions = 3; int[] actions = new int[countActions * 2]; // first failure actions[0] = (int)RecoverAction.Restart; actions[1] = 0; // second failure actions[2] = (int)RecoverAction.Restart; actions[3] = 0; // any subsequent failure actions[4] = (int)RecoverAction.Restart; actions[5] = 0; // 8 bytes per struct buffer = Marshal.AllocHGlobal(countActions * 8); Marshal.Copy(actions, 0, buffer, countActions * 2); // create the unmanaged struct ServiceFailureActions unmanagedActions = new ServiceFailureActions(); unmanagedActions.cActions = countActions; unmanagedActions.dwResetPeriod = 0; unmanagedActions.lpCommand = null; unmanagedActions.lpRebootMsg = null; unmanagedActions.lpsaActions = buffer; if (!ChangeServiceFailureActions(handleService, RecoveryOptionsFlag, ref unmanagedActions)) { throw new Exception("Error while setting service recovery options."); } } finally { if (handleService != IntPtr.Zero) { CloseServiceHandle(handleService); } if (handleDatabase != IntPtr.Zero) { UnlockServiceDatabase(handleDatabase); } if (handleManager != IntPtr.Zero) { CloseServiceHandle(handleManager); } if (buffer != IntPtr.Zero) { Marshal.FreeHGlobal(buffer); } } }
private Func <ServiceHandle, ServiceConfigInfoTypeLevel, IntPtr, bool> CreateChangeService2WHandler(string serviceName) { return((handle, infoLevel, info) => { switch (infoLevel) { case ServiceConfigInfoTypeLevel.ServiceDescription: var serviceDescription = Marshal.PtrToStructure <ServiceDescriptionInfo>(info); if (string.IsNullOrEmpty(serviceDescription.ServiceDescription)) { serviceDescriptions.Remove(serviceName); } else { serviceDescriptions[serviceName] = serviceDescription.ServiceDescription; } return true; case ServiceConfigInfoTypeLevel.FailureActions: var failureAction = Marshal.PtrToStructure <ServiceFailureActionsInfo>(info); if (failureAction.Actions?.Length == 0) { failureActions.Remove(serviceName); } else { failureActions[serviceName] = new ServiceFailureActions(failureAction.ResetPeriod, failureAction.RebootMsg, failureAction.Command, failureAction.Actions); } return true; case ServiceConfigInfoTypeLevel.FailureActionsFlag: var failureActionFlag = Marshal.PtrToStructure <ServiceFailureActionsFlag>(info); failureActionsFlags[serviceName] = failureActionFlag.Flag; return true; case ServiceConfigInfoTypeLevel.DelayedAutoStartInfo: if (info != IntPtr.Zero) { delayedAutoStartInfoSetOnNativeInterop = Marshal.ReadInt32(info) > 0; } else { delayedAutoStartInfoSetOnNativeInterop = null; } return true; case ServiceConfigInfoTypeLevel.ServiceSidInfo: break; case ServiceConfigInfoTypeLevel.RequiredPrivilegesInfo: break; case ServiceConfigInfoTypeLevel.PreShutdownInfo: break; case ServiceConfigInfoTypeLevel.TriggerInfo: break; case ServiceConfigInfoTypeLevel.PreferredNode: break; case ServiceConfigInfoTypeLevel.LaunchProtected: break; default: throw new ArgumentOutOfRangeException(nameof(infoLevel), infoLevel, null); } return false; }); }
static int Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Usage: {0} <name of service to adjust>", Path.GetFileName(typeof(Program).Assembly.Location)); Console.WriteLine("If you'd like to run this test against a dummy service, use these commands:"); Console.WriteLine("=> Create: sc create TestSvc binPath= {0} start= demand", EscapeArg(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "ping.exe"))); Console.WriteLine("=> Remove: sc delete TestSvc"); return(2); } Console.WriteLine("Adjusting service failure actions for service: {0}", args[0]); var actions = new ServiceFailureActions() { ResetPeriod = TimeSpan.FromSeconds(60), RestartCommand = null, RebootMessage = null, PerformFailureActionsOnStopWithNonZeroExitCode = false, Actions = new ServiceFailureAction[] { new ServiceFailureAction() { Type = ServiceFailureActionType.RestartService, DelayBeforeAction = TimeSpan.FromSeconds(5) }, new ServiceFailureAction() { Type = ServiceFailureActionType.RestartService, DelayBeforeAction = TimeSpan.FromSeconds(15) }, new ServiceFailureAction() { Type = ServiceFailureActionType.RestartService, DelayBeforeAction = TimeSpan.FromSeconds(25) }, new ServiceFailureAction() { Type = ServiceFailureActionType.RestartService, DelayBeforeAction = TimeSpan.FromSeconds(35) }, new ServiceFailureAction() { Type = ServiceFailureActionType.RestartService, DelayBeforeAction = TimeSpan.FromSeconds(45) }, new ServiceFailureAction() { Type = ServiceFailureActionType.None, DelayBeforeAction = TimeSpan.FromSeconds(0) }, }, }; try { actions.ApplyToService(args[0]); Console.WriteLine("The operation appears to have succeeded."); return(0); } catch (Exception e) { Console.WriteLine("EXCEPTION:"); Console.WriteLine(e); return(1); } }
//////////////////////////////////////////////////////////////////////////////////// // The worker method to set all the extension properties for the service private void UpdateServiceConfig(object sender, InstallEventArgs ea) { // Determine if we need to set fail actions _setFailActions = false; var numActions = FailureActions.Count; if (numActions > 0) { _setFailActions = true; } // Do we need to do any work that the base installer did not do already? if (!(_setDescription || _setFailActions)) { return; } // We've got work to do var scmHndl = IntPtr.Zero; var svcHndl = IntPtr.Zero; var tmpBuf = IntPtr.Zero; var svcLock = IntPtr.Zero; // Place all our code in a try block try { // Open the service control manager scmHndl = OpenSCManager(null, null, ScManagerAllAccess); if (scmHndl.ToInt32() <= 0) { LogInstallMessage(EventLogEntryType.Error, "Failed to Open Service Control Manager"); return; } // Lock the Service Database svcLock = LockServiceDatabase(scmHndl); if (svcLock.ToInt32() <= 0) { LogInstallMessage(EventLogEntryType.Error, "Failed to Lock Service Database for Write"); return; } // Open the service svcHndl = OpenService(scmHndl, ServiceName, ServiceAllAccess); if (svcHndl.ToInt32() <= 0) { LogInstallMessage(EventLogEntryType.Information, "Failed to Open Service "); return; } // Need to set service failure actions. the API lets us set as many as // we want, yet the Service Control Manager GUI only lets us see the first 3. // Bill is aware of this and has promised no fixes. Also the API allows // granularity of seconds whereas GUI only shows days and minutes. bool rslt; if (_setFailActions) { // We're gonna serialize the SA_ACTION structs into an array of ints // for simplicity in marshalling this variable length ptr to win32 var actions = new int[numActions * 2]; var currInd = 0; var needShutdownPrivilege = false; foreach (FailureAction fa in FailureActions) { actions[currInd] = (int)fa.RecoverAction; actions[++currInd] = fa.Delay; currInd++; if (fa.RecoverAction == RecoverAction.Reboot) { needShutdownPrivilege = true; } } // If we need shutdown privilege, then grant it to this process if (needShutdownPrivilege) { rslt = GrandShutdownPrivilege(); if (!rslt) { return; } } // Need to pack 8 bytes per struct tmpBuf = Marshal.AllocHGlobal(numActions * 8); // Move array into marshallable pointer Marshal.Copy(actions, 0, tmpBuf, numActions * 2); // Set the SERVICE_FAILURE_ACTIONS struct var sfa = new ServiceFailureActions { cActions = numActions, dwResetPeriod = _failResetTime, lpCommand = _failRunCommand, lpRebootMsg = _failRebootMsg, lpsaActions = tmpBuf.ToInt32() }; // Call the ChangeServiceFailureActions() abstraction of ChangeServiceConfig2() rslt = ChangeServiceFailureActions(svcHndl, ServiceConfigFailureActions, ref sfa); //Check the return if (!rslt) { var err = GetLastError(); if (err == ErrorAccessDenied) { throw new Exception(_logMsgBase + "Access Denied while setting Failure Actions"); } } // Free the memory Marshal.FreeHGlobal(tmpBuf); tmpBuf = IntPtr.Zero; } // Need to set the description field? if (_setDescription) { var sd = new ServiceDescription { lpDescription = _description }; // Call the ChangeServiceDescription() abstraction of ChangeServiceConfig2() rslt = ChangeServiceDescription(svcHndl, ServiceConfigDescription, ref sd); // Error setting description? if (!rslt) { throw new Exception(_logMsgBase + "Failed to set description"); } } } catch (Exception e) { LogInstallMessage(EventLogEntryType.Error, e.Message); } finally { if (scmHndl != IntPtr.Zero) { // Unlock the service database if (svcLock != IntPtr.Zero) { UnlockServiceDatabase(svcLock); } // Close the service control manager handle CloseServiceHandle(scmHndl); } // Close the service handle if (svcHndl != IntPtr.Zero) { CloseServiceHandle(svcHndl); } // Free the memory if (tmpBuf != IntPtr.Zero) { Marshal.FreeHGlobal(tmpBuf); } } }