Search code examples
.netvb.netwindows-servicesservicecontroller

Get Windows service start type?


In the System.ServiceProcess namespace, is there any kind of enumeration or other direct member to determine a Service's Start Type (Auto, Delayed Auto, On Demand, Disabled) of a ServiceController?

The idea is to use an available member of that namespace (or other namespace) of the .NET framework class library to determine that thing, instead of looking into the OS registry or WMI for the service's start type, because I could do that, I'm only asking if the .NET framework exposes an easier way to determine that thing.

Pseudo-Code written in VB.Net but I could manage a C# approach too:

Public Shared Function GetStartType(ByVal svcName As String) As ServiceControllerStatus

    Dim svc As ServiceController = (From service As ServiceController In ServiceController.GetServices()
         Where service.ServiceName.Equals(svcName, StringComparison.OrdinalIgnoreCase)
        ).FirstOrDefault

    If svc Is Nothing Then
        Throw New ArgumentException("Any service found with the specified name.", "svcName")
    Else
        Using svc
            ' Note that StartTypeEnumValue does not exists.
            Return svc.StartTypeEnumValue
        End Using
    End If

End Function

Solution

  • Since I'm not totally sure of the answer to my main question (a member inside .net framework class library capable to get this info) i've developed this registry approach which at least is much more fast that messing with WMI and also can determine if a service is autostart delayed.

    Firstlly a custom enum to extend the actual ServiceStartMode enum:

    ''' <summary>
    ''' Indicates the start mode of a service.
    ''' </summary>
    Public Enum SvcStartMode As Integer
    
        ''' <summary>
        ''' Indicates that the service has not a start mode defined.
        ''' Since a service should have a start mode defined, this means an error occured retrieving the start mode.
        ''' </summary>
        Undefinied = 0
    
        ''' <summary>
        ''' Indicates that the service is to be started (or was started) by the operating system, at system start-up.
        ''' The service is started after other auto-start services are started plus a short delay.
        ''' </summary>
        AutomaticDelayed = 1
    
        ''' <summary>
        ''' Indicates that the service is to be started (or was started) by the operating system, at system start-up. 
        ''' If an automatically started service depends on a manually started service, 
        ''' the manually started service is also started automatically at system startup.
        ''' </summary>
        Automatic = 2 'ServiceStartMode.Automatic
    
        ''' <summary>
        ''' Indicates that the service is started only manually, 
        ''' by a user (using the Service Control Manager) or by an application.
        ''' </summary>
        Manual = 3 'ServiceStartMode.Manual
    
        ''' <summary>
        ''' Indicates that the service is disabled, so that it cannot be started by a user or application.
        ''' </summary>
        Disabled = 4 ' ServiceStartMode.Disabled
    
    End Enum
    

    Secondly, this function:

    ''' <summary>
    ''' Gets the start mode of a service.
    ''' </summary>
    ''' <param name="svcName">The service name.</param>
    ''' <returns>The service's start mode.</returns>
    ''' <exception cref="ArgumentException">
    ''' Any service found with the specified name.
    ''' </exception>
    ''' <exception cref="Exception">
    ''' Registry value "Start" not found for service.
    ''' </exception>
    ''' <exception cref="Exception">
    ''' Registry value "DelayedAutoStart" not found for service.
    ''' </exception>
    Public Shared Function GetStartMode(ByVal svcName As String) As SvcStartMode
    
        Dim reg As RegistryKey = Nothing
        Dim startModeValue As Integer = 0
        Dim delayedAutoStartValue As Integer = 0
    
        Try
            reg = Registry.LocalMachine.
                  OpenSubKey("SYSTEM\CurrentControlSet\Services\" & svcName,
                  writable:=False)
    
            If reg Is Nothing Then
                Throw New ArgumentException("Any service found with the specified name.", 
                                            paramName:="svcName")
    
            Else
                startModeValue = Convert.ToInt32(reg.GetValue("Start",
                                 defaultValue:=-1))
    
                delayedAutoStartValue = Convert.ToInt32(reg.GetValue("DelayedAutoStart", 
                                        defaultValue:=0))
    
                If startModeValue = -1 Then
                    Throw New Exception(String.Format(
                              "Registry value ""Start"" not found for service '{0}'.", 
                              svcName))
    
                    Return SvcStartMode.Undefinied
    
                Else
                    Return DirectCast(
                           [Enum].Parse(GetType(SvcStartMode),
                                       (startModeValue - delayedAutoStartValue).ToString), 
                                        SvcStartMode)
    
                End If
    
            End If
    
        Catch ex As Exception
            Throw
    
        Finally
            If reg IsNot Nothing Then
                reg.Dispose()
            End If
    
        End Try
    
    End Function