The Two Sides of Group Policy Script Extension Processing, Part 1

By Judith Herman, Microsoft Corporation

In Part 1 of an eventual two-part series, Judith Herman begins to unravel – and explain – the process by which logon/logoff and startup/shutdown scripts are assigned and executed.

An Introduction to Deploying Scripts Using Group Policy

Have you ever deployed a script using Group Policy and wondered why it didn’t run? It looked as if the policy processed, so the script should have run, right? And yet still you have questions, big questions. Well, maybe not quite so big—not “the origin of the universe” big—but still fundamental questions about how the whole logon/logoff and startup/shutdown script process should be working.

And so you start looking around and confirm that the Group Policy scripts client-side extension (CSE) processed successfully. At the same time, however, you notice the startup or logon scripts don’t seem to have executed. But when you run them from a command prompt the scripts run fine. So what gives, you ask? You’ve checked everything and can’t find anything wrong; there aren’t even any USERENV error messages in the event logs. You’re stuck.

Here’s the short answer: The Group Policy scripts CSE is not responsible for running your scripts. Instead, its sole purpose is to figure out which scripts should run at startup, logon, logoff, or shutdown, and to add registry keys with information about those scripts to each computer target by the Group Policy object. A separate process—which is not part of Group Policy—actually runs the scripts at startup, logon, logoff or shutdown based on the information placed in those registry keys. It’s very possible for Group Policy to run just fine, but for the scripts to fail to run at all.

We’ll be looking at the two sides of Group Policy scripts policy settings in this two-part article. In Part 1, we discuss how the CSE processes the scripts policy setting information configured in the Group Policy object. In Part 2, we’ll discuss how the scripts run at startup, logon, logoff, or shutdown.

The Role of the Client-Side Extension

Let’s back up to the start of our conversation. The Group Policy engine calls the scripts CSE when the engine determines that the scripts policy settings have changed: either a script is added or a script is deleted from the startup, logon, logoff, or shutdown sections of the Group Policy object (GPO). The Group Policy scripts CSE determines which scripts to add or delete and stores this information in registry keys.

And yes, you, the administrator, can read these registry keys; this enables you to quickly see a list of the scripts deployed by Group Policy. Let’s take a closer look at these registry keys. There are four different registry keys of interest, one each for startup, logon, logoff, and shutdown.

  • HKLM\SOFTWARE\Policies\Microsoft\Windows\System\Scripts\Startup
  • HKLM\SOFTWARE\Policies\Microsoft\Windows\System\Scripts\Shutdown
  • HKCU\Software\Policies\Microsoft\Windows\System\Scripts\Logon
  • HKCU\Software\Policies\Microsoft\Windows\System\Scripts\Logoff

Don’t panic if you don’t find all of these keys on your system. You will see them only when Group Policy scripts exist for your Active Directory user or computer account.

The registry subkeys correspond to each GPO that has a script policy defined. For example, the layout for the GPO registry keys and subkeys might look something like this:

The subkeys are labeled with sequential numbers starting with 0. Expanding each GPO subkey reveals another set of numbered registry keys. These registry keys provide information for each script defined in the GPO for startup, logon, logoff, or shutdown. The values provided for each script are the script’s full name—which includes the path to the script—parameters, and execution time.

Compare that to the set of registry subkeys for a deployed script stored in a domain controller script’s directory:

When the script is stored inn the domain controller script’s directory, no path is provided in the registry key. The following screenshot shows a set of registry subkeys for a deployed script stored in a different folder on the domain computer:

You can write a script to read the registry list and thus obtain information about the Group Policy scripts that Group Policy deployed to your machine or user. To view any of the logon scripts shown in the example figures you need to list two sets of subkeys. Any script to read information on deployed scripts needs to look at the two sets of subkeys.

The first set of subkeys are the GPO subkeys, which are located directly under the HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System\Scripts\Logon registry key. These subkeys are named numerically, starting with 0 for the first GPO containing logon scripts and increasing by 1 for each subsequent GPO. In our example, you see two registry subkeys: 0 and 1. Under each of these GPO subkeys, the script displays the GPO name and GUID represented by the DisplayName and GPOName values. Here’s the portion of the script that handles this task:

 

strKeyPath = "Software\Policies\Microsoft\Windows\System\Scripts\Logon"
oReg.EnumKey HKEY_CURRENT_USER, strKeyPath, arrSubKeys

For Each subkey In arrSubKeys
    strValueName  = "DisplayName"
    strGUIDVName  = "GPOName"
    strFullKeyPath = strKeyPath & "\" & subkey
    oReg.GetStringValue HKEY_CURRENT_USER, strFullKeyPath, strValueName, szValue
    oReg.GetStringValue HKEY_CURRENT_USER, strFullKeyPath, strGUIDVName, szGPOName
    wScript.Echo "Name and GUID of GPO deploying logon Script = " & szValue & "    " & szGPOName
Next

The second set of subkeys are the individual logon scripts that are added to each GPO. These subkeys are also named numerically starting with 0 for the first logon script and increasing by 1 for each logon script added to the GPO. In our example, you see two registry subkeys: 0 and 1 under the GPO subkey 1. For each GPO subkey you need to display the script name containing the full path as well as the parameters for the scripts represented by the Script and Parameters values. Here’s the portion of the script that handles this task:

oReg.EnumKey HKEY_CURRENT_USER, strFullKeyPath, arrGPOSubKeys
For Each Scriptsubkey in arrGPOSubkeys

    ' Script and parameters under subkeys
    strScript = "Script"
    strParam  = "Parameters"
    strScriptKeyPath = strFullKeyPath & "\" & Scriptsubkey
    oReg.GetStringValue HKEY_CURRENT_USER, strScriptKeyPath, strScript, szScript
    oReg.GetStringValue HKEY_CURRENT_USER, strScriptKeyPath, strParam,  szParam
    wScript.Echo "   Logon script = " & szScript
    wScript.Echo "   Script Parameters = " & szParam
    wScript.Echo "    "
Next

Combining both sections gives us a full script sample similar to this:

Const HKEY_CURRENT_USER = &H80000001

strComputer = "."

Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

strKeyPath = "Software\Policies\Microsoft\Windows\System\Scripts\Logon"
oReg.EnumKey HKEY_CURRENT_USER, strKeyPath, arrSubKeys

For Each subkey In arrSubKeys
    strValueName  = "DisplayName"
    strGUIDVName  = "GPOName"
    strFullKeyPath = strKeyPath & "\" & subkey
    oReg.GetStringValue HKEY_CURRENT_USER, strFullKeyPath, strValueName, szValue
    oReg.GetStringValue HKEY_CURRENT_USER, strFullKeyPath, strGUIDVName, szGPOName
    wScript.Echo "Name and GUID of GPO deploying logon Script = " & szValue & "    " & szGPOName

    oReg.EnumKey HKEY_CURRENT_USER, strFullKeyPath, arrGPOSubKeys
    For Each Scriptsubkey in arrGPOSubkeys

        ' Script and parameters under subkeys
        strScript = "Script"
        strParam  = "Parameters"
        strScriptKeyPath = strFullKeyPath & "\" & Scriptsubkey
        oReg.GetStringValue HKEY_CURRENT_USER, strScriptKeyPath, strScript, szScript
        oReg.GetStringValue HKEY_CURRENT_USER, strScriptKeyPath, strParam,  szParam
        wScript.Echo "   Logon script = " & szScript
        wScript.Echo "   Script Parameters = " & szParam
        wScript.Echo "    "
    Next

Next

The full sample scripts to read the different Group Policy script registry keys can be found in the Script Center Script Repository. These scripts include:

  • List Logon Scripts Deployed to the Local Computer
  • List Logoff Scripts Deployed to the Local Computer
  • List Startup Scripts Deployed to the Local Computer
  • List Shutdown Scripts Deployed to the Local Computer

These scripts display the list of GPOs (the friendly display name and GUID) that have a specific type of script deployed to the computer or user account. In addition, the scripts display the script name with full path and parameters.

You can see how useful it is to read these registry keys. If a script registry key exists, then you can assume that Group Policy script client-side extension found and processed the policy setting correctly. No more confusion over whether or not Group Policy processed.