public void ServiceConfig_Repair() { string sourceFile = Path.Combine(ServiceConfigTests.TestDataDirectory, @"product.wxs"); string msiFile = Builder.BuildPackage(sourceFile, "test.msi", "WixUtilExtension"); MSIExec.InstallProduct(msiFile, MSIExec.MSIExecReturnCode.SUCCESS); // Change the service details ServiceFailureActionType[] expectedFailureActions = new ServiceFailureActionType[] { ServiceFailureActionType.RestartService, ServiceFailureActionType.RestartService, ServiceFailureActionType.RestartService }; ServiceVerifier.SetServiceInformation("MynewService", 4, expectedFailureActions); MSIExec.RepairProduct(msiFile, MSIExec.MSIExecReturnCode.SUCCESS); // Validate Existing Service Information. expectedFailureActions = new ServiceFailureActionType[] { ServiceFailureActionType.RestartService, ServiceFailureActionType.RebootComputer, ServiceFailureActionType.None }; ServiceVerifier.VerifyServiceInformation("W32Time", 1, expectedFailureActions); // Validate New Service Information. expectedFailureActions = new ServiceFailureActionType[] { ServiceFailureActionType.RebootComputer, ServiceFailureActionType.RestartService, ServiceFailureActionType.None }; ServiceVerifier.VerifyServiceInformation("MynewService", 3, expectedFailureActions); MSIExec.UninstallProduct(msiFile, MSIExec.MSIExecReturnCode.SUCCESS); // Validate New Service Does NOT exist any more. Assert.False(ServiceVerifier.ServiceExists("MynewService"), String.Format("Service '{0}' was NOT removed on Uninstall.", "MynewService")); }
/// <summary> /// verify a service has the expected failure action details /// </summary> /// <param name="serviceName">service name</param> /// <param name="resetPeriodInDays">the reset period in days</param> /// <param name="failureActions">an ordered list of the expected failure action types</param> public static void VerifyServiceInformation(string serviceName, int resetPeriodInDays, ServiceFailureActionType[] failureActions) { ServiceInformation service = GetSericeInformation(serviceName); string message = string.Empty; bool failed = false; if (resetPeriodInDays != service.ResetPeriodInDays) { failed = true; message += string.Format("Reset Period is incoorect. Actual: {0}, Expected: {1}.\r\n", service.ResetPeriodInDays, resetPeriodInDays); } for (int i = 0; i < failureActions.Length; i++) { if (failureActions[i] != service.Actions[i].Type) { failed = true; message += string.Format("FailureAction {0} is incorect. Actual: {1}, Expected: {2}. \r\n", i, service.Actions[i].Type.ToString(), failureActions[i].ToString()); } } Assert.IsFalse(failed, message); }
/// <summary> /// Changes the service failure action information /// </summary> /// <param name="serviceName">The service to look for</param> /// <param name="resetPeriodInDays">The reset period (in days)</param> /// <param name="rebootMessage">The message displayed on reboot</param> /// <param name="commandLine">Program command line</param> /// <param name="actions">Ordered list of actions to add to the service configuration</param> public static void SetServiceInformation(string serviceName, int resetPeriodInDays, string rebootMessage, string commandLine, ServiceFailureActionType[] actions) { // Get a valid service handle IntPtr serviceHandle = LookupServiceHandle(serviceName, scope.Modify); // marshal the actions ServiceFailureAction action = new ServiceFailureAction(); IntPtr lpsaActions = Marshal.AllocHGlobal(Marshal.SizeOf(action) * actions.Length); // Marshal.StructureToPtr(action, lpsaActions, false); IntPtr nextAction = lpsaActions; for (int i = 0; i < actions.Length; i++) { action = new ServiceFailureAction(); action.Type = actions[i]; action.Delay = (UInt32)TimeSpan.FromMinutes(1).TotalMilliseconds; Marshal.StructureToPtr(action, nextAction, false); nextAction = (IntPtr)(nextAction.ToInt64() + Marshal.SizeOf(action)); } // now put it all in one struct SERVICE_FAILURE_ACTIONS failureActions = new SERVICE_FAILURE_ACTIONS(); failureActions.dwResetPeriod = (int)TimeSpan.FromDays(resetPeriodInDays).TotalSeconds; failureActions.lpRebootMsg = rebootMessage; failureActions.lpCommand = commandLine; failureActions.cActions = actions.Length; failureActions.lpsaActions = lpsaActions; IntPtr lpInfo = Marshal.AllocHGlobal(Marshal.SizeOf(failureActions)); Marshal.StructureToPtr(failureActions, lpInfo, true); // do the change bool success = ChangeServiceConfig2(serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, lpInfo); //int errorcode = GetLatError(); // clean up Marshal.FreeHGlobal(lpInfo); Marshal.FreeHGlobal(lpsaActions); if (serviceHandle != IntPtr.Zero) { CloseServiceHandle(serviceHandle); } if (false == success) { throw new System.Runtime.InteropServices.ExternalException(string.Format("Cannot set ServiceConfig. Last Error: {0}.", Marshal.GetLastWin32Error())); } }
/// <summary> /// Change service failure action information /// </summary> /// <param name="serviceName">the name of the service</param> /// <param name="resetPeriodInDays">the new reset period in days</param> /// <param name="failureActions">ordered list of failure action types to add</param> public static void SetServiceInformation(string serviceName, int resetPeriodInDays, ServiceFailureActionType[] failureActions) { SetServiceInformation(serviceName, resetPeriodInDays, string.Empty, string.Empty, failureActions); }