MyITGuy
4/17/2025 - 1:02 PM

Delete Aged Discovery Records maintenance task deletes valid Active Directory discovered resources

Issue

The Delete Aged Discovery Records maintenance task deletes active Active Directory Discovery Method resources (user/user group/system).

Effect

  • Any collection that contains an affected non-Direct member resource will be missing the resource until a Full Active Directory discovery is run and the collection is updated.
  • Any collection that contains an affected Direct member resource will be missing the resource and NEVER get that resource back

Symptoms

  • User, User Group and System Active Directory discovered resource counts significantly drop
  • Collection member counts significantly drop
  • Resource IDs change

Cause

The latest agent time (last time a given agent communicated with the management point) is an Active Directory Discovery Method and the interval of that Active Directory Discovery Method is longer than the interval of the Delete Aged Discovery Data maintenance task.

Workaround

Manually run User, User Group and System Full Active Directory Discovery Methods BEFORE the interval of the Delete Aged Discovery Data maintenance task interval.

As a rule, no Active Directory Discovery Method should be less than half the interval of the Delete Aged Discovery Data maintenance task. For example...

  • If the Delete Aged Discovery Data is 5 days, no Active Directory Discovery Method interval should be more than 3 days.
  • If the Delete Aged Discovery Data is 30 days, no Active Directory Discovery Method interval should be more than 15 days.

Scenarios

Delete data that has been inactive for (days)Full discovery polling scheduleRace Condition
57TRUE
53FALSE
3031TRUE
3015FALSE
90200TRUE
9045FALSE

More Information

Configuration Manager can allow for the introduction of a race condition based on the intervals of Active Directory Discovery Methods and the Delete Aged Discovery Data maintenance task.

Active Directory Discovery Method setting for Delta discovery interval (minutes) has no impact on this issue.

The agent time for Active Directory Discovery Methods is updated during the respective Active Directory Discovery Method. When the Delete Aged Discovery Data maintenance task is executed, it checks for agent time earlier than the defined number of days (prior to execution time). When the Active Directory Discovery Method interval is higher than the Delete Aged Discovery Data interval, the days of the gap are impacted. This leads to active resources being deleted because their most recent agent time is for Active Directory Discovery, but is older than the Delete Aged Discovery Data date.

An example scenario:

Delete Aged Discovery Data: 5 days
Active Directory System Discovery: 7 days

A computer exists in Active Directory and the user has powered off their system while they are on vacation for 2 weeks.

During the time the computer is offline, the Active Directory System Discovery continues to run, which keeps the agent time for Active Directory System Discovery updated in the database. Because this is the latest agent time, it is used by the Delete Aged Discovery Data maintenance task.

Once the interval gap has been reached, the Delete Aged Discovery Data maintenance task will delete the resource. Subsequently, the Active Directory System Discovery will run on it's interval, see the object in Active Directory, and create a "new" resource in Configuration Manager.

Validate Affected (PowerShell)

Set-Location -Path "$((Get-CimInstance -ClassName SMS_Authority -Namespace root\ccm).Name.Split(':')[1]):"
$SMS_ScheduleMethods = [wmiclass]"root/sms/site_pr1:SMS_ScheduleMethods"
$DeleteDataThatHasBeenInactiveForDays = Get-CMSiteMaintenanceTask -Name 'Delete Aged Discovery Data' | Select-Object -ExpandProperty DeleteOlderThan
Get-CMDiscoveryMethod | Where-Object ItemName -match '^SMS_AD_' | ForEach-Object {
    $CMDiscoveryMethod = $_
    $Enabled = ($CMDiscoveryMethod.Props | Where-Object { $_.PropertyName -eq 'SETTINGS' -and $_.Value -eq 0 } | Select-Object -ExpandProperty Value1 ) -eq 'ACTIVE'
    $Properties = [ordered]@{
        Name = $CMDiscoveryMethod.ComponentName
        Enabled = $Enabled
        FullDiscoveryPollingSchedule = $null
        DeleteDataThatHasBeenInactiveForDays = $null
        Affected = $null
    }
    if ($Enabled) {
        $StringData = $CMDiscoveryMethod.Props | Where-Object PropertyName -eq 'Full Sync Schedule' | Select-Object -ExpandProperty Value1
        $SMS_ScheduleToken = $SMS_ScheduleMethods.ReadFromString($StringData).TokenData
        $Properties.Affected = $false
        if ($SMS_ScheduleToken) {
            $Properties.FullDiscoveryPollingSchedule = $SMS_ScheduleToken.DaySpan
            $Properties.DeleteDataThatHasBeenInactiveForDays = $DeleteDataThatHasBeenInactiveForDays
            $Properties.Affected = $Properties.DeleteDataThatHasBeenInactiveForDays -le $Properties.FullDiscoveryPollingSchedule
        }

    }
    [pscustomobject]$Properties
} | Format-Table -AutoSize

References

Active users and groups are unexpectedly deleted by the Delete Aged Discovery Data task in Configuration Manager
Active users and groups are unexpectedly deleted by the Delete Aged Discovery Data task in Configuration Manager
The Delete Aged Discovery Data task incorrectly removes active records in Configuration Manager
MEMCM Keep a System Group active without re- Group Discovery
ConfigMgr CB: 'Delete Aged Discovery Data' Internals (with Case Study)

Set-Location -Path "$((Get-CimInstance -ClassName SMS_Authority -Namespace root\ccm).Name.Split(':')[1]):"
$SMS_ScheduleMethods = [wmiclass]"root/sms/site_pr1:SMS_ScheduleMethods"
$DeleteDataThatHasBeenInactiveForDays = Get-CMSiteMaintenanceTask -Name 'Delete Aged Discovery Data' | Select-Object -ExpandProperty DeleteOlderThan
Get-CMDiscoveryMethod | Where-Object ItemName -match '^SMS_AD_' | ForEach-Object {
    $CMDiscoveryMethod = $_
    $Enabled = ($CMDiscoveryMethod.Props | Where-Object { $_.PropertyName -eq 'SETTINGS' -and $_.Value -eq 0 } | Select-Object -ExpandProperty Value1 ) -eq 'ACTIVE'
    $Properties = [ordered]@{
        Name = $CMDiscoveryMethod.ComponentName
        Enabled = $Enabled
        FullDiscoveryPollingSchedule = $null
        DeleteDataThatHasBeenInactiveForDays = $null
        Affected = $null
    }
    if ($Enabled) {
        $StringData = $CMDiscoveryMethod.Props | Where-Object PropertyName -eq 'Full Sync Schedule' | Select-Object -ExpandProperty Value1
        $SMS_ScheduleToken = $SMS_ScheduleMethods.ReadFromString($StringData).TokenData
        $Properties.Affected = $false
        if ($SMS_ScheduleToken) {
            $Properties.FullDiscoveryPollingSchedule = $SMS_ScheduleToken.DaySpan
            $Properties.DeleteDataThatHasBeenInactiveForDays = $DeleteDataThatHasBeenInactiveForDays
            $Properties.Affected = $Properties.DeleteDataThatHasBeenInactiveForDays -le $Properties.FullDiscoveryPollingSchedule
        }
 
    }
    [pscustomobject]$Properties
} | Format-Table -AutoSize
declare @TaskName varchar(100) = 'Delete Aged Discovery Data'
declare @NoOfDaysToRetainConfiguredInTask int = (select DeleteOlderThan from vSMS_SQLTaskStatus where TaskName = @TaskName)
declare @TaskLastStartTime datetime = (select LastStartTime from vSMS_SQLTaskStatus where TaskName = @TaskName)
declare @TaskBeginTime datetime = (select BeginTime from vSMS_SQLTaskStatus where TaskName = @TaskName)
declare @TaskNextStartTime datetime = (DATEADD(dd, DATEDIFF(dd, 0, @TaskLastStartTime), 1) + @TaskBeginTime)
declare @cutoffDate datetime = (DATEADD(dd, - @NoOfDaysToRetainConfiguredInTask, @TaskNextStartTime))

declare @siteRangeStart int = dbo.fnGetSiteRangeStart()
declare @siteRangeEnd int = dbo.fnGetSiteRangeEnd()
declare @isReservedRangedSite int = (select isnull(Value3, 0) from SC_SiteDefinition_Property where SiteNumber = dbo.fnGetSiteNUmber() and Name = N'ReplicatesReservedRanges')

select *
from (
    SELECT
        vrs.Name0
		, vrs.Resource_Domain_OR_Workgr0
		, vad.*
		, [CutoffDate] = @cutoffDate
		, [DeleteOnOrAfter] = DATEADD(dd, @NoOfDaysToRetainConfiguredInTask, DATEADD(dd, DATEDIFF(d, 0, vad.AgentTime), 1))
		, [DaysOverDue] = DATEDIFF(dd, vad.AgentTime, GETDATE())
        , [Rank] = RANK() OVER ( PARTITION BY vad.[ResourceID] ORDER BY vad.[ResourceID], vad.[AgentTime] DESC)
    FROM
		[v_R_System] vrs
		join v_AgentDiscoveries vad on vrs.ResourceID = vad.ResourceId
		join System_DISC sd on vad.ResourceID = sd.ItemKey and sd.Client_Type0 = 1
	WHERE
		((vrs.ResourceID between @siteRangeStart and @siteRangeEnd) or ((vrs.ResourceID between 2063597568 and 2147483647) and @isReservedRangedSite = 1))
) [cte]
WHERE
	1 = 1
	and [Rank] = 1
	and DaysOverDue >= 5
	-- and AgentTime <= @cutoffDate
ORDER BY
    DaysOverDue DESC