Using Windows PowerShell to Determine Service Launch Order

Using Windows PowerShell to Determine Service Launch Order

  • Comments 1
  • Likes

Summary: The Microsoft Scripting Guys show how to determine service launch order by using Windows PowerShell and WMI in this helpful step-by-step article.

 

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to find out the order in which services start on my computer. To properly shut down a computer, the services should stop in reverse order that they start. I can find service dependencies via the services.msc tool, but I cannot seem to find anywhere that tells me the actual order in which services start. Can you help me?

-- RY

Hey, Scripting Guy! Answer

Hello RY,

Microsoft Scripting Guy Ed Wilson here. I was deep in thought working on a script to illustrate service load order when the landline rang. My landline almost never rings, and if it does, it is generally phone spam, which I ignore it. In fact, I do not even bother to look at the caller ID because I know the call will not be of interest to me. If people want to talk to me, they call my Windows Mobile 6.5 phone, catch me on Twitter, post something on Facebook, shoot me an email, or find me on Communicator. They do not call my landline. For me, the only reason I have a landline is so I can have ADSL. Now, Teresa, that is a different story.

Anyway, the call was from one of the organizers of the Raleigh, NC., SQL Saturday event, and I will now be speaking there on September 18, 2010. I am excited about the event, not only because I get to speak, but also because there will be some awesome sessions. And all the cool people within the tri-state region will be there. I will be talking about Windows PowerShell 2.0 best practices, and I will pull together information from the Microsoft Press book, Windows PowerShell 2.0 Best Practices, which I wrote. It will be very cool. By the way, Teresa will be there as well, and she is a lot more fun to talk to than I am. (Scripting Editor: They are both fun to talk to. Be sure to ask Ed about tea.)

RY, once I got off the phone, I completed the Get-ServiceLoadOrder.ps1 script. The complete script is shown here.

Get-ServiceLoadOrder.ps1

Get-WmiObject -Class win32_LoadOrderGroupServiceMembers |
ForEach-Object {
New-Object -TypeName psobject -Property `
   @{
     "GroupOrder"=([wmi]$_.GroupComponent).GroupOrder
     "GroupName"=([wmi]$_.GroupComponent).Name
     "ServiceName"=([wmi]$_.PartComponent).Name
     "Started"=([wmi]$_.PartComponent).Started
    }
} |
Where-Object { $_.started } |
Sort-Object -Property grouporder -Descending

Services group load order is stored in the registry in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder registry key. This is shown in the following image.

Image of registry key in which services group load order is stored

You do not have to directly query the registry key if you do not wish to do so, because WMI can retrieve the information by querying the win32_loadOrderGroup WMI class. Output from this class is shown in the following image.

Image of output from win32_loadOrderGroup WMI class

The Get-ServiceLoadOrder.ps1 script begins by using the Get-WmiObject cmdlet to query the Win32_LoadOrderGroupServiceMembers WMI class, which is an association class. Association classes relate one WMI class to another WMI class. The two classes that are related are the Win32_BaseService and the Win32_LoadOrderGroup class. This relationship is shown in the following image.

Image of relationship between Win32_BaseService class and Win32_LoadOrderGroup class

When the Win32_LoadOrderGroupServiceMembers WMI class is queried, the information that is returned does not look too exciting. An example of the kind of information that is returned is shown here:

PS C:\> Get-WmiObject -Class win32_LoadOrderGroupServiceMembers
__GENUS                  : 2
__CLASS                   : Win32_LoadOrderGroupServiceMembers
__SUPERCLASS         : CIM_Component
__DYNASTY                : CIM_Component
__RELPATH                : Win32_LoadOrderGroupServiceMembers.GroupComponent="\\\\MRED1\\roo
                                    t\\cimv2:Win32_LoadOrderGroup.Name=\"Boot Bus Extender\"",PartCom
                                    ponent="\\\\MRED1\\root\\cimv2:Win32_SystemDriver.Name=\"ACPI\""
__PROPERTY_COUNT : 2
__DERIVATION           : {CIM_Component}
__SERVER                  : MRED1
__NAMESPACE           : root\cimv2
__PATH                      : \\MRED1\root\cimv2:Win32_LoadOrderGroupServiceMembers.GroupCompon
                                     ent="\\\\MRED1\\root\\cimv2:Win32_LoadOrderGroup.Name=\"Boot Bus
                                     Extender\"",PartComponent="\\\\MRED1\\root\\cimv2:Win32_SystemDri
                                     ver.Name=\"ACPI\""
GroupComponent       : \\MRED1\root\cimv2:Win32_LoadOrderGroup.Name="Boot Bus Extender"
PartComponent          : \\MRED1\root\cimv2:Win32_SystemDriver.Name="ACPI"

The two main properties that are returned are called GroupComponent and PartComponent—they do not even sound too exciting. However, as seen in the following image, these two properties point to the key property of their respective classes.

Image of two main properties pointing to key property of respective classes

This is exciting! The reason is that the PartComponent and GroupComponent properties contain the path to a specific instance of a WMI class. Compare the __Path property from the query below with the value of the PartComponent property seen above. They are the same.

PS C:\> gwmi win32_baseservice -Filter "name = 'acpi'" | fl *

Status                           : OK
Name                            : ACPI
State                             : Running
ExitCode                       : 0
Started                          : True
ServiceSpecificExitCode : 0
__GENUS                       : 2
__CLASS                        : Win32_SystemDriver
__SUPERCLASS              : Win32_BaseService
__DYNASTY                    : CIM_ManagedSystemElement
__RELPATH                    : Win32_SystemDriver.Name="ACPI"
__PROPERTY_COUNT     : 22
__DERIVATION               : {Win32_BaseService, CIM_Service, CIM_LogicalElement, CIM_M
                                         anagedSystemElement}
__SERVER                      : MRED1
__NAMESPACE               : root\cimv2
__PATH                          : \\MRED1\root\cimv2:Win32_SystemDriver.Name="ACPI"
AcceptPause                  : False
AcceptStop                    : True
Caption                          : Microsoft ACPI Driver
CreationClassName       : Win32_SystemDriver
Description                     : Microsoft ACPI Driver
DesktopInteract             : False
DisplayName                  : Microsoft ACPI Driver
ErrorControl                   : Critical
InstallDate                     :
PathName                      : C:\Windows\system32\DRIVERS\ACPI.sys
ServiceType                    : Kernel Driver
StartMode                      : Boot
StartName                      :
SystemCreationClassName : Win32_ComputerSystem
SystemName                  : MRED1
TagId : 1
Scope                             : System.Management.ManagementScope
Path                               : \\MRED1\root\cimv2:Win32_SystemDriver.Name="ACPI"
Options                          : System.Management.ObjectGetOptions
ClassPath                       : \\MRED1\root\cimv2:Win32_SystemDriver
Properties                      : {AcceptPause, AcceptStop, Caption, CreationClassName...}
SystemProperties           : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers                        : {dynamic, Locale, provider, UUID}
Site                                 :
Container                       :

PS C:\>

One of the things that makes using the [WMI] type accelerator difficult to use is that it requires a key to a specific instance of a WMI class. But the cool thing is we get keys to specific instances of classes for free when using a WMI association class. This makes working with association classes extremely flexible and easy when using Windows PowerShell.

The GroupComponent and the PartComponent properties are described as a reference to another class. The reference to the other class is the key to the class in path form, and when using the [WMI] type accelerator, we use the path to the other class to return an instance of that class. This means that all of the properties from the Win32_BaseService and Win32_LoadOrderGroup are available to us.

It is this reference to another WMI class concept that fakes students of WMI out at first glance. They see the property GroupOrder or Started being used in the script, and wonder from where it comes. The properties are coming from the referenced WMI classes. The results of the Get-WmiObject WMI query are piped to the ForEach-Object cmdlet to allow us to work with each object as it comes across the pipeline. This is shown here:

Get-WmiObject -Class win32_LoadOrderGroupServiceMembers |

ForEach-Object {

Because we want to return information from each of the two WMI classes that are referenced, I decided to use the New-Object cmdlet to create a new object, and then use a hash table to add four properties to the object. The properties are the group order number, the name of the group, the service name, and whether the service is started. This section of the script is shown here:

New-Object -TypeName psobject -Property `

   @{

     "GroupOrder"=([wmi]$_.GroupComponent).GroupOrder

     "GroupName"=([wmi]$_.GroupComponent).Name

     "ServiceName"=([wmi]$_.PartComponent).Name

     "Started"=([wmi]$_.PartComponent).Started

    }

The cool thing about creating a custom Windows PowerShell object is that regular Windows PowerShell cmdlets can be used to manipulate the results that come from the query. Therefore, the first thing I am interested in seeing is only the services that are started. The Where-Object cmdlet is used to filter out only services that are started. Because the started property is a Boolean value, we can use a shortcut method as shown here:

Where-Object { $_.started } |

The above command is the same as saying only return objects that have a value for the started property of $true. This command is shown here:

Where-Object { $_.started -eq $true }

After the started services have been filtered, they are piped to the Sort-Object cmdlet, which is used to sort the services into their start order group in a descending fashion. This portion of the command is shown here:

Sort-Object -Property grouporder –Descending

When the script runs, the output is displayed that is shown in the following image.

Image of output displayed when script runs

RY, that is all there is to using WMI to display the service load groups for running services. This also concludes WMI Week. Join us tomorrow for Quick-Hits Friday.

We would love for you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum.. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi, really interesting stuff.

    I arrived here while investigating the possibility of managing service startup order, as the lan services take a while and I wondered if it was possible to increase the priority, without causing problems with dependencies/security/call order...

    here's the boot order (groups)

    ccekrnlG

    System Reserved

    EMS

    WdfLoadGroup

    Boot Bus Extender

    System Bus Extender

    SCSI miniport

    Port

    Primary Disk

    SCSI Class

    SCSI CDROM Class

    FSFilter Infrastructure

    FSFilter System

    FSFilter Bottom

    FSFilter Copy Protection

    FSFilter Security Enhancer

    FSFilter Open File

    FSFilter Physical Quota Management

    FSFilter Virtualization

    FSFilter Encryption

    FSFilter Compression

    FSFilter Imaging

    FSFilter HSM

    FSFilter Cluster File System

    FSFilter System Recovery

    FSFilter Quota Management

    FSFilter Content Screener

    FSFilter Continuous Backup

    FSFilter Replication

    FSFilter Anti-Virus

    FSFilter Undelete

    FSFilter Activity Monitor

    FSFilter Top

    Filter

    Boot File System

    Base

    Pointer Port

    Keyboard Port

    Pointer Class

    Keyboard Class

    Video Init

    Video

    Video Save

    File System

    Streams Drivers

    NDIS Wrapper

    COM Infrastructure

    Event Log

    AudioGroup

    ProfSvc_Group

    UIGroup

    MS_WindowsLocalValidation

    PlugPlay

    Cryptography

    PNP_TDI

    NDIS

    TDI

    iSCSI

    NetBIOSGroup

    ShellSvcGroup

    SchedulerGroup

    SpoolerGroup

    SmartCardGroup

    NetworkProvider

    MS_WindowsRemoteValidation

    NetDDEGroup

    Parallel arbitrator

    Extended Base

    PCI Configuration

    MS Transactions

    That means little to me, but I think that my services (synergy, hippomous 'winvnc') need stuff like Wlansvc, which is in the TDI group. So I COULD add a group, and have that load after TDI, but is there anything in the last ... ~12 groups that SHOULD be loaded before using the localnetwork/productivity programs that have been installed as super cool services that run on the login screen?

    Thanks!