Cleanup #ConfigMgr Software Update Groups via PowerShell

We use Automatic Deployment Rules (ADR) for Security Updates, other updates, Defender updates and 3rd party Software Update Catalogs. Since all these updates need to be tested through our internal rings, we use the option ‘Create a new Software Update Group’. So, if the ADR detects added updates it creates a new Software Update Group (SUG). Once the SUGs are outdated we need to cleanup.


Additionally, we use the option ‘Install Software Updates > Mandatory software updates only’ in the OSD task sequence to ensure that only tested updates will be applied.
As a result, we want to keep the SUG with the last expired deployment deadline but delete all older.

The goal

Run a PowerShell script daily that goes through the ADR created SUGs, detect the last deadline of all deployments of the SUGs and remove all older SUGs.

The script

Needs to:

  • Find all active ADRs
  • Find all SUGs of an ADR
  • Find all deployments of a SUG of an ADR
  • Find the latest deadline of all deployments of a SUG of an ADR
  • Find the latest expired deadline of all deployments of all SUGs of an ADR
  • Delete older expired SUGs
# Get all ADRs
$ADRs = Get-CMSoftwareUpdateAutoDeploymentRule -Name "*" -ForceWildcardHandling -Fast
foreach ($ADRItem in $ADRs) {
  if ($ADRItem.AutoDeploymentEnabled) {
    # If the ADR is enabled
    $SUGNameWildcard = $ADRItem.Name + "*"
    # Find all Software Update Groups
    $SUGroups =  Get-CMSoftwareUpdateGroup -Name $SUGNameWildcard -ForceWildcardHandling
    foreach ($SUGItem in $SUGroups) {
      # Find all deployments for a SUG
      $SUGDeployments = Get-CMDeployment -FeatureType SoftwareUpdate -SoftwareName $SUGItem.LocalizedDisplayName
      foreach ($SUGDItem in $SUGDeployments) {
        #Search for the deadlines of a SUG deployment
        if (!$DeadLineMax) {
          [datetime]$DeadLineMax = $SUGDItem.EnforcementDeadline
        elseif ($SUGDItem.EnforcementDeadline -gt $DeadLineMax) {
          #Keep the greatest (latest) deadline of a SUG deployment
          [datetime]$DeadLineMax = $SUGDItem.EnforcementDeadline
      # Add to max deadline list
      if ($DeadLineMax) {
        # A list of all greatest (latest) deadlines of all deployments of all SUGs of a specific ADR 
        $SUGDDeadlineList.Add($SUGDItem.ApplicationName, $DeadLineMax)
        Remove-Variable DeadLineMax
    # Sort the list by deadlines
    $SUGDDeadlineListSorted = $SUGDDeadlineList.GetEnumerator() | Sort-Object -Property Value -Descending
    # Find the SUGs of an ADR to be deleted
    foreach ($SUGDLItem in $SUGDDeadlineListSorted) {
      if ($ToBeDeleted){
        Remove-CMSoftwareUpdateGroup -Name $SUGDLItem.Name -Force
      elseif ($SUGDLItem.Value -lt $Now) {
        # from here all smaller (older) deadlines in the list can be deleted
        $ToBeDeleted = $true
    # Refresh for next ADR
    $SUGDDeadlineListSorted = @{}
    $SUGDDeadlineList = @{}
    $ToBeDeleted = $false

The full script incl. CM initialization and a logfile is here:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s