tags:

views:

218

answers:

3

I'm writing a service monitoring ASP .NET app and I'm having issues particularly with getting the service descriptions. My current method (reading from registry) is not going to work due to registry read permissions on the production server.

For example:

Microsoft.Win32.RegistryKey system, currentControlSet, services, service;
system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System");
currentControlSet = system.OpenSubKey("CurrentControlSet");
services = currentControlSet.OpenSubKey("Services");
service = services.OpenSubKey(scTemp.ServiceName, true);
row["service_description"] = service.GetValue("Description");

Produces:

System.Security.SecurityException: Requested registry access is not allowed.

My question is:

Is there a work-around with another .NET class (maybe under System.ServiceProcess namespace?) or will it always end with a security exception error?

I have no issues getting Service names and states with the System.ServiceProcess namespace but I can't find any classes contained to get descriptions which is why I resorted to reading from registry.

+1  A: 

I think this should work.

EDIT: I should read questions closer. The code below gets the description for the first service in the array.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Management;

namespace ServiceNames
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceController[] services = ServiceController.GetServices();

            string serviceName = services[0].ServiceName;
            string objPath = string.Format("Win32_Service.Name='{0}'", serviceName);
            using (ManagementObject service = new ManagementObject(new ManagementPath(objPath)))
            {
                Console.WriteLine(service["Description"]);
            }

            Console.Read();
        }
    }
}
Brett Bim
Not the DisplayName, the Description text.
jw0rd
Sorry about that, I didn't pay close enough attention to the original question. The code above should do what you want, I believe.
Brett Bim
Works perfectly, thanks!
jw0rd
A: 

Side question: is there something you are trying to accomplish that PerfMon and logging can't tell you?

Chris Brandsma
Yes, it has to be web accessible to start.
jw0rd
+1  A: 

The previous answer showing the WMI solution is a good alternative and worth trying first.

--

I am not aware of a .NET Framework class that exposes the service description.

The first thing I would consider is requiring authenticated connections (e.g. NTLM) and impersonate the caller. As long as you don't do a double-hop (i.e. make a remote call with your impersonated credentials) you may find that you are able to successfully make the registery read.

If that is not possible then making a P/Invoke call may work.

If the credentials your web service has the SERVICE_QUERY_CONFIG permission you could do the following:

  1. Find the service you are interested in using the ServiceController class
  2. Using the ServiceHandle property make a P/Invoke call to QueryServiceConfig2 using the SERVICE_CONFIG_DESCRIPTION info level passing in null for the buffer and 0 for the lenght, reading the required buffer length from pcbBytesNeeded.
  3. Allocate the proper buffer length and call QueryServiceConfig2 a second time getting the service description.

Obviously reading from the registery is a little more straight-forward (and in the end the permissions issues may be similar in both cases) - but using a supported API seems like a less fragile solution.

Bubbafat
Yes, reading from registry in the end was just too much of a permissions hassle, esp with the limitations of regini.exe
jw0rd