Best Practice for the Active Setup StubPath value

by Jeremy Saunders on September 25, 2023

It’s been a best practice for a long time to clear the Active Setup StubPath value per application to avoid the Active Setup processes from running at logon, impacting the user experience. This is a challenge we constantly have with Vendors and packaging teams. But blindly clearing the StubPath value could lead to application issues. So what happens when you need to go back and troubleshoot an issue with an application that may be related to what “should have” run via the Active Setup process. How do you know what the StubPath value was originally set to? Do you record it somewhere?

I’ve been running a script for years over my builds that simply renames the existing StubPath value to StubPath.Backup and time stamps it. This way you can always review what it should be, and make the necessary changes to allow for this.

The following screen shot shows what the Microsoft Edge StubPath looks like once the script has run.

Active Setup StubPath

Notice how the real StubPath value is blank as per best practice, but a second value exists that is a point in time backup of the value? So in this case should we experience issues with Microsoft Edge, I can easily review what the expected value was set to in order to understand if this is the cause of the issue. With this in place there is no stress.

The script enumerates all subkeys from the following keys to process all StubPath values:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components
  • HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Active Setup\Installed Components

I run this as a once of task after all the applications are patches are installed before a build completes, but you can also run it as a computer startup script.

Here is the Active Setup StubPath (176 downloads) script:

<#
  This script will clear the Active Setup Stubpath values. However, instead of just clearing them,
  it creates a backup of the Stubpath with the time stamp for future reference and troublshooting
  requirements.

  Script name: ClearActiveSetup.ps1
  Release 1.2
  Written by Jeremy Saunders (jeremy@jhouseconsulting.com) 19th September 2017
  Modified by Jeremy Saunders (jeremy@jhouseconsulting.com) 25th September 2023

#>

#-------------------------------------------------------------

# Set Powershell Compatibility Mode
Set-StrictMode -Version 2.0

# Enable verbose, warning and error mode
$VerbosePreference = 'Continue'
$WarningPreference = 'Continue'
$ErrorPreference = 'Continue'

#-------------------------------------------------------------

$StartDTM = (Get-Date)

# Get the TEMP path
$logPath = [System.IO.Path]::GetTempPath()
$logPath = $logPath.Substring(0,$logPath.Length-1)

# Set the logpath to C:\Windows\Temp
$logPath = "${env:SystemRoot}" + "\Temp"

# Get the script name
$ScriptName = [System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString())

$logFile = "$logPath\$ScriptName.log"

# Start the transcript
try {
  Start-Transcript "$logFile"
}
catch {
  Write-Verbose "$(Get-Date -format "dd/MM/yyyy HH:mm:ss"): This host does not support transcription"
}

#------------------------------------

# Add strings to this array that may be in StubPaths that you want to be excluded from being cleared.
$Excludes = @()

$ParentPaths = @("HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components","HKLM:\SOFTWARE\WOW6432Node\Microsoft\Active Setup\Installed Components")
$Value = "StubPath"
$BackupValue = "StubPath.Backup-$(Get-Date -format "dd/MM/yyyy HH:mm:ss")"

ForEach ($ParentPath in $ParentPaths) {
  Get-Childitem "$ParentPath" -Recurse -ErrorAction SilentlyContinue | % {
    $ValueExist = $False
    $ErrorActionPreference = "stop"
    Try {
      If ((Get-ItemProperty -Path "$ParentPath\$($_.PSChildName)" | Select-Object -ExpandProperty "$Value") -ne $null) {
        $ValueExist = $True
      }
    }
    Catch [System.Exception] {
      #$($_.Exception.Message)
    }
    $ErrorActionPreference = "Continue" 
    If ($ValueExist) {
      Write-Verbose "`"$Value`" found under `"$ParentPath\$($_.PSChildName)`"" -verbose
      $BackupValueExist = $False
      $ErrorActionPreference = "stop"
      Try {
        If ((Get-ItemProperty -Path "$ParentPath\$($_.PSChildName)" | Select-Object -ExpandProperty "$BackupValue") -ne $null) {
          $BackupValueExist = $True
        }
      }
      Catch [System.Exception] {
        #$($_.Exception.Message)
      }
      $ErrorActionPreference = "Continue" 
      If ($BackupValueExist -eq $False) {
        $ParentKey = Get-Item -Path "$ParentPath\$($_.PSChildName)"
        $PropertyValue = $ParentKey.GetValue("$Value")
        If ($PropertyValue -ne "") {
          Write-Verbose "- Value: $PropertyValue" -verbose
          $PropertyType = $ParentKey.GetValueKind("$Value")
          $Skip = $False
          ForEach ($Exlude in $Excludes) {
            If ($PropertyValue -Like "*$Exlude*") {
              $Skip = $True
              Break
            }
          }
          If ($Skip -eq $False) {
            Write-Verbose "- Type: $PropertyType" -verbose
            Write-Verbose "- Renaming to `"$BackupValue`"..." -verbose
            Rename-ItemProperty -Path "$ParentPath\$($_.PSChildName)" -Name "$Value" -NewName "$BackupValue"
            Write-Verbose "- Creating an empty `"$Value`" value with property type of `"$PropertyType`"..." -verbose
            New-ItemProperty -Path "$ParentPath\$($_.PSChildName)" -Name "$Value" -PropertyType $PropertyType -Value ""  Force | Out-Null
          } Else {
            Write-Verbose "- This $Value value has been excluded. No action will be taken." -verbose
          }
        } Else {
          Write-Verbose "- The value is empty. No action will be taken." -verbose
        }
      } Else {
        Write-Verbose "- The `"$BackupValue`" value already exists." -verbose
      }
    }
  }
}

#------------------------------------

Write-Verbose "Stop logging" -Verbose
$EndDTM = (Get-Date)
Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalSeconds) Seconds" -Verbose
Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalMinutes) Minutes" -Verbose

# Stop the transcript
try {
  Stop-Transcript
}
catch {
  Write-Verbose "$(Get-Date -format "dd/MM/yyyy HH:mm:ss"): This host does not support transcription"
}

Enjoy!

Jeremy Saunders

Jeremy Saunders

Technical Architect | DevOps Evangelist | Software Developer | Microsoft, NVIDIA, Citrix and Desktop Virtualisation (VDI) Specialist/Expert | Rapper | Improvisor | Comedian | Property Investor | Kayaking enthusiast at J House Consulting
Jeremy Saunders is the Problem Terminator. He is a highly respected IT Professional with over 35 years’ experience in the industry. Using his exceptional design and problem solving skills with precise methodologies applied at both technical and business levels he is always focused on achieving the best business outcomes. He worked as an independent consultant until September 2017, when he took up a full time role at BHP, one of the largest and most innovative global mining companies. With a diverse skill set, high ethical standards, and attention to detail, coupled with a friendly nature and great sense of humour, Jeremy aligns to industry and vendor best practices, which puts him amongst the leaders of his field. He is intensely passionate about solving technology problems for his organisation, their customers and the tech community, to improve the user experience, reliability and operational support. Views and IP shared on this site belong to Jeremy.
Jeremy Saunders
Jeremy Saunders

Previous post:

Next post: