MSEndpointMgr

SCCM Client Cache Maintenance – Configuration Baseline

Many of you would have found at some point you have had to deal with applications not deploying to due client cache directories being full. Typically the way around this is to run a PowerShell command at the machine / collection to clear this down or on the client using the “Delete Files” button on the Cache tab of the SCCM client.

There is a much easier way of maintaining cache directories automatically though, by using a Configuration Baseline to monitor your machines and clear down folder that are either no longer required due to applications being withdrawn or are beyond a retention range for which you could like to set.

In the below walk through we take you through adding a Configuration Item and Baseline for this purpose. The PowerShell script looks for inactive applications, applications with folders older than the retention range specified (14 days in this example) and misc folders contained within the ccmcache directory which can be removed.

Create A Configuration Item

Open the SCCM Management console and under Assets and Compliance\Compliance  Settings select Configuration Item. Now create a new Configuration Item

Select Operating Systems

Pick the Operating Systems that you which to apply the CI to:

Add Settings

Click on New on this screen and select “Script” under Settings Type:

Discovery & Remediation Scripts

Now enter your Discovery and Remediation Scripts

function SCCMPurgeList
{
  # Specify Max Days For CCM Cache Entries
  $MaxRetention = "14"
  
  # Connect To Resource Manager Com Object
  $SCCMClient = New-Object -ComObject UIResource.UIResourceMgr
  
  # Get SCCM Client Cache Directory Location
  $SCCMCacheDir = ($SCCMClient.GetCacheInfo().Location)
  
  # List All Applications Due In The Future Or Currently Running
  $PendingApps = $SCCMClient.GetAvailableApplications() | Where-Object { (($_.StartTime -gt (Get-Date)) -or ($_.IsCurrentlyRunning -eq "1")) }
  
  # Create List Of Applications To Purge From Cache
  $PurgeApps = $SCCMClient.GetCacheInfo().GetCacheElements() | Where-Object { ($_.ContentID -notin $PendingApps.PackageID) -and ((Test-Path -Path $_.Location) -eq $true) -and ($_.LastReferenceTime -lt (Get-Date).AddDays(- $MaxRetention)) }
  
  # Count Applications To Purge
  $PurgeCount = ($PurgeApps.Items).Count
  
  # Clean Up Misc Directories 
  $ActiveDirs = $SCCMClient.GetCacheInfo().GetCacheElements() | ForEach-Object { Write-Output $_.Location }
  $MiscDirs = (Get-ChildItem -Path $SCCMCacheDir | Where-Object { (($_.PsIsContainer -eq $true) -and ($_.FullName -notin $ActiveDirs)) }).count
  
  # Add Old App & Misc Directories
  $PurgeCount = $PurgeCount + $MiscDirs
  
  # Return Number Of Applications To Purge
  Return $PurgeCount
}
SCCMPurgeList
Remediation Script
function SCCMPurgeList
{
  # Specify Max Days For CCM Cache Entries
  $MaxRetention = "14"
  
  # Connect To Resource Manager Com Object
  $SCCMClient = New-Object -ComObject UIResource.UIResourceMgr

  # Check for Com Object type and process
    if ($SCCMClient -ne $null){
        if (($SCCMClient.GetType()).Name -match "_ComObject"){

            # Get SCCM Client Cache Directory Location
            $SCCMCacheDir = ($SCCMClient.GetCacheInfo().Location)
            
            # List All Applications Due In The Future Or Currently Running
            $PendingApps = $SCCMClient.GetAvailableApplications() | Where-Object { (($_.StartTime -gt (Get-Date)) -or ($_.IsCurrentlyRunning -eq "1")) }
            
            # Create List Of Applications To Purge From Cache
            $PurgeApps = $SCCMClient.GetCacheInfo().GetCacheElements() | Where-Object { ($_.ContentID -notin $PendingApps.PackageID) -and $((Test-Path -Path $_.Location) -eq $true) -and ($_.LastReferenceTime -lt (Get-Date).AddDays(- $MaxRetention)) }
            
            # Purge Apps No Longer Required
            foreach ($App in $PurgeApps)
            {
                $SCCMClient.GetCacheInfo().DeleteCacheElement($App.CacheElementID)
            }
            
            # Clean Up Misc Directories 
            $ActiveDirs = $SCCMClient.GetCacheInfo().GetCacheElements() | ForEach-Object { Write-Output $_.Location }
            Get-ChildItem -Path $SCCMCacheDir | Where-Object { (($_.PsIsContainer -eq $true) -and ($_.FullName -notin $ActiveDirs)) } | Remove-Item -Recurse -Force -Verbose
        }
    }
}
SCCMPurgeList

Create A New Rule

Here we will select the settings previously created and set a target value for the new rule


Now the Configuration Item is in place, we can go onto setting up the Baseline to deploy to your chosen Collection.

Create A New Configuration Baseline

Create your new Configuration Baseline, Select the Configuration Item you set up in the previous steps and click OK.

The Final Step is to deploy your newly created Configuration Baseline to a chosen collection.

Now sit back, relax and let your Configuration Baseline take care of maintaining your client cache folders 😀

Note: As always the scripts provided are used at your own risk and should be tested against limited collections.

Maurice Daly

Maurice has been working in the IT industry for the past 20 years and currently working in the role of Senior Cloud Architect with CloudWay. With a focus on OS deployment through SCCM/MDT, group policies, active directory, virtualisation and office 365, Maurice has been a Windows Server MCSE since 2008 and was awarded Enterprise Mobility MVP in March 2017. Most recently his focus has been on automation of deployment tasks, creating and sharing PowerShell scripts and other content to help others streamline their deployment processes.

35 comments

  • Can confirm this change is necessary as of 11/2018. I noticed it, came here to post, and you beat me to it.

  • theres a Typo in Line 11 of the remediation script – no wildcards = always false

  • Yes, the script itself works locally when I change the above value. When the script is run from the CI/CB it does not. I get errors, something along the lines of “Handling dependency failure” and also “CCIInfo::SetError – Setting CI level error to (0x87d00324). CIAgent 22/10/2018 14:28:18 2040 (0x07F8)”

    Any clue OP? Cheers.

  • My environment is running CB 1710 and I was having trouble getting this to work on a Windows 10 machine.. the discovery script worked perfectly and the remediation script was running, however nothing was getting purged.

    I pulled my hair out for a bit before I started to tear apart the logic in the remediation script one by one, on line 11 I came across a discrepancy:

    if (($SCCMClient.GetType()).Name -like “_ComObject”){

    On my workstation that value returns __ComObject instead of _ComObject so that entire block was not executing. Not sure if something changed with newer versions of CB?

    • Hi Brandon,
      I was facing the same issue. Tried running the script on several computers. Than I read your comment and changing “_ComObject” to “__ComObject” did the trick.

    • Thank you for this, solved my problems getting this to work also.
      Creator should respond to this and update the script.

      • Hi Tobias,

        First of all it is not my intention to not respond to the typo, I have just been busy with work and travel over the past while and I am on catch up. The script typo was fixed in this instance.

        Regards

        Maurice

  • Does this ignore applications that are configured to persist in cache? Thanks

    • Hi Wayne,

      No the script is designed to delete beyond day x. It would be simple enough to add in exclusions based on your the list of applications set to persist in cache. I might re-work the script to cater for this.

      Maurice

  • Thanks Maurice script changed and detection value returned reverted back to 0 as it should be in the compliance conditions and all is working – Good stuff.

  • Hi Maurice – what did you change in the script as like Morten I too could not get it to work – I had to change the detection value returned to 1 instead of 0 in the compliance conditions and this worked – would you recommend to update script or would it be OK to leave as is.
    Cheers

    • Hi Dallan,

      The change is in the following line:

      # Create List Of Applications To Purge From Cache
      $PurgeApps = $SCCMClient.GetCacheInfo().GetCacheElements() | Where-Object { ($_.ContentID -notin $PendingApps.PackageID) -and ((Test-Path -Path $_.Location) -eq $true) -and ($_.LastReferenceTime -lt (Get-Date).AddDays(- $MaxRetention)) }

      You should update the script as it should return a 0 from running the detection script if the machine is compliant.

      Maurice

  • Am i missing something to the script.
    Ive been testing with everything over 1 day should be removed and still nothing happens.

    I am using 1703 windows.
    Even if i just run the script alone in powershell it finds nothing.
    On my test pc the cache dir has things over 4 days old.

    • Hi Morten,

      The post was migrated from the DeployEverything site and it looks like an old typo was included in the port. I have just updated the script in the post for you, if you use the detection script it should now do its job correctly. Thanks for pointing this out.

      Maurice

      • Perfekt.
        Works like a charm.
        Thank you so much for all the hard work!

  • For those getting the error “Error ID 0x80070001 – Incorrect Function”… as Maurice has explained, it’s because the client Powershell version is lower than 3. The detection and remediation scripts use an operator “-notin” which did not exist before Powershell 3.0.

    Good news, though, you can easily modify both scripts so they will work on Powershell 2.0 which came standard with Windows 7. Wherever you see “-notin” (it appears twice in each script), replace it with “-notcontains”, and swap the variables.

    For example, instead of
    $_.ContentID -notin $PendingApps.PackageID

    You want
    $PendingApps.PackageID -notcontains $_.ContentID

    And instead of
    $_.FullName -notin $ActiveDirs

    You want to have
    $ActiveDirs -notcontains $_.FullName

    That should get the configuration baseline working on clients with Powershell 2.0.

    • Good work around Cody, but I would encourage everyone to update to the latest version of PS on your selected OS. This not only ensures compatibility with many of the scripts out there in the community but also provides additional security & protection against malicious code contained within PS scripts.

      • I still get: Setting Discovery Error 0x80070001 Incorrect function.

        After applying the Powershell 2.0 script fixes mentioned by Cody above.

      • Just a suggestion, but you should be running the latest version of PowerShell for compatibility with new scripts etc.

  • Works flawlessly on Windows 8.1 and windows 10 clients.
    Windows 8.1 ships with PS version 4.0 and Windows 10 ships with PS version 5.0
    For the scripts to work with Windows 7 SP1 requires the PS version 2.0 to be upgraded – have upgraded a number of Windows 7 x86 & x64 systems via application upgrade and can confirm all now have compliance with the CB.

  • Hi Maurice

    Why you use in the discovery script “$_.StartTime” and in the remediation “$_.LastReferenceTime” ?

    Regards, Martin

  • Hi Maurice, I tried this script on one pc ( into collection ) and I recieve this error : Error ID 0x80070001 – Incorrect Function. It maybe say that the code is wrong? can you help me ? Max

  • it seemed to have worked on one machine running windows 7, but aside from that this is the error message I pulled from dcmwmiprovider.log:

    ScriptProvider::CreateInstanceEnumAsync – Script Execution Returned :1, Error Message:You must provide a value expression on the right-hand side of the ‘-‘ operator.
    At C:WindowsCCMSystemTemp26e9fa0e-f85a-4eb3-b599-904442947742.ps1:16 char:9
    3
    + $PurgeApps = $SCCMClient.GetCacheInfo().GetCacheElements() | Where-Object
    { ($_.ContentID – <<<< notin $PendingList.PackageID) -and ((Test-Path -Path $_
    .Location) -eq $true) -and ($_.StartTime -gt (Get-Date).AddDays(- $MaxRetention
    )) }
    + CategoryInfo : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : ExpectedValueExpression

    • Hi Jessie. You’ll need to update the version of PowerShell running on your Windows 7 machine. By the looks of the error you are probably running version 2.0.

  • quick question, I am testing this with a test collection for some odd reason I get an error message stating (Incorrect function) error id 0x80070001, error category: discovery. Any idea what this issue may be?

  • Hi Maurice,thx for sharing.
    In CM1610 I don’t see browseproperties button where you create RULE,

  • This is a stupid question, but after that last step you would than deploy it to your collections correct?

    • That is correct. You need to simply deploy the CB to a collection of your choice (obviously taking caution and testing against a test collection is recommended). I have added an extra screenshot to clarify the final step.

Sponsors