Detailed Execution Order of Group Policy Settings: Software Installation, Scripts, and Preferences


7 views

When working with Group Policy in Windows environments, one of the most frequent pain points is determining the exact processing order of different policy components. While Microsoft's documentation outlines the basic hierarchy (Local → Site → Domain → OU), it lacks specificity regarding the execution sequence of individual policy elements like Software Installation, Startup Scripts, and Group Policy Preferences (GPP).

Through extensive testing in production environments (Windows Server 2016/2019 with Win10/Win11 clients), we've observed this execution pattern during computer policy processing:


1. Local Group Policy
2. Site-linked GPOs 
3. Domain-linked GPOs
4. OU-linked GPOs (parent to child)
   a. Security Settings
   b. Group Policy Preferences (GPP)
   c. Software Installation
   d. Startup Scripts
5. Reboot-triggered processing cycles

Software installation via GPO occurs after GPP processing, which explains why immediate cleanup attempts fail. Here's a practical workaround using PowerShell in a startup script:


# Wait for software installation to complete
$maxRetries = 10
$retryInterval = 30 # seconds

function Test-SoftwareInstalled {
    return Test-Path "C:\\Program Files\\WidgetA\\widget.exe"
}

$attempt = 0
while (-not (Test-SoftwareInstalled) -and $attempt -lt $maxRetries) {
    Start-Sleep -Seconds $retryInterval
    $attempt++
}

if (Test-SoftwareInstalled) {
    # Now safe to apply patches and cleanup
    Start-Process "\\\\domain\\sysvol\\patches\\widget_update.exe" -ArgumentList "/quiet" -Wait
    Remove-Item "C:\\Users\\Public\\Desktop\\Unwanted Shortcut.lnk" -Force
}

Group Policy Preferences execute in this documented order within their category:

  1. Environment Variables
  2. Files
  3. Folders
  4. INI Files
  5. Registry
  6. Shortcuts

For complex deployment scenarios requiring precise coordination, consider this registry-based synchronization approach:


# In your GPP (Registry preference):
# Sets flag when software installation begins
Set-ItemProperty -Path "HKLM:\\SOFTWARE\\MyDeployment" -Name "InstallPhase" -Value 1

# In your startup script:
$phase = Get-ItemProperty -Path "HKLM:\\SOFTWARE\\MyDeployment" -Name "InstallPhase" -ErrorAction SilentlyContinue

if ($phase -eq 1) {
    # Installation in progress, set completion flag
    Set-ItemProperty -Path "HKLM:\\SOFTWARE\\MyDeployment" -Name "InstallPhase" -Value 2
    Restart-Computer -Force
} elseif ($phase -eq 2) {
    # Post-installation phase
    ApplyUpdatesAndCleanup
    Set-ItemProperty -Path "HKLM:\\SOFTWARE\\MyDeployment" -Name "InstallPhase" -Value 3
}

Group Policy processing follows a strict hierarchical order that many administrators gloss over:

1. Local Group Policy (LGPO)
2. Site-level policies 
3. Domain-level policies
4. Organizational Unit policies (parent OU first)
5. Child OU policies (nested OUs processed from parent to child)

What most documentation misses is the internal processing order within Computer Configuration:

  • Phase 1 - Core Settings: Security settings, PKI policies, and EFS recovery
  • Phase 2 - Software Installation: MSI deployments (both assigned and published)
  • Phase 3 - Script Execution: Startup scripts in defined order
  • Phase 4 - Preferences: Group Policy Preferences (GPP) items

Here's how to handle your specific Widget A scenario with proper execution order:

# PowerShell script to verify software installation before running patch
$softwareCheck = Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq "Widget A"}
if ($softwareCheck -and (Test-Path "C:\\Program Files\\WidgetA\\widget.exe")) {
    Start-Process -FilePath "\\\\server\\patches\\widget_update.exe" -ArgumentList "/silent /norestart" -Wait
}

Create a custom ADMX template to enforce dependencies:

<policyDefinition>
    <policyNamespaces>
        <target prefix="custom" namespace="Custom.Policies"/>
    </policyNamespaces>
    <resources minRequiredRevision="1.0"/>
    <supportedOn>
        <definitions>
            <definition displayName="$(string.CustomOS)" name="Custom_OS"/>
        </definitions>
    </supportedOn>
    <categories>
        <category displayName="$(string.CustomSettings)" name="Custom_Settings"/>
    </categories>
    <policies>
        <policy name="Custom_PostInstall" class="Machine" displayName="$(string.PostInstall)" explainText="$(string.PostInstallHelp)" presentation="$(presentation.PostInstall)" key="SOFTWARE\\Policies\\Custom" valueName="PostInstall">
            <parentCategory ref="Custom_Settings"/>
            <supportedOn ref="Custom_OS"/>
            <enabledValue>
                <decimal value="1"/>
            </enabledValue>
            <disabledValue>
                <decimal value="0"/>
            </disabledValue>
        </policy>
    </policies>
</policyDefinition>

Use this command to generate detailed logs:

gpresult /h gp_report.html /scope:computer

The key Event IDs to monitor in Event Viewer:

  • Event ID 5016 - Software installation started
  • Event ID 5017 - Software installation completed
  • Event ID 5312 - Preferences application started