So earlier this year the great ConfigMgr team released CB1702 and in turn a couple of tools including the Content Library Cleanup Tool. I previously blogged about using the tool (https://msendpointmgr.com/2017/04/03/configmgr-cb-1702-content-library-cleanup-tool/) and the possible storage space savings that could be achieved.
So it occurred to me that this new tool might not be utilised as effectively as it could be when it comes to providing a holistic approach to content maintenance across your ConfigMgr estate, the reason being that command line tools are great but can often be a single use tool that people forget about. So let’s talk about automating this tool..
Automating The Command-Line Tool
So this got me thinking that a PowerShell script which wrapped the functions of the new tool could assist in providing ConfigMgr administrators with an easier means of automating / managing the process. If you are familiar with PowerShell you could of course draft up your own script to make use of the tool in much the same manner that I am going to talk about, but I am catering for those who also are not (yet) comfortable about setting out down this path.
GUI or PS Script – Your Choice
So wanting to cater for both those who prefer a GUI and those who prefer a PS script, here we have the SCConfigMgr Content Cleaner Tool.
Technet Download Link – https://gallery.technet.microsoft.com/scriptcenter/Content-Library-Cleaner-c634da6b
The tool can be used as a GUI to run on demand, or via the schedule job button it schedules a PS script to take care of the maintenance of your distribution points.
On launch it will check the following prerequisites are discovered;
- ConfigMgr PS commandlets
- Content Library Cleanup
Note: It should be used on your site server with an account with full rights to your ConfigMgr environment.
After the prerequisites are met you have two options, you can either analyse all discovered distribution points for left over packages or you can schedule a clean up job to run on a daily basis.
Analyse Job
The analyse job does exactly what is says on the tin, it looks at all of your distribution points within the same site for orphaned packages. Each of the server names and their associated values are read out of the logs and displayed in a data grid view within the GUI. The total potential savings figure provides you with an indication of the savings, of course these might vary due to conditions including data deduplication.
Clean Up Job
After the distribution points have been analysed, you will have the option to click on the “Clean Content Libraries Now” button which launches the delete data process. At this point any distribution points which had been identified as transferring data in the analyse job will be skipped, as will any distribution points with a null saving figure. All remaining distribution points will be processed in sequence.
Schedule Job
To schedule the clean up of distribution points, all we need to do is select a time from the drop down list, select a folder for the script to copy a clean up script into (for the purpose of a scheduled task) and enter credentials which have both log on as a batch service and ConfigMgr full access rights.
The credentials will be validated with Active Directory when setting the schedule and error messages relating to this and the path will be displayed within the form;
Upon providing user authentication being verified, the ContentCleanupRemoval.ps1 script is copied down to the path specified and a scheduled task set up;
The schedule calls the PowerShell script to scan and automatically take care of your orphaned content. Below you have the full script;
<# .NOTES =========================================================================== Created with: SAPIEN Technologies, Inc., PowerShell Studio 2017 v5.4.139 Created on: 05/05/2017 15:11 Created by: Maurice.Daly Filename: ContentCleanupRemoval.ps1 =========================================================================== .DESCRIPTION This script works in conjuction with the content library clean up tool in SCCM CB1702 onwards to automate the function of deleting orphaned content on your distribution ponts Use : This script is provided as it and I accept no responsibility for any issues arising from its use. Twitter : @modaly_it Blog : https://msendpointmgr.com #> function Get-ScriptDirectory { [OutputType([string])] param () if ($null -ne $hostinvocation) { Split-Path $hostinvocation.MyCommand.path } else { Split-Path $script:MyInvocation.MyCommand.Path } } [string]$ScriptDirectory = Get-ScriptDirectory # Logging Function function Write-CMLogEntry { param (
[parameter(Mandatory = $true, HelpMessage = “Value added to the log file.”)]
[ValidateNotNullOrEmpty()] [string]$Value,
[parameter(Mandatory = $true, HelpMessage = “Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.”)]
[ValidateNotNullOrEmpty()] [ValidateSet(“1”, “2”, “3”)] [string]$Severity,
[parameter(Mandatory = $false, HelpMessage = “Name of the log file that the entry will written to.”)]
[ValidateNotNullOrEmpty()] [string]$FileName = “ScheduledContentLibraryCleanup-$(Get-Date -Format dd-MM-yyyy).log” ) # Determine log file location $LogFilePath = Join-Path -Path $ScriptDirectory -ChildPath $FileName # Construct time stamp for log entry $Time = -join @((Get-Date -Format “HH:mm:ss.fff”), “+”, (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) # Construct date for log entry $Date = (Get-Date -Format “MM-dd-yyyy”) # Construct context for log entry $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) # Construct final log entry $LogText = “<![LOG[$($Value)]LOG]!><time=””$($Time)”” date=””$($Date)”” component=””ScheduledContentLibraryCleanup”” context=””$($Context)”” type=””$($Severity)”” thread=””$($PID)”” file=””””>” # Add value to log file try { Add-Content -Value $LogText -LiteralPath $LogFilePath -ErrorAction Stop } catch [System.Exception] { Write-Warning -Message “Unable to append log entry to ScheduledContentLibraryCleanup.log file. Error message: $($_.Exception.Message)” } } # Import SCCM PowerShell Module $ModuleName = (Get-Item $env:SMS_ADMIN_UI_PATH).parent.FullName + “\ConfigurationManager.psd1” Write-CMLogEntry -Value “RUNNING: ConfigMgr PS commandlets path set to $ModuleName” -Severity 1 # Specify SCCM Site Vairables $SiteServer = %SITESERVER% Write-CMLogEntry -Value “RUNNING: Site server identified as $SiteServer” -Severity 1 $SiteCode = %SITECODE% Write-CMLogEntry -Value “RUNNING: SMS site code identified as $SiteCode” -Severity 1 # Define Content Library Path Location $ContentLibraryExe = (“$($env:SMS_LOG_PATH | Split-Path -Parent)” + “\cd.latest\SMSSETUP\TOOLS\ContentLibraryCleanup\ContentLibraryCleanup.exe”) # Define Arrays $DistributionPoints = New-Object -TypeName System.Collections.ArrayList # Import SCCM Module Import-Module $ModuleName # Connect to Site Code PS Drive Set-Location -Path ($SiteCode + “:”) # List Distribution Points $DistributionPoints = @(((Get-CMDistributionPoint | Select-Object NetworkOSPath).NetworkOSPath).TrimStart(“\\”)) # Specify Temp Log Location $LogDir = ($ScriptDirectory + “\ContentLibraryCleanerLogs”) function CleanContent { param (
[parameter(Mandatory = $true)]
[String]$DistributionPoint,
[parameter(Mandatory = $true)]
[String]$SiteServer,
[parameter(Mandatory = $true)]
[String]$SiteCode ) try { Write-CMLogEntry -Value “CLEANING: Setting location to $ScriptDirectory” -Severity 1 Set-Location -Path $ScriptDirectory # Content Library Cleanup switches Write-CMLogEntry -Value “CLEANING: Setting execution switches to $ContentCleanupString” -Severity 1 $ContentCleanupStrings = “/q /ps $SiteServer /dp $DistributionPoint /sc $SiteCode /delete” Write-Host “Running process for $DistributionPoint” Write-CMLogEntry -Value “CLEANING: Starting clean up process for server $DistributionPoint” -Severity 1 $RunningProcess = Start-Process -FilePath $ContentLibraryExe -ArgumentList $ContentCleanupStrings -NoNewWindow -RedirectStandardOutput $($LogDir + “\$DistributionPoint-ScheduledDeletionJob.log”) -PassThru # Wait for Process completion While ((Get-Process | Where-Object { $_.Id -eq $RunningProcess.Id }).Id -ne $null) { Write-CMLogEntry -Value “CLEANING: Waiting for process PID:$($RunningProcess.Id) to finish” -Severity 1 sleep -Seconds 1 } # Get most recent log file generated $ContentCleanUpLog = Get-ChildItem -Path $LogDir -Filter *.log | Where-Object { ($_.Name -match “$DistributionPoint-ScheduledDeletionJob”) } | select -First 1 # Exception for reports with active distributions preventing the content rule from estimating space if ((Get-Content -Path $ContentCleanUpLog.FullName | Where-Object { $_ -match “This content library cannot be cleaned up right now” }) -ne $null) { Write-CMLogEntry -Value “CLEANING: $DistributionPoint currently has active transfers. Skipping.” -Severity 2 $RowData = @($DistributionPoint, “N/A – Active Transfers”) } else { Write-CMLogEntry -Value “CLEANING: Process completed” -Severity 1 } } catch [System.Exception] { Write-CMLogEntry -Value “ERROR: $($_.Exception.Message)” -Severity 3 Write-Warning -Message “ERROR: $($_.Exception.Message)” } Write-CMLogEntry -Value “Finished: Job Complete” -Severity 1 } foreach ($DistributionPoint in $DistributionPoints) { Write-CMLogEntry -Value “RUNNING: Starting clean up process for server $DistributionPoint” -Severity 1 CleanContent $DistributionPoint $SiteServer $SiteCode } # // ————- Clean Up Log Files ———– // # # Define Maximum Log File Age $MaxLogAge = 30 # Remove Logs Write-CMLogEntry -Value “CLEANING: Removing log files older than $MaxLogAge days old” -Severity 2 Get-ChildItem -Path $ScriptDirectory -Filter “ScheduledContentLibrary*.log” -File | Where-Object {$_.LastWriteTime -lt ((Get-Date).AddDays(-$MaxLogAge))} | Remove-Item
Logging
A full verbose log is created during every step of the process, this is located in a “ContentLibraryCleanerLogs” sub-folder of the folder from which you ran the tool. The logs can be viewed using CMTrace and have both warning and error outputs for troubleshooting purposes.
The contentlibrarytool logs are written to the %temp% folder as per the default, however the output from the process is again written into the “ContentLibraryCleanerLogs” sub-folder, however note that all bar the ContentLibraryCleanerTool main log is removed on each subsequent run.
For those scheduling the process, the logs are written into the directory you specified when scheduling the job.
I guess this does not solve the Problem that this tool cannot be used on a Primary site Server with a DP on it?
Is there any clean way to remove unneeded objects from the Content library in this Scenario?
Hi Maurice,
I like this tool, however i was hoping you able to help me find out what change i need to do in the script to use the ContentLibraryCleaner.exe that i have locally saved on each Distribution Point instead of using the site servers location?
We have many DPs with different WLAN link speeds and this will help us to speed up the process.
Thanks
Leon
Hi Leon,
In the scenario you speak about, it would be only a simple matter of adding a scheduled PowerShell script. The script should copy the contentlibrarycleanup tool down to the local DP (if not already available) and then run the tool with the required switches for the local DP. See this post on the manual process – https://msendpointmgr.com/2017/04/03/configmgr-cb-1702-content-library-cleanup-tool/
Regards
Maurice
Hi Maurice,
I like the idea of this tool, but when I start it I stopped after checking of first DP with error message like:
ERROR: Cannot convert value “8.451.030.916” to type “System.Int32”. Error: “Input string was not in a correct format.” ContentLibraryCleanerTool 19.09.2017 15:17:17 6740 (0x1A54)
Can you help me with this issue?
Thx,
Lukas