在Windows服务上设置恢复选项

我最近写了一个小类来帮助我改变Windows服务的恢复选项(我在网上找到的大部分代码)。 代码为第一次,第二次和后续故障创建FailureAction。 每个Failure对象都包含一个类型(None,Restart,Reboot,RunCommand)和一个Delay(int),以毫秒为单位。 这些对象打包在struct中,并传递给ChangeServiceConfig2(WinAPI P / Invoke)。 但是,当我实际右键单击控制台上的服务并转到“恢复”选项卡时,您只能为所有故障(第一个,第二个和后续)设置一次延迟(“重新启动服务器后”字段)。 当我以编程方式设置它时,它从第一次FailureAction开始延迟并忽略所有其他的。 有谁知道为什么会这样? 当只使用第一个对象时,为什么我们必须传递所有FailureAction对象的延迟值? 我误会了什么吗?

此外,设置dwResetPeriod /“重置失败计数后”似乎没有任何影响。

码:

public class ServiceConfigurator { private const int SERVICE_ALL_ACCESS = 0xF01FF; private const int SC_MANAGER_ALL_ACCESS = 0xF003F; private const int SERVICE_CONFIG_DESCRIPTION = 0x1; private const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2; private const int SERVICE_NO_CHANGE = -1; private const int ERROR_ACCESS_DENIED = 5; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct SERVICE_FAILURE_ACTIONS { public int dwResetPeriod; [MarshalAs(UnmanagedType.LPWStr)] public string lpRebootMsg; [MarshalAs(UnmanagedType.LPWStr)] public string lpCommand; public int cActions; public IntPtr lpsaActions; } [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")] private static extern bool ChangeServiceFailureActions(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS lpInfo); [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")] private static extern bool ChangeServiceDescription(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo); [DllImport("kernel32.dll")] private static extern int GetLastError(); private IntPtr _ServiceHandle; public IntPtr ServiceHandle { get { return _ServiceHandle; } } public ServiceConfigurator(ServiceController svcController) { this._ServiceHandle = svcController.ServiceHandle.DangerousGetHandle(); } public void SetRecoveryOptions(FailureAction pFirstFailure, FailureAction pSecondFailure, FailureAction pSubsequentFailures, int pDaysToResetFailureCount = 0) { int NUM_ACTIONS = 3; int[] arrActions = new int[NUM_ACTIONS * 2]; int index = 0; arrActions[index++] = (int)pFirstFailure.Type; arrActions[index++] = pFirstFailure.Delay; arrActions[index++] = (int)pSecondFailure.Type; arrActions[index++] = pSecondFailure.Delay; arrActions[index++] = (int)pSubsequentFailures.Type; arrActions[index++] = pSubsequentFailures.Delay; IntPtr tmpBuff = Marshal.AllocHGlobal(NUM_ACTIONS * 8); try { Marshal.Copy(arrActions, 0, tmpBuff, NUM_ACTIONS * 2); SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS(); sfa.cActions = 3; sfa.dwResetPeriod = pDaysToResetFailureCount; sfa.lpCommand = null; sfa.lpRebootMsg = null; sfa.lpsaActions = new IntPtr(tmpBuff.ToInt32()); bool success = ChangeServiceFailureActions(_ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa); if(!success) { if(GetLastError() == ERROR_ACCESS_DENIED) throw new Exception("Access denied while setting failure actions."); else throw new Exception("Unknown error while setting failure actions."); } } finally { Marshal.FreeHGlobal(tmpBuff); tmpBuff = IntPtr.Zero; } } } 

特雷弗

我发现win 7的所有版本都没有能力重启某些服务,即使它们在失败时重启也设置为是。

我最终写了一个服务来监控启动和停止状态以及(启发式推导)响应(例如挂不挂)。 您是否希望在此处发布服务代码?

编辑:添加了代码

好的,以下是我提到的服务代码。 记住:

  • 此代码旨在指向用于日志记录的“C:\ appMon”和cpu util。 阈值。
  • 这段代码很丑陋,因为当我被其他优先事项抨击时它被剔除 – 因此,它可以被重写以处理任意数量的服务,用户定义的日志和cfg路径等。
  • 它所写的服务是臭名昭着的Windows假脱机程序(spoolsv.exe)。

要安装该服务,请使用MS中的installutil.exe。 确保该服务作为“本地系统帐户”运行,否则将无法启动/停止服务。

appMon.cs:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.ServiceProcess; using System.Text; using System.Timers; using System.Windows.Forms; using System.IO; using System.Net.Mail; using System.Threading; using System.Management; namespace appMon { public class appMon : ServiceBase { public const string serviceName = "appMon"; public appMon() { InitializeComponent(); } private void InitializeComponent() { this.ServiceName = serviceName; } ///  /// Clean up any resources being used. ///  protected override void Dispose(bool disposing) { // free instantiated object resources not handled by garbage collector base.Dispose(disposing); } public static string getCurrUser() {// gets the owner of explorer.exe/UI to determine current logged in user String User = String.Empty; String Domain = String.Empty; String OwnerSID = String.Empty; string processname = String.Empty; int PID = Process.GetProcessesByName("explorer")[0].Id; ObjectQuery sq = new ObjectQuery ("Select * from Win32_Process Where ProcessID = '" + PID + "'"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq); foreach (ManagementObject oReturn in searcher.Get()) { string[] o = new String[2]; oReturn.InvokeMethod("GetOwner", (object[])o); User = o[0]; System.IO.StreamWriter sr = new System.IO.StreamWriter(@"C:\user.txt"); sr.WriteLine("\\" + o[2] + "\\" + o[1] + "\\" + o[0]); return User; } return User; } public static int readConfigFile() { int cputime = 5; // 5 min dflt try { string readcfg; readcfg = File.ReadAllText(@"c:\appMon\cpuUtilization.txt"); cputime = Convert.ToInt16(readcfg); return cputime; } catch (Exception e) { MessageBox.Show(e.ToString()); return cputime; // 5 min dflt } } public static void logEvents(bool spoolerHang, bool appHang, string msg) { try { StreamWriter sw; sw = File.AppendText(@"c:\appMon\appMonLog.txt"); sw.WriteLine(@"appMon spoolsv.exe event: " + "," + System.Environment.MachineName + "," + System.DateTime.Now + "," + msg); sw.Close(); } catch (Exception e) { MessageBox.Show(e.ToString()); } } ///  /// Start this service. ///  protected override void OnStart(string[] args) {// upon appMon load, a polling interval is set (in milliseconds 1000 ms = 1 s) System.Timers.Timer pollTimer = new System.Timers.Timer(); pollTimer.Elapsed += new ElapsedEventHandler(pollTimer_Elapsed); pollTimer.Interval = 20000; // 20 sec pollTimer.Enabled = true; } public static void StartService(string serviceName, int timeoutMilliseconds) { ServiceController service = new ServiceController(serviceName); try { TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); if (service.Status == ServiceControllerStatus.Stopped) // if service is not running... { service.Start(); // ...start the service } } catch(Exception e) { MessageBox.Show(e.ToString()); } } public static void StopService(string serviceName, int timeoutMilliseconds) { ServiceController service = new ServiceController(serviceName); try { TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds); if (service.Status == ServiceControllerStatus.Running) // if service is running... { service.Stop(); //...stop the service } service.WaitForStatus(ServiceControllerStatus.Stopped, timeout); } catch (Exception e) { MessageBox.Show(e.ToString()); } } public static void delFiles(string path) { string[] filePaths = Directory.GetFiles(path); foreach (string filePath in filePaths) { try { File.Delete(filePath); } catch (Exception e) { // TODO: !log to file instead! MessageBox.Show("error deleting files: " + e.ToString()); } } } public static void getServiceInfo(string serviceName) { ServiceController service = new ServiceController(serviceName); ServiceController[] depServices = service.ServicesDependedOn; List depServicesList = new List(); foreach (ServiceController sc in depServices) { depServicesList.Add(sc.ServicesDependedOn.ToString()); logEvents(false, false, sc.ServicesDependedOn.ToString()); } } void pollTimer_Elapsed(object sender, ElapsedEventArgs e) {// polling interval has elapsed getServiceInfo("spooler"); ServiceController serviceSpooler = new ServiceController("spooler"); if (serviceSpooler.Status == ServiceControllerStatus.Stopped) { logEvents(true, false, "Print Spooler is: " + serviceSpooler.Status.ToString()); serviceSpooler.Refresh(); serviceSpooler.Start(); logEvents(true, false, "Print Spooler is: " + serviceSpooler.Status.ToString()); } int cputime = readConfigFile(); // get active processes (exe's, including services) Process[] processlist = Process.GetProcesses(); // iterate through process list foreach (Process theprocess in processlist) { // assign local variable to iterator - cures the foreach "gotcha" Process p = theprocess; if (p.ProcessName == "spoolsv") // "spoolsv" = windows name for spoolsv.exe aka "spooler" { if (p.TotalProcessorTime.Minutes > cputime) // has current spooler thread occupied >= cputime # mins of CPU time? { logEvents(true, false, "spoolsv.exe CPU time (mins): " + p.TotalProcessorTime.Minutes.ToString()); p.Refresh(); StopService("spooler", 0); StartService("spooler", 0); } } } } ///  /// Stop this service. ///  /// protected override void OnStop() { } } } 

sc命令为自动化服务管理提供了一种很好的方法。 要从代码调用,只需执行Process.Start("sc", "args")并重定向输出,如果您想获得结果。

这一行告诉服务在等待1分钟后重启两次。 失败了。 经过一天后,它会重置故障计数。 您还可以将其设置为在后续故障时运行程序等。

 sc failure myservice reset= 86400 actions= restart/60000/restart/60000// 

http://technet.microsoft.com/en-us/library/cc742019(v=ws.10).aspx