创建 Web 服务方法以管理 NT 服务
创建 Web 服务方法以管理 NT 服务。
引言
最近,我创建了一个 移动应用程序 - Siccolo,它允许我通过托管在公共域上的 Web 服务来管理 SQL Server(有关如何开发移动管理工具的更多信息,请参阅 此处)。
在其他问题中,我必须能够从 Web 方法中重新启动 Web 服务主机以外的计算机上的 SQL Server 服务。我不仅要停止和启动 MSSQLSERVER
服务,还要重新启动所有依赖于 MSSQLSERVER
服务的服务,例如 SQL Server Agent、Crystal Reports Engine、CRM Security Service 等。
此处提供的代码允许重新启动(或仅停止或启动)NT 服务。
背景(可选,但需要)
我的“管理”Web 服务托管在启用了“集成 Windows”身份验证的 SSL 下。 因此,移动应用程序需要传递网络凭据。 这对于能够远程访问 SQL Server 计算机以控制 MSSQLSERVER
服务是必需的。
Using the Code
使用的组件如下
- serviceprocessor.asmx.cs - Web 服务接口
- NTServiceInfo.cs - 用于控制 NT 服务的一个小型“包装器”
让我们看看如何重新启动 SQL Server 服务。 .NET 提供了完成此任务的工具 - System.ServiceProcess.ServiceController
类。 要创建 System.ServiceProcess.ServiceController
的实例
// C# //
...
System.ServiceProcess.ServiceController <CODE>Service;
if (this.m_MachineName!="")
{Service = new ServiceController(this.m_ServiceName, this.m_MachineName ) ;}
else
{Service = new ServiceController(this.m_ServiceName ) ;}
...
事实上,IIS 上已启用身份验证(集成 Windows 身份验证或基本身份验证),这实际上有所帮助。 为了能够访问与 Web 服务主机不同的计算机上的服务,Web 服务需要“承担”经过身份验证的用户的身份。 通常,Web 服务以 ASP.NET 用户身份运行,权限最小,我需要模拟经过身份验证的用户来使用 Web 服务。
在服务器端,要检索经过身份验证的用户,我们需要使用 System.Web.Services.WebService.User
然后进行模拟:代码正是这样做的 - “模拟由 WindowsIdentity
对象表示的用户”。
// C# //
...
System.Security.Principal.WindowsImpersonationContext <CODE>impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
...
要枚举依赖服务 - System.ServiceProcess.ServiceController
具有 DependentServices
属性
// C# //
...
foreach (System.ServiceProcess.ServiceController <CODE>dependent_service
in Service.DependentServices)
{
...
}
...
为了处理递归停止和启动,我添加了一个小的“包装器”NTServiceInfo
类
// NTServiceInfo :
public bool RestartServervice(WindowsPrincipal User,
bool ToDebug,
out string ErrorInfo)
{
try
{
ErrorInfo ="";
if (this.StopService(User, ToDebug, out ErrorInfo))
{
if (this.StartService(User, ToDebug, out ErrorInfo))
{return true;}
else{return false;}
}
else
{return false;}
}
catch (Exception ex_restart_service)
{
ErrorInfo = "Restart Service [" + this.m_ServiceName + "]
[" + ex_restart_service.Message + "]";
return false;
}
}
其中 StopService()
和 StartService()
方法是
// NTServiceInfo :
public bool StopService(WindowsPrincipal User,
bool ToDebug,
out string ErrorInfo)
{
try
{
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)
User.Identity).Impersonate();
System.ServiceProcess.ServiceController Service;
if (this.m_MachineName!="")
{Service = new ServiceController(this.m_ServiceName, this.m_MachineName ) ;}
else
{Service = new ServiceController(this.m_ServiceName ) ;}
//stop all the Dependent services...
foreach (System.ServiceProcess.ServiceController dependent_service
in Service.DependentServices)
{
switch ( dependent_service.Status)
{
case ServiceControllerStatus.Stopped:
//already stopped...nothing to do
break;
case ServiceControllerStatus.StopPending:
dependent_service.WaitForStatus(ServiceControllerStatus.Stopped);
break;
default:
Service.Stop();
Service.WaitForStatus(ServiceControllerStatus.Stopped);
break;
}
}
//stop main service...
switch ( Service.Status)
{
case ServiceControllerStatus.Stopped:
//already stopped...nothing to do
break;
case ServiceControllerStatus.StopPending:
Service.WaitForStatus(ServiceControllerStatus.Stopped);
break;
default:
// *-****************************************************************
//check all dependent services?
foreach (System.ServiceProcess.ServiceController dependent_service
in Service.DependentServices)
{
switch ( dependent_service.Status)
{
case ServiceControllerStatus.Stopped:
//already stopped...nothing to do
break;
case ServiceControllerStatus.StopPending:
dependent_service.WaitForStatus
(ServiceControllerStatus.Stopped);
break;
default:
Service.Stop();
Service.WaitForStatus(ServiceControllerStatus.Stopped);
break;
}
}
if ( !Service.CanStop )
{
throw new Exception ("Cannot stop service [" +
this.m_ServiceName + "]");
}
Service.Stop();
Service.WaitForStatus(ServiceControllerStatus.Stopped);
break;
}
Service.Close();
impersonationContext.Undo();
ErrorInfo="";
return true;
}
catch (Exception ex_stop_service)
{
ErrorInfo = ex_stop_service.Message;
return false;
}
}
public bool StartService(WindowsPrincipal User,
bool ToDebug,
out string ErrorInfo)
{
try
{
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
System.ServiceProcess.ServiceController Service;
if (this.m_MachineName!="")
{Service = new ServiceController(this.m_ServiceName, this.m_MachineName ) ;}
else
{Service = new ServiceController(this.m_ServiceName ) ;}
switch ( Service.Status)
{
case ServiceControllerStatus.Stopped:
Service.Start();
Service.WaitForStatus(ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.StopPending:
//wait for it to stop
Service.WaitForStatus(ServiceControllerStatus.Stopped);
//... and then start
Service.Start();
Service.WaitForStatus(ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.StartPending:
//nothing to do...just wait
Service.WaitForStatus(ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.Running:
//nothing to do.already running...
break;
default:
Service.Start();
Service.WaitForStatus(ServiceControllerStatus.Running);
break;
}
//start all the Dependent services...
foreach (System.ServiceProcess.ServiceController dependent_service
in Service.DependentServices)
{
switch (dependent_service.Status )
{
case ServiceControllerStatus.StartPending:
//just wait for it to start
dependent_service.WaitForStatus (ServiceControllerStatus.Running);
break;
case ServiceControllerStatus.Running:
//already running.nothing to do
break;
default:
NTServiceInfo si =
new NTServiceInfo( dependent_service.ServiceName,
this.m_MachineName);
if ( !si.StartService(User, ToDebug, out ErrorInfo))
{
throw new Exception ("Failed to start Dependent Service [" +
dependent_service.ServiceName +
"] - Error [" + ErrorInfo + "]") ;
}
break;
}
}
Service.Close();
impersonationContext.Undo();
ErrorInfo="";
return true;
}
catch (Exception ex_start_service)
{
ErrorInfo = ex_start_service.Message;
return false;
}
}
所以,总而言之,Web 方法如下所示
[WebMethod]
public bool RestartSQLServerService(string RemoteServerAddress,
out string NewServiceStatus,
out string ErrorInfo )
{
try
{
string ToDebugSetting =
System.Configuration.ConfigurationSettings.AppSettings.Get("DebugMode");
bool ToDebug = (ToDebugSetting!="");
string NTServiceName = "MSSQLSERVER";
ErrorInfo="";
NewServiceStatus ="";
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)
User.Identity).Impersonate();
NTServiceInfo si = new NTServiceInfo(NTServiceName, RemoteServerAddress);
if ( ! si.RestartServervice ((WindowsPrincipal)
this.User,ToDebug, out ErrorInfo))
{return false;}
NewServiceStatus = si.ServiceStatus();
impersonationContext.Undo();
ErrorInfo = "";
return true;
}
catch (Exception ex_get_service_info)
{
NewServiceStatus ="";
ErrorInfo = ex_get_service_info.Message;
return false;
}
}
或者,为了使功能更通用
[WebMethod]
public bool RestartNTService(string RemoteServerAddress ,
string NTServiceName,
out string NewServiceStatus ,
out bool CanStop,
out bool CanPauseAndContinue,
out string ErrorInfo )
{
try
{
string ToDebugSetting =
System.Configuration.ConfigurationSettings.AppSettings.Get("DebugMode");
bool ToDebug = (ToDebugSetting!="");
ErrorInfo="";
NewServiceStatus ="";
CanStop = false;
CanPauseAndContinue = false;
System.Security.Principal.WindowsImpersonationContext
impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)
User.Identity).Impersonate();
NTServiceInfo si = new NTServiceInfo(NTServiceName, RemoteServerAddress);
if ( ! si.RestartServervice ((WindowsPrincipal)
this.User,ToDebug, out ErrorInfo))
{return false;}
NewServiceStatus = si.ServiceStatus();
CanStop = si.CanStop();
CanPauseAndContinue = si.CanPauseAndContinue();
impersonationContext.Undo();
ErrorInfo = "";
return true;
}
catch (Exception ex_get_service_info)
{
NewServiceStatus ="";
CanStop = false;
CanPauseAndContinue = false;
ErrorInfo = ex_get_service_info.Message;
return false;
}
}
关注点
如果您想阅读更多关于此存储的信息 - 请查看 Siccolo - 适用于 SQL Server 的免费移动管理工具 和完整的文章 如何开发移动管理工具.
历史
到目前为止没有改进。 几乎完美。