shishir kushawaha
MECM Cleanup Series: List Unused Software
Unused or unimportant applications and packages in MECM can consume valuable space and hinder the performance of the environment. When too many applications and packages exist, it can impact the system's performance, leading to slow deployment times and decreased efficiency. Therefore, it is crucial to identify and remove such packages and applications.
Unused applications and packages can accumulate in MECM for various reasons, such as not being deployed, not being linked to any task sequence, or not being distributed to any distribution point. These packages and applications can cause clutter and make it challenging to find what is essential in the environment.
To avoid such issues, it is necessary to perform a thorough investigation to identify and remove unused applications and packages. Once identified, the applications and packages can be safely removed to free up space and optimize the MECM environment's performance.

To achieve this, you can use PowerShell scripts to identify and remove unused packages and applications. Here are the steps:
First you need to list the packages and applications. You can use the Get-CMPackage cmdlet to retrieve package information such as name, package ID, source date, and object path.
$Packages = Get-CMPackage -fast | Select-Object Name, PackageID, SourceDate, ObjectPath
Use the Get-CMApplication cmdlet to retrieve application information such as localized display name, number of dependent task sequences, package ID, deployment status, expiration status, enabled status, created by, model name, and date created. Additionally, the Where-Object cmdlet is used to filter the results to only include applications that are not deployed, expired, or disabled.
$Applications = Get-CMApplication | Select-Object LocalizedDisplayName, PackageID,IsDeployed, IsExpired, IsEnabled,NumberOfDependentTS,CreatedBy, ModelName, DateCreated | Where-Object {$_.IsDeployed -eq $false -or $_.IsExpired -eq $true -or $_.IsEnabled -eq $false}
Next you need to gather all task sequences. You can use the Get-CMTaskSequence cmdlet to retrieve task sequence information such as name, package ID, and references. The Where-Object cmdlet is used to filter the results to only include task sequences that have references.
$TaskSequences = Get-CMTaskSequence | Select-Object Name, PackageID, References | Where-Object { $null -ne $_.References }
Finally, you need to list all the deployments. You can use the Get-CMDeployment cmdlet to retrieve deployment information such as software name, package ID, deployment ID, and collection ID.
$Deployments = Get-CMDeployment | Select-Object softwarename,packageid,deploymentid,collectionid
Once you have all the required information, you can execute below PowerShell scripts to list outdated and unused softwares.
Code to list outdated and unused Applications
foreach ($Application in $Applications)
{
if($Application.NumberOfDependentTS -eq 0 )
{
$dpcount=0;$pkgStatus=$null
if(($($Application.PackageID) -ne ""))
{
$pkgStatus=Get-CMDistributionStatus -Id $($Application.PackageID) $dpcount=$($pkgStatus.NumberErrors+$pkgStatus.NumberInProgress+$pkgStatus.NumberSuccess+$pkgStatus.NumberUnknown+0)
}
else{$dpcount='Unknown'}
$TaskSequenceMatch = [PSCustomObject]@{
'Software Name' = $($Application.LocalizedDisplayName)
'Type'="Application Model"
'Package ID'= $($Application.PackageID)
'Owner'= $($Application.CreatedBy)
'Date Created'=$($Application.DateCreated)
'DP Count'=$dpcount
}
$PackageReport += $TaskSequenceMatch
}}
Above PowerShell script loops through all the applications gathered in the previous step and checks if each application has any dependent task sequences. If an application does not have any dependent task sequences, it proceeds to check the number of distribution points to which the application package has been distributed. It used Get-CMDistributionStatus commandlet to get the distribution status.
If an application package ID exists, it uses the package ID to get the distribution status of the package, which includes the number of successful, in-progress, failed, and unknown distributions. If the package ID is not available, the DP count is set to 'Unknown'.
Code to list outdated and unused packages
Foreach ($Package in $Packages)
{
$TaskSequenceCount = $DeploymentCount=0
$DeploymentCount = ($Deployments | Where-Object { $_.PackageID -match $Package.PackageID }).count
if(($DeploymentCount -eq 0) -or ($null -eq $DeploymentCount ))
{
foreach ($TaskSequence in $TaskSequences)
{
if ($null -ne ($TaskSequence | Select-Object -ExpandProperty References | Where-Object { $_.Package -contains $Package.PackageID }))
{$TaskSequenceCount++;break}
}
if(($TaskSequenceCount -eq 0))
{
$pkgStatus=$null
$pkgStatus=Get-CMDistributionStatus -Id $($Package.PackageID)
$TaskSequenceMatch = [PSCustomObject]@{
'Software Name' = $($Package.Name)
'Type'="Package Model"
'Package ID'= $($Package.PackageID )
'Owner'= "NA"
'Date Created'= $($Package.SourceDate)
'DP Count'=$($pkgStatus.NumberErrors+$pkgStatus.NumberInProgress+$pkgStatus.NumberSuccess+$pkgStatus.NumberUnknown+0)
}
$PackageReport += $TaskSequenceMatch
}}}
This script iterates through each package in the $Packages array and checks whether it has any deployments associated with it. If there are no deployments, the script checks whether the package is referenced by any task sequence. If not, the script fetches the distribution status of the package.
Finally, a HTML report is prepared which have the details of all those softwares.

Before proceeding with the cleanup based on the generated list, there are several important considerations to keep in mind.
Check that none of the software listed in the report are part of a UDI deployment or referenced in any script used in a task sequence or any other deployment. Keep in mind that a package referenced in a script or UDI wizard does not guarantee the distribution status and its reference to a task sequence.
The script may take a longer time to run depending on the amount of software it has to analyze. Therefore, it's recommended to run the script during non-working hours to avoid any impact on users.
Double check everything before deleting. Ensure that the cleanup is aligned with the team and organization's policy.
Make sure to keep a backup of the objects being deleted so that if recreation is required, it can be done easily without any loss of data.
Remove unused packages and applications:
Use the following PowerShell command to remove the unused packages and applications:
Remove-CMApplication -ApplicationName "ApplicationName"
Remove-CMPackage -PackageName "PackageName"
Note: Replace "ApplicationName" and "PackageName" with the name of the package or application that needs to be removed.
You can find the complete PowerShell code from GitHub.
In conclusion, removing outdated and unused packages and applications in MECM is crucial to optimize the environment's performance and free up valuable space. It can be achieved using built-in reports or PowerShell commands to identify unused packages and applications that are no longer required. However, it is essential to perform a thorough investigation before removing any package or application to prevent any unintended consequences.