ConfigMgr

VMware, Azure and Automation

SCCM – Duplicate Device Records

6 juni 2017 ConfigMgr Powershell SCCM Script

A few days back I was investigating duplicate device records in SCCM. Basically, there are two major reasons for duplicate device records:

  1. Reinstalling a device
  2. Active Directory delta discovery

For the first reason SCCM has some built-in solutions. In the Hierarchy Settings there’s an option for conflicting client records. This option looks at the hardware ID’s to detect duplicates and gives you the option to automatically resolve the conflict or to do it manually.

There’s an old Microsoft article that describes how SCCM (SMS) handles duplicate ID’s and how you can find them.

If you look at the image you can see that in my test environment the option to manually resolve conflicts is selected. One way of resolving the conflicts manually is to create a Status Filter Rule.

Event 2642:

Configuration Manager has detected a record that might be conflicting with the following client record in the site database: <GUID> . Possible cause: <GUID> has been imaged, recovered from backup, or migrated to a new computer. Solution: In the Configuration Manager console, under Computer Management, in the Conflicting Records node, right click <GUID> and then choose one of the following options: Merge to match the conflicting record with the existing record, New to create a new client record, or Block to block this record from being a client.

BTW the location in SCCM 1702 is Monitoring, System Status, Conflicting Records node.

MergeConflictingRecords.ps1

[code language=”powershell”]
####################################################################################
# #
# Configuration #
# #
####################################################################################

# SCCM Servername
Set-Variable serverName "servername" -Option Constant

# test = $true: shows information about conflicting records without merging them.
# test = $false: shows information about conflicting records and merges them.
Set-Variable test $false -Option Constant

####################################################################################
# #
# Functions #
# #
####################################################################################

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

function Log
{
param
(
[Parameter(Mandatory=$true)]
[String]
$message
,
[Parameter(Mandatory=$true)]
[ValidateSet("Info","Debug","Warn","Error")]
[String]
$type
,
[Parameter(Mandatory=$true)]
[ValidateSet("Console","LogFile","Both")]
[String]
$outputMode
)

$dateTimeString = Get-Date -Format "yyyy-MM-dd HH:mm:sszz"
$output = ($dateTimeString + "`t" + $type.ToUpper() + "`t" + $message)

if ($outputMode -eq "Console" -OR $outputMode -eq "Both")
{
Write-Host $output
}

if ($outputMode -eq "LogFile" -OR $outputMode -eq "Both")
{
try
{
Add-Content $logFile -Value $output -ErrorAction Stop
}
catch
{
Log ("Failed to write to log file: """ + $logFile + """.") -OutputMode Console -Type Error
Log ("[" + $_.Exception.GetType().FullName + "] " + $_.Exception.Message) -OutputMode Console -Type Error
}
}
}

function GetSCCMSiteCode
{
try
{
$sccmProvider = Get-WMIObject -ComputerName $serverName -Namespace "root\SMS" -Class "SMS_ProviderLocation"
$sccmProvider | foreach-object{if ($_.ProviderForLocalSite -eq $true){$siteCode=$_.sitecode}}
}
catch
{
Log ("[" + $_.Exception.GetType().FullName + "] " + $_.Exception.Message) -OutputMode Both -Type Error
exit 1
}

if (!$siteCode)
{
Log ("Failed to determine site code.") -OutputMode Both -Type Error
exit 1
}

return $siteCode
}

function MergeRecords
{
param
(
[Parameter(Mandatory=$true)]
[String]
$SMSID
)

$pendingRegClass = [WmiClass]("\\$serverName\ROOT\SMS\Site_" + $sccmSiteCode + ":SMS_PendingRegistrationRecord")

$inParams = $pendingRegClass.PSBase.GetMethodParameters("ResolvePendingRegistrationRecord")
$inParams.SMSID = $SMSID
$inParams.Action = 1 # Action 1 = Merge

Log ("Merging records…") -OutputMode Both -Type Info

try
{
$result = $pendingRegClass.PSBase.InvokeMethod("ResolvePendingRegistrationRecord", $inParams, $Null)
if ($result["returnValue"] -eq "0")
{
Log ("Successfully merged records. Return value: " + $result["returnValue"]) -OutputMode Both -Type Info
}
else
{
Log ("Failed to merge records! Return value: " + $result["returnValue"]) -OutputMode Both -Type Error
}
}
catch
{
Log ("Failed to merge records!") -OutputMode Both -Type Error
Log ("[" + $_.Exception.GetType().FullName + "] " + $_.Exception.Message) -OutputMode Both -Type Error
}
}

####################################################################################
# #
# Main Code #
# #
####################################################################################

# Logfile
Set-Variable logFile ((Get-ScriptDirectory) + "\MergeConflictingRecords.log") -Option Constant -ErrorAction SilentlyContinue

# Determine SCCM Site Code
Set-Variable sccmSiteCode (GetSCCMSiteCode) -Option Constant -ErrorAction SilentlyContinue

# Get conflicting records
$pendingRegistrations = Get-WmiObject -class "SMS_PendingRegistrationRecord" -namespace ("root\sms\site_" + $sccmSiteCode) -impersonation 3 -computername $serverName

# Merge conflicting records
if ($pendingRegistrations)
{
Log ("Found conflicting records.") -OutputMode Both -Type Info

foreach ($item in $pendingRegistrations)
{
Log ("**************************************************************************************************************************************") -OutputMode Both -Type Info

Log ("NetBIOS Name: " + $item.NetBiosName) -OutputMode Both -Type Info
Log ("SMSID: " + $item.SMSID) -OutputMode Both -Type Info
Log ("Conflicting SMSID: " + $item.ConflictSMSID) -OutputMode Both -Type Info
Log ("Hardware ID: " + $item.HardwareID) -OutputMode Both -Type Info

if (!$test)
{
MergeRecords -SMSID $item.SMSID
}

Log ("**************************************************************************************************************************************") -OutputMode Both -Type Info
}
}
else
{
Log ("No conflicting records found.") -OutputMode Both -Type Info
}
[/code]

However, for the second reason there is no built-in solution. So I had to create one.

The first step was getting some background information about the issue. There’s a Microsoft article about the issue.

As you can see the article is old (2011) and it’s not using powershell. So I rewrote the script from VB to powershell. One other change is that the VB script kicks of a full AD discovery but I will use the regular scheduled delta discovery method. For this to work the AD object must be changed. I found one blog that uses the same approach but uses an EXE file for this.  I decided to incorporate this into the powershell script.

DeleteDuplicateRecords.ps1

[code language=”powershell”]
<# .SYNOPSIS Deletes duplicate device records .DESCRIPTION Use this script if you need to delete duplicate device records because of a timing issue between OSD and AD delta discovery .PARAMETER SiteServer Site server name with SMS Provider installed .PARAMETER MachineName Name of the duplicate device .EXAMPLE .\DeleteDuplicateRecords.ps1 -SiteServer "SERVER" -MachineName "MACHINE" Deletes duplicate records of the device with the name "MACHINE" .NOTES Script name: DeleteDuplicateRecords.ps1 Author: Jeroen Buren DateCreated: 02-06-2017 #>

[CmdletBinding(SupportsShouldProcess=$true)]

param(
[parameter(Mandatory=$true,HelpMessage="Site server where the SMS Provider is installed")]
[ValidateScript({Test-Connection -ComputerName $_ -Count 1 -Quiet})]
[string]$SiteServer,
[parameter(Mandatory=$true,HelpMessage="Name of the device")]
[string]$MachineName
)

####################################################################################
# #
# Functions #
# #
####################################################################################

function Get-ScriptDirectory {
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

function Log {
param
(
[Parameter(Mandatory=$true)]
[String]
$message
,
[Parameter(Mandatory=$true)]
[ValidateSet("Info","Debug","Warn","Error")]
[String]
$type
,
[Parameter(Mandatory=$true)]
[ValidateSet("Console","LogFile","Both")]
[String]
$outputMode
)

$dateTimeString = Get-Date -Format "yyyy-MM-dd HH:mm:sszz"
$output = ($dateTimeString + " " + $type.ToUpper() + " " + $message)

if ($outputMode -eq "Console" -OR $outputMode -eq "Both")
{
Write-Host $output
}

if ($outputMode -eq "LogFile" -OR $outputMode -eq "Both")
{
try
{
Add-Content $logFile -Value $output -ErrorAction Stop
}
catch
{
Log ("Failed to write to log file: """ + $logFile + """.") -OutputMode Console -Type Error
Log ("[" + $_.Exception.GetType().FullName + "] " + $_.Exception.Message) -OutputMode Console -Type Error
}
}
}

function GetSCCMSiteCode {
try
{
$sccmProvider = Get-WMIObject -ComputerName $SiteServer -Namespace "root\SMS" -Class "SMS_ProviderLocation"
$sccmProvider | foreach-object{if ($_.ProviderForLocalSite -eq $true){$siteCode=$_.sitecode}}
}
catch
{
Log ("[" + $_.Exception.GetType().FullName + "] " + $_.Exception.Message) -OutputMode Both -Type Error
exit 1
}

if (!$siteCode)
{
Log ("Failed to determine site code.") -OutputMode Both -Type Error
exit 1
}

return $siteCode
}

####################################################################################
# #
# Main Code #
# #
####################################################################################

# Logfile
Set-Variable logFile ((Get-ScriptDirectory) + "\DeleteDuplicateRecords.log") -Option Constant -ErrorAction SilentlyContinue

# Determine SCCM Site Code
Set-Variable sccmSiteCode (GetSCCMSiteCode) -Option Constant -ErrorAction SilentlyContinue

# If you give the computer a new machine name, you need to query for the new machine name
$StatusMessageQuery = "select RecordID from SMS_StatMsg where MessageID = 11171 and MachineName = ‘" + $MachineName + "’ order by RecordID desc"
$StatusMessages = gwmi -Query $StatusMessageQuery -Namespace ("root\sms\site_" + $sccmSiteCode) -ComputerName $SiteServer

If ($StatusMessages.Count -lt 1) {
Log ("No Status Message with ID = 11171 and MachineName = $MachineName found. Exiting…") -OutputMode LogFile -Type Info
#Exit
}
Else {
$RecordID = $StatusMessages[0].RecordID
Log ("Status Message RecordID = $RecordID") -outputMode LogFile -type Info
$StatusMessageAttributeQuery = "select AttributeValue from SMS_StatMsgAttributes where RecordID = ‘" + $RecordID + "’ and AttributeID = 408"
$StatusMessageAttributes = gwmi -Query $StatusMessageAttributeQuery -Namespace ("root\sms\site_" + $sccmSiteCode) -ComputerName $SiteServer
If ($StatusMessageAttributes.Count -lt 1) {
Log ("No Status Message Attribute with AttributeID = 408 and RecordID = $RecordID found. Exiting…") -outputMode LogFile -type Info
}
Else {
$GUID = $StatusMessageAttributes[0].AttributeValue
Log ("SMS Client GUID = $GUID") -outputMode LogFile -type Info
$MachineNameQuery = "select NetbiosName from SMS_R_System where SMSUniqueIdentifier = ‘" + $GUID + "’"
$MachineNames = gwmi -Query $MachineNameQuery -Namespace ("root\sms\site_" + $sccmSiteCode) -ComputerName $SiteServer
If ($MachineNames.Count -lt 1) {
Log ("No Systems with SMSGUID = $GUID found. Using the Machine Name in the status message.") -outputMode LogFile -type Info
}
Else {
$MachineName = $MachineNames[0].NetbiosName
Log ("New MachineName = $MachineName" ) -outputMode LogFile -type Info
}
}
}

# Find the system with the specific machine name.

$duplicateRecordsQuery = "select * from SMS_R_System where NetBIOSName = ‘" + $MachineName + "’"
$duplicateRecords = gwmi -Query $duplicateRecordsQuery -Namespace ("root\sms\site_" + $sccmSiteCode) -ComputerName $SiteServer

If ($duplicateRecords.Count -lt 1) {
Log ("Didn’t find a duplicate record for the machine, exiting…") -outputMode LogFile -type Info
}
Else {
# Delete if the Client, Client Type, Hardware ID, SMBIOSGUID, SMSUniqueIdentifier is null
Foreach ($item in $duplicateRecords) {
$Active = $item.Active
$Client = $item.Client
$ClientType = $item.ClientType
$HardwareID = $item.HardwareID
$ResourceId = $item.ResourceId
$SMBIOSGUID = $item.SMBIOSGUID
$SMSUniqueIdentifier = $item.SMSUniqueIdentifier
If (($Active -eq $null) -and ($Client -eq $null) -and ($ClientType -eq $null) -and ($HardwareID -eq $null) -and ($SMBIOSGUID -eq $null) -and ($SMSUniqueIdentifier -eq $null)) {
Log ("Delete this one: ResourceId = $ResourceId") -outputMode LogFile -type Info
# Delete Record when there’s duplicate and it’s active/SMBIOSGUID, etc is null
$item.Delete()
Log ("Deleted item: ResourceId = $ResourceId") -outputMode LogFile -type Info
}
}
}

# Modify AD computer object so delta discovery will pick this up.
Get-ADComputer -Identity $MachineName | Set-ADComputer -Replace @{adminDescription="Touched by SCCM – $dateTimeString"}
[/code]

clientDuplicatesccmSystem Center

Powershell - Get SCCM Client info from WMI

Frequent, continuous releases coming for System Center

Recent Posts

  • Using API for Aria OPS Chargeback
  • Unable to set reservation on Org VDC
  • Veeam Tweaks
  • VCF Anyone? Get your license for free…
  • Configure Entra ID as Cloud Director IdP

Recent Comments

Geen reacties om te tonen.

Archives

  • april 2025
  • maart 2025
  • november 2024
  • oktober 2024
  • januari 2024
  • november 2023
  • oktober 2023
  • september 2023
  • juni 2023
  • mei 2023
  • april 2023
  • november 2022
  • maart 2021
  • februari 2021
  • januari 2021
  • november 2020
  • oktober 2020
  • september 2020
  • juli 2020
  • juni 2020
  • april 2020
  • maart 2020
  • februari 2020
  • oktober 2019
  • september 2019
  • juli 2019
  • juni 2019
  • mei 2019
  • maart 2019
  • februari 2019
  • januari 2019
  • december 2018
  • november 2018
  • april 2018
  • januari 2018
  • juli 2017
  • juni 2017
  • mei 2017

Categories

  • AnyLinq
  • Azure
  • Cloud Director
  • ConfigMgr
  • DIY
  • HomeAssistant
  • Microsoft
  • PowerCli
  • Powershell
  • SCCM
  • Script
  • Solutions
  • System Center
  • Veeam
  • VMware
  • vRealize Automation
  • vRealize Orchestrator
Proudly powered by WordPress | Theme: Doo by ThemeVS.