Get Incremental Collection Evaluation Results in ConfigMgr with PowerShell

Update 04-Mar-16: Added translation of CollectionIDs to CollectionNames

You may be aware that there is a ‘soft limit’ to the number of collections that can use incremental refresh in Configuration Manager 2012 onward, as described in this technet article.  It’s important to check that the time taken for the incremental collection evaluation cycle does not exceed the frequency with which the cycle runs, or the cycle will not complete before the next one begins, meaning some collections will never get incrementally refreshed.

There is a useful tool in the Configuration Manager toolkit called Collection Evaluation Viewer, which can display the evaluation queues in real-time as they run, as well as how long each collection took to evaluate and how many member changes were made.  But the tool does not tell you the total time taken for the evaluation cycle, which can be important to know.

To that end, I prepared a PowerShell script that reads the colleval.log to find various data about the most recent or currently running incremental collection evaluation, including the start and end time, how long the evaluation took to run, the number of collections evaluated, and the list of collections evaluated with the time and duration of each evaluation.

capture

Because the colleval.log is continually in use and will periodically rollover, getting information from the log is inherently dynamic.  Therefore it’s possible that incomplete results may be returned if the log file was rolled over during the most recent evaluation, or if the evaluation is currently processing when the script is run.

The script also has a parameter –TimePeriodInMinutes, which should be set to the same as (or possibly less than) your Collection Membership Evaluation cycle interval (default 5 minutes).  Setting it higher may return misleading results.

The script uses PSRemoting to the primary site server, so should not be run on the site server itself.

 

Finally, the list of collections evaluated is returned as an array, so to read the list save the results to a variable like this:

$Result = Get-IncrementalCollectionEvaluationResults -SiteServer SCCM-01
$Result.'Collections Evaluated List'

Get-IncrementalCollectionEvaluationResults

If you have PowerShell 5, you can download from the PowerShell Gallery:

Install-Script Get-IncrementalCollectionEvaluationResults

Or here’s the script:

 <#
.Synopsis
   Gets statistics for the most recent or currently running Incremental Evaluation Cycle (Express Evaluation) from the colleval.log in Configuration Manager
.NOTES
   Reads the colleval.log on a Configuration Manager Primary Site server to extract data and statistics from the Incremental Collection evaluation cycle.

   Since the log file may contain results from more than one cycle, you should limit the time period in which to search the log file using the -TimePeriodInMinutes parameter.  This should
   be set to the same value (or less) as your Collection Membership Evaluation Cycle interval in Configuration Manager (default 5).

   As this log file is frequently updated and periodically rolled over, it's possible that incomplete results may be returned if the current log file itself does not contain all the log
   entries for the most recent cycle.

   If the cmdlet is run while an incremental evaluation cycle is currently in progress, incomplete results will also be returned until the cycle has finished.

   The cmdlet returns the list of collections evaluated as an array, so save the output to a variable to view them.

   PSRemoting is used so the cmdlet should not be run on the site server itself.
.EXAMPLE
   Get-IncrementalCollectionEvaluation -SiteServer SCCM-01

   Returns statistics for the most recent incremental evaluation cycle on the site server SCCM-01
.EXAMPLE
   Get-IncrementalCollectionEvaluation -SiteServer SCCM-01 -TimePeriodInMInutes 10

   Returns statistics for the most recent incremental evaluation cycle on the site server SCCM-01 with an extended time period
.EXAMPLE
   $Result = Get-IncrementalCollectionEvaluation -SiteServer SCCM-01
   $Result.'Collections Evaluated List'

   Returns the list of collections that were evaluated in the time period with the collection ID, how long the evaluation took and the time of the evaluation.
#>
  
    [CmdletBinding()]
    Param
    (
        # ConfigMgr Primary Site Server name
        [Parameter(Mandatory = $true)]
        [string]$SiteServer,
        
        # Number of minutes past to check the colleval.log
        [Parameter(Mandatory = $false)]
        [int]$TimePeriodInMinutes = 5
    )


###################
# Get the results #
###################

# Set the earliest date/time to return results for
[datetime]$CurrentTime = Get-Date
$EarliestTime = $CurrentTime.AddMinutes(-$TimePeriodInMinutes) | Get-Date

# Open a new PS remoting session to the site server
if ($env:COMPUTERNAME -eq $SiteServer)
    {
        Write-host 'This script uses PSRemoting to the site server and cannot be run on the site server itself.' -ForegroundColor Red
        continue
    }
$s = New-PSSession -ComputerName $SiteServer

# Get the current number of collections in the incremental evaluation graph
[array]$CollectionsFound = Invoke-Command -Session $s -ScriptBlock {
$CollectionsFound = @()
$string = Select-String -Path "$env:SMS_LOG_PATH\colleval.log" -Pattern 'collections in incremental evaluation graph'
$string | ForEach-Object -Process {
    $obj = '' | Select-Object -Property String, Date
    $obj.String = $_.Line.Split('$')[0]
    [datetime]$obj.Date = $_.Line.Split('<')[2] -replace ".{4}$"
    $CollectionsFound += $obj
    }
$CollectionsFound = $CollectionsFound | Where-Object -FilterScript {
$_.date -ge $using:EarliestTime
}
$CollectionsFound
} | Select-Object -Property String, Date

# Get the time the evaluation cycle started
[array]$EvaluationStarted = Invoke-Command -Session $s -ScriptBlock {
$EvaluationStarted = @()
$string = Select-String -Path "$env:SMS_LOG_PATH\colleval.log" -Pattern 'Express Evaluator] Starting'
$string | ForEach-Object -Process {
    $obj = '' | Select-Object -Property String, Date
    $obj.String = $_.Line.Split('$')[0]
    [datetime]$obj.Date = $_.Line.Split('<')[2] -replace ".{4}$"
    $EvaluationStarted += $obj
    }
$EvaluationStarted = $EvaluationStarted | Where-Object -FilterScript {
$_.date -ge $using:EarliestTime
}
$EvaluationStarted
} | Select-Object -Property String, Date

# Get the list of collections that were evaluated
[array]$CollectionEvaluated = Invoke-Command -Session $s -ScriptBlock {
$CollectionEvaluated = @()
$string = Select-String -Path "$env:SMS_LOG_PATH\colleval.log" -Pattern 'Express Evaluator] successfully evaluated collection'
$string | ForEach-Object -Process {
    $obj = '' | Select-Object -Property CollectionID, SecondsToEvaluate, Date
    $obj.CollectionID = $_.Line.Split('$')[0].Split('[')[2].Split(']')[0]
    $obj.SecondsToEvaluate = $_.Line.Split('$')[0].Split()[9]
    [datetime]$obj.Date = $_.Line.Split('<')[2] -replace ".{4}$"
    $CollectionEvaluated += $obj
    }
$CollectionEvaluated = $CollectionEvaluated | Where-Object -FilterScript {
$_.date -ge $using:EarliestTime
}
$CollectionEvaluated
} | Select-Object -Property CollectionID, SecondsToEvaluate, Date

# Get the time the evaluation ended
[array]$EvaluationEnded = Invoke-Command -Session $s -ScriptBlock {
$EvaluationEnded = @()
$string = Select-String -Path "$env:SMS_LOG_PATH\colleval.log" -Pattern 'Express Evaluator] Exiting'
$string | ForEach-Object -Process {
    $obj = '' | Select-Object -Property String, Date
    $obj.String = $_.Line.Split('$')[0]
    [datetime]$obj.Date = $_.Line.Split('<')[2] -replace ".{4}$"
    $EvaluationEnded += $obj
    }
$EvaluationEnded = $EvaluationEnded | Where-Object -FilterScript {
$_.date -ge $using:EarliestTime
}
$EvaluationEnded
} | Select-Object -Property String, Date

# Close the remote session
Remove-PSSession $s


###############################
# Work the results for output #
###############################

# Collection count
if ($CollectionsFound -ne $null)
    {
        $CollectionCount = $CollectionsFound | Where-Object -FilterScript {
$_.String.Split(' ')[1] -gt 0
}
        $CollectionCount = $CollectionCount.String.Split(' ')[1]
    }
Else 
{
$CollectionCount = 'Not found'
}

# Evaluation Start Time
if ($EvaluationStarted -ne $null)
    {
[datetime]$EvaluationStartTime = $EvaluationStarted[0].Date
}

# Evaluation End Time
if ($EvaluationEnded -ne $null)
    {
[datetime]$EvaluationEndTime = $EvaluationEnded[0].Date
}

# Evaluation time taken
if ($EvaluationStartTime -and $EvaluationEndTime)
    {
        $TimeTaken = '' | Select-Object -Property Minutes, Seconds
        $TimeTaken.Minutes = ($EvaluationEndTime - $EvaluationStartTime).Minutes
        $TimeTaken.Seconds = ($EvaluationEndTime - $EvaluationStartTime).Seconds
    }
Else {$TimeTaken = 'N/A'}

# Collections Evaluated
$CollectionsEvaluatedCount = $CollectionEvaluated.Count
$measure = ($CollectionEvaluated.SecondsToEvaluate | Measure-Object -Sum -Average -Maximum -Minimum)
$CollectionsEvaluatedAverage = [math]::Round($measure.Average,2)
$CollectionsEvaluatedSum = [math]::Round(($measure.Sum / 60),2) # minutes
$CollectionsEvaluatedMaximum = [math]::Round($measure.Maximum,2)
$CollectionsEvaluatedMinimum = [math]::Round($measure.Minimum,2)
$NS = (Get-CimInstance -ComputerName $SiteServer -Namespace ROOT\SMS -ClassName __Namespace).Name
$Collections = Get-CimInstance -ComputerName $SiteServer -Namespace ROOT\SMS\$NS -Query "Select Name,CollectionID from SMS_Collection" | Select Name,CollectionID
$CollectionsEvaluatedWN = @()
$CollectionEvaluated | foreach {
    $a = $_
    $obj = '' | Select CollectionName, CollectionID, SecondsToEvaluate, Date
    $obj.CollectionName = $Collections | where {$_.CollectionID -eq $a.CollectionID} | Select -ExpandProperty Name
    $obj.CollectionID = $_.CollectionID
    $obj.SecondsToEvaluate = $_.SecondsToEvaluate
    $obj.Date = $_.Date
    $CollectionsEvaluatedWN += $obj
    }   


# Add the results to custom object
$Result = '' | Select-Object -Property 'Evaluation StartTime', 'Evaluation EndTime', 'Time Taken', `
    'Incremental Collections in graph', `
    'Collections Evaluated', 'Collection Eval TimeTaken (minutes)', 'Collection Eval Average Time (Seconds)', `
    'Longest Collection Eval (seconds)', 'Quickest Collection Eval (seconds)', 'Collections Evaluated List'
if ($EvaluationStarted)
    {
$Result.'Evaluation StartTime' = $EvaluationStartTime
}
Else 
{
$Result.'Evaluation StartTime' = 'Not found'
}
if ($EvaluationEnded)
    {
$Result.'Evaluation EndTime' = $EvaluationEndTime
}
Else 
{
$Result.'Evaluation EndTime' = 'Not found'
}
if ($EvaluationStarted -and $EvaluationEnded)
    {
$Result.'Time Taken' = "$($TimeTaken.Minutes) minutes $($TimeTaken.Seconds) seconds"
}
Else 
{
$Result.'Time Taken' = 'N/A'
}
$Result.'Incremental Collections in graph' = $CollectionCount
$Result.'Collections Evaluated' = $CollectionsEvaluatedCount
$Result.'Collection Eval TimeTaken (minutes)' = $CollectionsEvaluatedSum
$Result.'Collection Eval Average Time (Seconds)' = $CollectionsEvaluatedAverage
$Result.'Longest Collection Eval (seconds)' = $CollectionsEvaluatedMaximum
$Result.'Quickest Collection Eval (seconds)' = $CollectionsEvaluatedMinimum
$Result.'Collections Evaluated List' = $CollectionsEvaluatedWN

# Return the results
return $Result

2 thoughts on “Get Incremental Collection Evaluation Results in ConfigMgr with PowerShell

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.