Friday, 3 October 2014

SCCM 2012 - Automatically uninstall unused applications

In this post I will explain how to automate the uninstall of applications that are not used in a number of days.

This is useful for a number of reasons but mostly to save on licenses.

The following is the workflow until it gets to the automatic uninstall of the application.



Once you follow all the steps of this post no further interaction is required. When a condition is met the application will automatically be uninstalled from the computer.

Let's get started. I'm going to use as example the automatic uninstall of WinZip (a licensed application) if it's not used for 90 days or more.

First thing create a Software Metering rule for WinZip.



Once the rule is created, select it and from the Summary at the bottom of the console take note of the Internal Rule ID which will be used in a Collection Query later.



Now create the following collections:

INSTALL WinZip

The membership can be Direct or Query based. In this case I will chose query based which is the most complex but most common scenario. Limit the membership to All Systems.


Let's assumed that my domain is ITSELF and the AD Groups is named WinZip. The following query will retrieve all member of the ITSELF\WinZip AD Group.

select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.SystemGroupName = "ITSELF\\WinZip"

This collection will have the WinZip install deployed to it.

UNINSTALL WinZip

The membership should be Query based. Limit the membership to All Systems. The following query will retrieve all computers which have WinZip installed.


select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_AppClientState on SMS_G_System_AppClientState.MachineName = SMS_R_System.Name where SMS_G_System_AppClientState.ComplianceState = 1 and SMS_G_System_AppClientState.AppName like "%WinZip%"

This collection will have the WinZip uninstall deployed to it.

USED IN THE LAST 90 DAYS WinZip

The membership should be Query based. Limit the membership to the INSTALL WinZip collection.


The following query will retrieve the Software Metering data collected for WinZip using the Rule ID I told you to take note in the beginning of this post. But it doesn't get all computers which have used WinZip, it only retrieve those which have used it in the last 90 days.


select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_SYSTEM inner join SMS_MonthlyUsageSummary on SMS_R_SYSTEM.ResourceID = SMS_MonthlyUsageSummary.ResourceID INNER JOIN SMS_MeteredFiles ON SMS_MonthlyUsageSummary.FileID = SMS_MeteredFile.MeteredFileID WHERE DateDiff(day, SMS_MonthlyUsageSummary.LastUsage, GetDate()) < 90  AND SMS_MeteredFiles.RuleID = 16777317

There is nothing deployed to this collection.

AUTOMATIC UNINSTALL WinZip

This collection should be limited to the INSTALL WinZip collection.


The membership should be the inclusion of the INSTALL Winzip Collection and the exclusion of the USED IN THE LAST 90 DAYS WinZip collection.


There is nothing deployed to this collection also.

OK now we have all the collections required and they should reflect the correct numbers.

Next step is to create a daily scheduled task which will run the script below. The scheduled task should run using an user which has both permissions to remove members of SCCM collections and remove members of AD groups.

The script below will go through all the AUTOMATIC UNINSTALL collections and it will retrieve a list of its members. Then it will search for those members in the INSTALL collection and in the AD Group and it will remove them from there.

Once they are removed from the collection the Uninstall Deploy will trigger and uninstall the application.

Note that we must have a good name convention for your collections and AD groups. They should all match in order for this to work. For example if the collection is INSTALL Winzip, your AD group should be named WinZip. Of course you can adapt the script to fit your environment.

#Gets current date to append to log
$date = (get-date).ToShortDateString().replace("/","")

#Log location and log name
$logfile = "C:\Temp\AutomaticUninstall$date.log"

#Writes first line to log
"Starting AutomaticUninstall.ps1..." | Out-File $logfile

#Imports SCCM module
Import-Module ($Env:SMS_ADMIN_UI_PATH.ToString().SubString(0,$Env:SMS_ADMIN_UI_PATH.Length - 5) + "\ConfigurationManager.psd1")

#Imports AD module
Import-Module ActiveDirectory

#Gets SCCM Site Code
$SMSProvider = get-wmiobject sms_providerlocation -namespace root\sms -filter “ProviderForLocalSite = True”
$SiteCode = $SMSProvider.SiteCode

#Change location to SCCM drive
Set-Location "$SiteCode:"

#Get a list of all collections which starts with AUTOMATIC UNINSTALL
$collections = Get-CMDeviceCollection -Name "AUTOMATIC UNINSTALL*" | select Name, MemberCount

#for each collection
foreach($collection in $collections){

#if current collection has more than 1 member
    if($collection.MemberCount -gt 0){

#Write current collection name to log
    "Collection: $($collection.name)" | Out-File $logfile -append

#Get members of the current collection
    $devices = Get-CMDevice -CollectionName $collection.Name | Select -ExpandProperty Name

#Get name of AD Group
    $group = $collection.Name.Replace("AUTOMATIC UNINSTALL ","")

#Get name of the current INSTALL collection
    $InstallCollection = "INSTALL $group"

#for each computer in the current collection
    foreach($device in $devices){

#Write computer name to log        
 "Member removed: $device" | Out-File $logfile -append

#Remove computer from AD group
        Try{Remove-ADGroupMember -Identity $group -Members (Get-ADComputer $device) -Confirm:$False -ErrorAction SilentlyContinue}
        Catch{}

#Remove computer from current INSTALL collection
        Remove-CMDeviceCollectionDirectMembershipRule -CollectionName $InstallCollection -ResourceName $device -Force
        }
    }
}


No comments:

Post a Comment