Updated 2018.05.31 to include script to Remove all software Updates from Nomad Cache.
Updated 2018.01.29 to include script to clean Nomad based on Content ID.
The CCMCache is pretty good at taking care of itself, but perhaps you have a reason to delete something specific, how do you do that in a supported way?
I have two scripts below, one that will just blow away ALL Software Updates in the cache, thoughts behind this, software updates should be installed within a couple weeks of being cached, after that, they are useless and never needed again, the other reason, if I’m upgrading to a new Windows 10 Build, I don’t need any of those old Windows 10 Software Updates in my cache anymore. (yes, you probably have others in there from office, etc, but hopefully you’ve installed them already, I admit, this isn’t for everyone) Script Name:
Remove-CCMCacheSoftwareUpdateContent.ps1Script 2, delete specific items based on ContentID. This is more for when you have a package / app you just want gone, perhaps you’re never going to deploy it again, or perhaps, someone accidently put a domain admin username & password in the script that’s now in the package sitting on all of our workstation ccmcache’s. Instead of dumping the entire cache, you can target a specific content and delete it. I also use this for deleting the Windows 10 Upgrade Media from the CCMCache after the upgrade. Normally you wouldn’t need to clean up after your task sequence, but if you precache your payloads into the ccmcache to speed up your actual deployment, then you’ll have that package contents just taking up space. Script Name:
Remove-CCMCacheContent.ps1
Flipside, Reasons to just leave it alone… once you fill up your CCMCache, it’s YOURS! You own that 20GB or whatever your CCMCache size is. No one can take that space away from you again. If you clear it out, sure, your machine might have more available free space, then the user steals it with cat videos, and guess what, when you need to cache that Adobe Software install, you can’t, not enough storage on the machine, if you would have just left the cache full, it would have cleared out what it needed at the time of the request, and pulled down the installer content.
How am I using them?
I have a script that will dump all of the Software Updates in the Cache, I use it in my Upgrade TS if after several other remediation’s, still don’t have 20GB free space to start the Build upgrade.
The other one, I have it clean up a couple packages at the end of the TS that are in the CCMCache from the PreCache TS:
Script is set to create a log in c:\windows\temp\ you can modify this to whatever you like.
Remove-CCMCacheSoftwareUpdateContent.ps1
<# .SYNOPSIS Delete Specified Item(s) From CCM Cache .DESCRIPTION Uses ContentIDs to identify (ALL SOFTWARE UPDATES) and purge content from the local ccm cache - Created by Gary Blok @gwblok Partial Code borrowed from: https://gallery.technet.microsoft.com/scriptcenter/Deleting-the-SCCM-Cache-da03e4c7 Assist by Keith S. Garner @keithga1 .LINK https://garytown.com #> $Logfile = "c:\windows\temp\Remove-CCMCacheContent.log" # Connect to resource manager COM object $CMObject = New-Object -ComObject 'UIResource.UIResourceMgr' # Using GetCacheInfo method to return cache properties $CMCacheObjects = $CMObject.GetCacheInfo() # Delete Cache item $CMCacheObjects.GetCacheElements() | Where-Object { $_.ContentID | Select-String -Pattern '^[\dA-F]{8}-(?:[\dA-F]{4}-){3}[\dA-F]{12}$' } | ForEach-Object { $CMCacheObjects.DeleteCacheElement($_.CacheElementID) Add-Content $Logfile -value "Deleted: Name: $($_.ContentID) Version: $($_.ContentVersion)" Write-Host "Deleted: Name: $($_.ContentID) Version: $($_.ContentVersion)" -BackgroundColor Red }
Remove-CCMCacheContent.ps1
<# .SYNOPSIS Delete Specified Item(s) From CCM Cache .DESCRIPTION Uses ContentIDs to identify and purge content from the local ccm cache - Created by Gary Blok @gwblok Partial Code borrowed from: https://gallery.technet.microsoft.com/scriptcenter/Deleting-the-SCCM-Cache-da03e4c7 Assist by Mark Godfrey @Geodesicz .PARAMETER CachItemsToDelete Comma separated values for the Content ID(s) of the cach item(s) to delete .EXAMPLE .\Remove-CCMCacheContent.ps1 -CacheItemsToDelete "PS100123","20eb8ec8-0b7e-4831-a5ae-95680b11e6b5","PS111197" .LINK https://garytown.com #> [CmdletBinding()] Param( [Parameter(Mandatory=$true,Position=1,HelpMessage="ContentIDs")] [ValidateNotNullOrEmpty()] [String[]]$CacheItemsToDelete ) #$CacheItemsToDelete = "PS100002","20eb8ec8-0b7e-4831-a5ae-95680b11e6b5","decbb5fe-1cbc-4984-bbf2-e76347150135" $Logfile = "c:\windows\temp\Remove-CCMCacheContent.log" # Connect to resource manager COM object $CMObject = New-Object -ComObject 'UIResource.UIResourceMgr' # Using GetCacheInfo method to return cache properties $CMCacheObjects = $CMObject.GetCacheInfo() # Delete Cache item $CMCacheObjects.GetCacheElements() | Where-Object {$_.ContentID -in $CacheItemsToDelete} | ForEach-Object { #$CMCacheObjects.DeleteCacheElement($_.CacheElementID) Add-Content $Logfile -value "Deleted: Name: $($_.ContentID) Version: $($_.ContentVersion)" Write-Host "Deleted: Name: $($_.ContentID) Version: $($_.ContentVersion)" -BackgroundColor Red }
Added 2018.01.29 – Remove-NomadCacheContent.ps1 (works the same as Remove-CCMCacheContent.ps1)
[CmdletBinding()] Param( [Parameter(Mandatory=$true,Position=1,HelpMessage="ContentIDs")] [ValidateNotNullOrEmpty()] [String[]]$CacheItemsToDelete ) ForEach ($CacheItemsToDelete in $CacheItemsToDelete) { $pkgver = (Get-ItemPropertyValue "HKLM:\SOFTWARE\1E\NomadBranch\PkgStatus\$CacheItemsToDelete" 'version') cmd.exe /c "CacheCleaner.exe -deletepkg=$CacheItemsToDelete -pkgver=$pkgver" }
Added 2018.01.29 – Remove-NomadCacheSoftwareUpdateContent.ps1 (works the same as Remove-CCMCacheSoftwareUpdateContent.ps1)
$NomadCachePath = get-itempropertyvalue -path 'HKLM:\Software\1E\NomadBranch' -name 'LocalCachePath' | Write-Output $NomadInstallPath = get-itempropertyvalue -path 'HKLM:\Software\1E\NomadBranch' -name 'InstallationDirectory' | Write-Output $Folder = '*_cache' $TotalNomadDiskSize = get-childitem (join-path ($NomadCachePath) $Folder) -recurse -ErrorAction SilentlyContinue | measure-object -Sum length | % sum | write-output $exclude = @("ContentDeliveryGUID","ReturnStatus","ElapsedSeconds","BackOffSeconds") $NomadPackages = foreach ( $Pkg in get-childitem HKLM:\software\1e\NomadBranch\PkgStatus ) { $pkg | Get-ItemProperty | Select-Object -Property *,@{ Name = 'ActualSize'; expression = { Get-TotalNomadDiskSize -folder "$($_.PSChildName)_Cache" } } -ExcludeProperty $exclude } $SoftwareUpdates = $NomadPackages | where-object { $_.PSChildName | Select-String -Pattern '^[\dA-F]{8}-(?:[\dA-F]{4}-){3}[\dA-F]{12}$' } | write-output Write-Host "Before Deleting Updates Nomad Cache size: $TotalNomadDiskSize" -ForegroundColor Green ForEach ($SoftwareUpdates in $SoftwareUpdates) { $SoftwareUpdatesContentLocation = ($SoftwareUpdates).PSChildName $SoftwareUpdatesContentVersion = ($SoftwareUpdates).Version Write-Host "Deleting: $SoftwareUpdatesContentLocation version: $SoftwareUpdatesContentVersion" -ForegroundColor Green cmd.exe /c """$NomadInstallPath\CacheCleaner.exe"" -deletepkg=$SoftwareUpdatesContentLocation -pkgver=$SoftwareUpdatesContentVersion" Write-Host "Deleted: $SoftwareUpdatesContentLocation version: $SoftwareUpdatesContentVersion" -ForegroundColor Yellow } $TotalNomadDiskSize = get-childitem (join-path ($NomadCachePath) $Folder) -recurse -ErrorAction SilentlyContinue | measure-object -Sum length | % sum | write-output Write-Host "Current Nomad Cache size: $TotalNomadDiskSize" -ForegroundColor Green
In Action:
as you can see, it deletes every version of the content id. AKA, if the client cached version 1 of the package, then you updated the package with a new file, the client could then download version 2 of the same package. Running this script will dump every version of that same package.
Nomad Cleanup In Action (if you pick a package that isn’t on the machine, it gives the errors about not finding it, and continues on)
Feel free to use them however you want, I just tend to live in the Task Sequence world now, so that’s how I use them.
Thanks to Mark Godfrey, Keith Garner & the PS Gallery, see actual scripts for more details.
Nice work and useful.
You might also want to look into removing the old version of Windows. This is achieved via Disk CleanUp. The Disk CleanUp utility in storage spaces was updated in 1709 and should further advance in 1803.
@gwblok is there away to tweak your Remove-NomadCacheContent.ps1 script so that it can delete just Microsoft Updates instead of deleting everything in the nomad cache? Thanks!
Done, PLEASE TEST before you deploy, I whipped this together pretty quick (updated in above post), stealing a little code from Keith Garner. 🙂
A much MUCH nicer version will be blogged by Keith Garner or Mike Terrill when they have time.
Seems like Get-ItemPropertyValue only works in PS 5.1 or above. I’m using 4.0.
Ok I think I have fixed the first part.
$((get-itemproperty -path “Registry::HKEY_LOCAL_MACHINE\Software\1E\NomadBranch”).LocalCachePath)
Still reaching your Select-String -Pattern. I don’t think the pattern is correct for my environment.
Here is an example. b4dd4aaf-ad1f-4eb8-856c-210c782f86cc_Cache
This seemed to work better for me. Tell me what you think? Thanks 🙂
$NomadCachePath = $((get-itemproperty -path “Registry::HKEY_LOCAL_MACHINE\Software\1E\NomadBranch”).LocalCachePath) | Write-Output
#Write-Host “Nomad Cache Directory is $NomadCachePath”
$NomadInstallPath = $((get-itemproperty -path “Registry::HKEY_LOCAL_MACHINE\Software\1E\NomadBranch”).InstallationDirectory) | Write-Output
#Write-Host “Nomad Install Directory is $NomadInstallPath”
$SoftwareUpdates = gci “HKLM:\SOFTWARE\1E\NomadBranch\PkgStatus” | where-object { $_.PSChildName | Select-String -Pattern ‘^[\dA-F]{8}-(?:[\dA-F]{4}-){3}[\dA-F]{12}$’} | write-output
ForEach ($SoftwareUpdates in $SoftwareUpdates){
#Write-Host $SoftwareUpdates
$SoftwareUpdatesContentLocation = ($SoftwareUpdates).PSChildName
$SoftwareUpdatesContentVersion = $SoftwareUpdates.getvalue(“Version”)
$SoftwareUpdatesDate = $SoftwareUpdates.getvalue(“FinishTimeUTC”)
$SoftwareUpdatesDate = $SoftwareUpdatesDate.Substring(0,$SoftwareUpdatesDate.Length-9)
If($SoftwareUpdatesDate -le ‘20180430’)
{
Write-Host “Deleting: $SoftwareUpdatesContentLocation version: $SoftwareUpdatesContentVersion” -ForegroundColor Green
cmd.exe /c “””$NomadInstallPath\CacheCleaner.exe”” -deletepkg=$SoftwareUpdatesContentLocation -pkgver=$SoftwareUpdatesContentVersion”
Write-Host “Deleted: $SoftwareUpdatesContentLocation version: $SoftwareUpdatesContentVersion” -ForegroundColor Yellow
}
}
For Nomad Cache, I would not use this and just use the Nomad Cache Clean Cycle that comes with Nomad 6.3.
Actually the cache clean cycle that is in 6.3 is very primitive. I tried to get them to take cache management seriously when I was there but they had more important priorities (i.e. tachyon). We ended up implementing my vision for cache management that is pretty sophisticated in terms of purging items based on type (something else I tried to get them to do is tag the type of content). This way you can control things based on how long it should be kept vs. doing a rather ‘dumb’ FIFO method.
I use this really simple matching method for updates
If($PackageID -match “……..-….-….-……..” -or $PackageID -match “Content_……..-….-….-……..”)
Stupid question – but in your actual Cache delete up there for sccm isn’t the actual deleting part commented out?
Yes, I had it commented out to just see what was going to happen before I enabled it.
Sorry I didn’t better explain that.
cacheCleaner.exe is not purging/deleting content from CCM cache for every package even when I specify the correct -pkgver in the command. I’ve verified the pkgver in Nomad registry location, Nomad cache .LsZ file, and CCM cache.
Anyone come across this before?
We’re no longer using Nomad, we’ve moved to Branch Cache & LEDBAT++. I’d recommend reaching out to their support.