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

Detection Script
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
  
  # 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
}
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 since 1999. Technology focus includes Active Directory, Group Policy, Hyper-V, Windows Deployment (SCCM & MDT) and Office 365.

Maurice is a Microsoft MVP since 2017 in the area of Enterprise Mobility

(2241)

comments
  • Jessie
    Posted at 21:29 February 21, 2017
    Jessie
    Reply
    Author

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

    • Maurice Daly
      Posted at 21:58 February 21, 2017
      Maurice Daly
      Reply
      Author

      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.

  • Jessie
    Posted at 22:44 February 21, 2017
    Jessie
    Reply
    Author

    Awesome thanks

  • orion
    Posted at 03:54 February 22, 2017
    orion
    Reply
    Author

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

  • Jessie
    Posted at 21:31 February 23, 2017
    Jessie
    Reply
    Author

    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?

    • Maurice Daly
      Posted at 23:34 February 23, 2017
      Maurice Daly
      Reply
      Author

      What happens if you run the contents of the function manually in a PS session on a client?

  • Jessie
    Posted at 04:54 February 24, 2017
    Jessie
    Reply
    Author

    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

    • Maurice Daly
      Posted at 07:22 February 24, 2017
      Maurice Daly
      Reply
      Author

      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.

  • Massimiliano Scopigno
    Posted at 12:13 March 2, 2017
    Massimiliano Scopigno
    Reply
    Author

    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

    • Massimiliano Scopigno
      Posted at 17:14 March 6, 2017
      Massimiliano Scopigno
      Reply
      Author

      This script has worked only client with 8.1 Enterprise , but not with client Seven 32 Bit Enterprise …. anyone can you help me ? where I can try the log on client? thanks at all !!!

  • Martin
    Posted at 16:09 March 16, 2017
    Martin
    Reply
    Author

    Hi Maurice

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

    Regards, Martin

  • Dallan Reilly
    Posted at 18:20 April 15, 2017
    Dallan Reilly
    Reply
    Author

    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.

  • Cody
    Posted at 20:27 April 18, 2017
    Cody
    Reply
    Author

    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.

    • Maurice Daly
      Posted at 00:08 April 19, 2017
      Maurice Daly
      Reply
      Author

      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.

  • Morten
    Posted at 14:27 May 8, 2017
    Morten
    Reply
    Author

    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.

    • Maurice Daly
      Posted at 00:07 May 9, 2017
      Maurice Daly
      Reply
      Author

      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

      • Morten
        Posted at 09:11 May 9, 2017
        Morten
        Reply
        Author

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

  • Dallan Reilly
    Posted at 00:17 May 9, 2017
    Dallan Reilly
    Reply
    Author

    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

    • Maurice Daly
      Posted at 08:58 May 9, 2017
      Maurice Daly
      Reply
      Author

      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

  • Dallan Reilly
    Posted at 09:42 May 9, 2017
    Dallan Reilly
    Reply
    Author

    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.

  • Leave a Reply