Recently, I created a mobile application-Siccolo that allows me to manage SQL Servers by using Web services hosted on public domain (see more information here about how to develop a mobile management tool).
As part of a management tool, I needed to show some information about the selected NT Service, such as path to a service executable. For example, services.msc shows it like this:

In my mobile management tool, I needed to display in a similar manner:
The code presented retrieves information about Path to Executable for a selected NT Service.
My "managing" Web service is hosted under SSL with "Integrated Windows" authentication being set. Therefore, a mobile application is required to pass network credentials. And this is needed to be able to remotely access to get information from the registry on the remote machine.
Components used:
.NET provides just the tool for this task - System.ServiceProcess.ServiceController class. To create an instance of 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 ) ;}
...
The fact that authentication (Integrated Windows authentication or Basic) is in place on IIS, actually helps here. In order to be able to access service(s) on a different machine than Web service host, Web service needs to "assume" an identity of authenticated user. Normally, Web service is running under ASP.NET user with minimum privileges and I needed to impersonate authenticated user with the Web service.
On the server side, to retrieve an authenticated user, we need to use System.Web.Services.WebService.User and then impersonate: and code does just that - "Impersonates the user represented by the WindowsIdentity object."
// C# //
...
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
...
To retrieve the path to the executable, we can look under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services, find the selected service, and get ImagePath:
To read the value of a registry key (on the remote machine, or on the local machine):
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 "";
}
}
Once the path to the executable is extracted, we need to check if the path needs to be "extracted" from something like %SystemRoot%\system32\... to the actual path.
Value of %SystemRoot% can be found in the registry:
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;
}
Finally:
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;
}
Notice, how the calls to ReadRegestryKey() and ExpandEnvironmentString() are "wrapped in" :
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
...
...
impersonationContext.Undo();
Then, the actual Web method:
[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;
}
}
If you would like to read more on this story, please take a look at Siccolo - Free Mobile Management Tool For SQL Server and full article at How to Develop Mobile Management Tool.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||