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: https://github.com/sigurd-de/CM-ClearSoftwareUpdateGroups