I was testing a compliance baseline recently and wanted to verify if the schedule defined in the baseline deployment is actually honored on the client. I set the schedule to run every hour, but it was clear that it did not run every hour and that some randomization was being used.
To review the most recent evaluation times and the next scheduled evaluation time, I had to read the scheduler.log in the CCM\Logs directory, because I could only find a single last evaluation time recorded in WMI.
The following PowerShell script reads which baselines are currently deployed to the local machine, displays a window for you to choose one, then basically reads the Scheduler log to find when the most recent evaluations were and when the next one is scheduled.


############################################################## | |
## ## | |
## Reads the most recent and next scheduled evaluation time ## | |
## for deployed Compliance Baselines from the Scheduler.log ## | |
## ## | |
############################################################## | |
#requires -RunAsAdministrator | |
# Get Baselines from WMI | |
# Excludes co-management policies | |
Try | |
{ | |
$Instances = Get-CimInstance –Namespace ROOT\ccm\dcm –ClassName SMS_DesiredConfiguration –Filter "PolicyType!=1" –OperationTimeoutSec 5 –ErrorAction Stop | Select DisplayName,IsMachineTarget,Name | |
} | |
Catch | |
{ | |
Throw "Couldn't get baseline info from WMI: $_" | |
} | |
If ($Instances.Count -eq 0) | |
{ | |
Throw "No deployed baselines found!" | |
} | |
# Datatable to hold the baselines for the WPF window | |
$DataTable = New-Object System.Data.DataTable | |
[void]$DataTable.Columns.Add("DisplayName") | |
[void]$DataTable.Columns.Add("IsMachineTarget") | |
foreach ($Instance in ($Instances | Sort DisplayName)) | |
{ | |
[void]$DataTable.Rows.Add($Instance.DisplayName,$Instance.IsMachineTarget) | |
} | |
# WPF Window for baseline selection | |
Add-Type –AssemblyName PresentationFramework,PresentationCore,WindowsBase | |
$Window = New-Object System.Windows.Window | |
$Window.WindowStartupLocation = [System.Windows.WindowStartupLocation]::CenterScreen | |
$Window.SizeToContent = [System.Windows.SizeToContent]::WidthAndHeight | |
$window.ResizeMode = [System.Windows.ResizeMode]::NoResize | |
$Window.Title = "DOUBLE-CLICK A BASELINE TO SELECT" | |
$DataGrid = New-Object System.Windows.Controls.DataGrid | |
$DataGrid.ItemsSource = $DataTable.DefaultView | |
$DataGrid.CanUserAddRows = $False | |
$DataGrid.IsReadOnly = $true | |
$DataGrid.SelectionMode = [System.Windows.Controls.DataGridSelectionMode]::Single | |
$DataGrid.Height = "NaN" | |
$DataGrid.MaxHeight = "250" | |
$DataGrid.Width = "NaN" | |
$DataGrid.AlternatingRowBackground = "#e6ffcc" | |
$DataGrid.Add_MouseDoubleClick({ | |
$script:SelectedRow = $This.SelectedValue | |
$Window.Close() | |
}) | |
$Window.AddChild($DataGrid) | |
[void]$Window.ShowDialog() | |
If (!$SelectedRow) | |
{ | |
Throw "No baseline was selected!" | |
} | |
# If the baseline is user-targetted | |
If ($SelectedRow.row.IsMachineTarget -eq $false) | |
{ | |
# Get Logged-on user SID | |
$LogonUIRegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI" | |
#Could also use this: | |
#Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\SMS\CurrentUser -Name UserSID -ErrorAction Stop | |
$Property = "LastLoggedOnUserSID" | |
$LastLoggedOnUserSID = Get-ItemProperty –Path $LogonUIRegPath –Name $Property | Select –ExpandProperty $Property | |
$LastLoggedOnUserSIDUnderscore = $LastLoggedOnUserSID.Replace('–','_') | |
$Namespace = "ROOT\ccm\Policy\$LastLoggedOnUserSIDUnderscore\ActualConfig" | |
} | |
Else | |
{ | |
$Namespace = "ROOT\ccm\Policy\Machine\ActualConfig" | |
} | |
# Get assignment info | |
$BaselineName = $SelectedRow.Row.DisplayName | |
$Pattern = [Regex]::Escape($BaselineName) | |
$CIAssignment = Get-CimInstance –Namespace $Namespace –ClassName CCM_DCMCIAssignment | where {$_.AssignmentName -match $Pattern} | |
$AssignmentIDs = $CIAssignment | Select AssignmentID,AssignmentName | |
Write-host "Baseline: $BaselineName" –ForegroundColor Magenta | |
foreach ($AssignmentID in $AssignmentIDs) | |
{ | |
# Read the scheduler log | |
$Log = "$env:SystemRoot\CCM\Logs\Scheduler.log" | |
If ($SelectedRow.row.IsMachineTarget -eq $false) | |
{ | |
$LogEntries = Select-String –Path $Log –SimpleMatch "$LastLoggedOnUserSID/$($AssignmentID.AssignmentID)" | |
} | |
Else | |
{ | |
$LogEntries = Select-String –Path $Log –SimpleMatch "Machine/$($AssignmentID.AssignmentID)" | |
} | |
If ($LogEntries) | |
{ | |
# Get the previous evaluations date/time | |
$Evaluations = New-Object System.Collections.ArrayList | |
$EvaluationEntries = $LogEntries | where {$_ -match "SMSTrigger"} | |
Foreach ($Entry in $EvaluationEntries) | |
{ | |
$Time = $Entry.Line.Split('=')[1] | |
$Date = $Entry.Line.Split('=')[2] | |
$a = $Time.Split()[0].trimend().replace('"','') | |
$b = $Date.Split()[0].trimend().replace('"','').replace('–','/') | |
$Time = (Get-Date $a).ToLongTimeString() | |
$Date = [DateTime]"$b $Time" | |
$LocalDate = Get-Date $date –Format (Get-Culture).DateTimeFormat.RFC1123Pattern | |
[void]$Evaluations.Add($LocalDate) | |
} | |
# Get the next scheduled evaluation date/time | |
$LastEvaluation = $EvaluationEntries | Select –Last 1 | |
$date = $LastEvaluation.Line.Split()[8] | |
$time = $LastEvaluation.Line.Split()[9] | |
$ampm = $LastEvaluation.Line.Split()[10] | |
$NextEvaluation = [DateTime]"$date $time $ampm" | |
$NextEvaluationLocal = Get-Date $NextEvaluation –Format (Get-Culture).DateTimeFormat.RFC1123Pattern | |
# Return the results | |
Write-Host "Assignment: $($AssignmentID.AssignmentName)" –ForegroundColor Green | |
Write-host "Last Evaluations:" | |
foreach ($Evaluation in $Evaluations) | |
{ | |
Write-host " $Evaluation" –ForegroundColor Yellow | |
} | |
Write-host "Next Scheduled Evaluation:" | |
Write-Host " $NextEvaluationLocal" –ForegroundColor Yellow | |
} | |
Else | |
{ | |
Write-Host "No log entries found!" –ForegroundColor Red | |
} | |
} |