创建 Web 服务方法以获取 NT 服务信息
一篇关于创建 Web 服务方法以获取 NT 服务信息的文章。
引言
最近,我创建了一个移动应用程序 - Siccolo,它允许我通过托管在公共域上的 Web 服务来管理 SQL Server(有关如何开发移动管理工具的更多信息,请参见此处)。
作为管理工具的一部分,我需要显示有关所选 NT 服务的一些信息,例如服务可执行文件的路径。 例如,services.msc 这样显示
在我的移动管理工具中,我需要以类似的方式显示

提供的代码检索有关所选 NT 服务的可执行文件路径的信息。
背景
我的“管理”Web 服务托管在 SSL 下,并设置了“集成 Windows”身份验证。 因此,移动应用程序需要传递网络凭据。 这是需要能够远程访问以从远程计算机上的注册表中获取信息。
Using the Code
使用的组件
- serviceprocessor.asmx.cs - Web 服务接口
- NTServiceInfo.cs - 用于检索 NT 服务信息的小型“包装器”
.NET 提供了此任务的工具 - System.ServiceProcess.ServiceController
类。 要创建 System.ServiceProcess.ServiceController
的实例
// C# //
...
System.ServiceProcess.ServiceController 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 impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
...
要检索可执行文件的路径,我们可以查看 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services,找到所选服务,并获取 ImagePath

要读取注册表项的值(在远程计算机上或在本地计算机上)
private string ReadRegestryKey(string RegistryKey, out string ErrorInfo)
{
try
{
string Value="";
ErrorInfo ="";
RegistryKey Key;
RegistryKey KeyHKLM = Registry.LocalMachine;
try
{
if (this.m_MachineName !="" ) //open on remote machine
Key = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(
RegistryHive.LocalMachine, this.m_MachineName
).OpenSubKey(RegistryKey);
else
Key = KeyHKLM.OpenSubKey(RegistryKey);
Value = Key.GetValue("ImagePath").ToString();
Key.Close();
}
catch (Exception ex_open_key)
{
ErrorInfo = "Error Accessing Registry [" + ex_open_key.ToString() + "]";
return "";
}
return Value;
}
catch (Exception ex_read_registry)
{
ErrorInfo = ex_read_registry.Message;
return "";
}
}
提取可执行文件的路径后,我们需要检查是否需要从 %SystemRoot%\system32\... 之类的路径“提取”到实际路径。
%SystemRoot% 的值可以在注册表中找到

private string ExpandEnvironmentString(string Path)
{
string SystemRootKey = "Software\\Microsoft\\Windows NT\\CurrentVersion\\";
RegistryKey Key;
if (this.m_MachineName !="" )
Key = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(
RegistryHive.LocalMachine, this.m_MachineName
).OpenSubKey(SystemRootKey);
else
Key = Registry.LocalMachine.OpenSubKey(SystemRootKey);
string ExpandedSystemRoot ="";
ExpandedSystemRoot = Key.GetValue("SystemRoot").ToString();
Key.Close();
Path = Path.Replace ("%SystemRoot%", ExpandedSystemRoot);
return Path;
}
最后
public string PathToExecutable(WindowsPrincipal User)
{
//HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services.
string RegistryKey = "SYSTEM\\CurrentControlSet\\Services\\" +
this.m_ServiceName;
string ErrorInfo="";
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
string Path= this.ReadRegestryKey(RegistryKey, out ErrorInfo);
if ( Path.IndexOf("%")>0)
{
Path = ExpandEnvironmentString(Path);
}
impersonationContext.Undo();
return Path;
}
请注意,对 ReadRegestryKey()
和 ExpandEnvironmentString()
的调用是如何“包装在”中的
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
...
...
impersonationContext.Undo();
然后,是实际的 Web 方法
[WebMethod]
public bool GetNTServiceInfo(string RemoteServerAddress ,
string NTServiceName,
out string ServiceInfo_XML ,
out string ErrorInfo )
{
try
{
string ToDebugSetting
= System.Configuration.ConfigurationSettings.AppSettings.Get("DebugMode");
bool ToDebug = (ToDebugSetting!="");
ErrorInfo="";
ServiceInfo_XML ="";
System.ServiceProcess.ServiceController Service;
if (RemoteServerAddress!="")
{Service = new ServiceController(NTServiceName, RemoteServerAddress ) ;}
else
{Service = new ServiceController(NTServiceName ) ;}
DataSet objDataSet = new DataSet("QueryResults");
objDataSet.Tables.Add("ServiceInfo");
objDataSet.Tables[0].Columns.Add("service_display_name",
System.Type.GetType("System.String"));
objDataSet.Tables[0].Columns.Add("status",
System.Type.GetType("System.String"));
objDataSet.Tables[0].Columns.Add("service_name",
System.Type.GetType("System.String"));
objDataSet.Tables[0].Columns.Add("path_to_executable",
System.Type.GetType("System.String"));
objDataSet.Tables[0].Columns.Add("can_stop",
System.Type.GetType("System.Boolean"));
objDataSet.Tables[0].Columns.Add("can_pause_and_continue",
System.Type.GetType("System.Boolean"));
objDataSet.Tables[0].Columns.Add("services_depend_on",
System.Type.GetType("System.String"));
objDataSet.Tables[0].Columns.Add("dependent_services",
System.Type.GetType("System.String"));
NTServiceInfo si = new NTServiceInfo(NTServiceName,
RemoteServerAddress);
Object[] r = new Object[8] {Service.DisplayName,
Service.Status.ToString(),
Service.ServiceName,
si.PathToExecutable((WindowsPrincipal) this.User),
Service.CanStop.ToString(),
Service.CanPauseAndContinue.ToString(),
si.ServiceDependOnStringList(Service.ServicesDependedOn),
si.DependentServicesStringList(Service.DependentServices)
};
objDataSet.Tables[0].Rows.Add(r);
Service.Close();
System.IO.StringWriter objStringWriter =new System.IO.StringWriter();
objDataSet.WriteXml(objStringWriter, XmlWriteMode.WriteSchema);
ServiceInfo_XML = "<?xml version='1.0' ?>" + objStringWriter.ToString();
ErrorInfo = "";
return true;
}
catch (Exception ex_get_service_info)
{
ServiceInfo_XML ="";
ErrorInfo = ex_get_service_info.Message;
return false;
}
}
关注点
如果您想了解更多相关信息,请查看 Siccolo - 用于 SQL Server 的免费移动管理工具以及 如何开发移动管理工具的完整文章。