Deleting records from SCCM and Active Directory

Hello, I am writing a script to achieve the above results, based on a collection I created in SCCM and using a WQL query to narrow it down to any systems that have not had a heartbeat in over 30 days. The part I have yet to figure out is how to easily add sections to remove records from SCCM…I have tried a few methods, to no avail yet. I am pasting my code below with areas that note “REMOVE FROM SCCM” where needed. Please advise if you have any suggestion on how to go about this using my existing code! Thank you.

 

Import-Module ActiveDirectory

#Create file for logging TPOS
$logfile = "C:\temp\SCCMTPOSLog.txt"
$adlogfile = "C:\temp\RemovedfromAD.txt"

#Create variables for SCCM
$SCCMServer = "computer.company.net"
$siteCode = "P60"
$CollectionName = 'ECO - TPOS Older than 30 Days' 

Write-Host "Retrieving register names from SCCM..." 

#Retrieve SCCM collection by name 
$Collection = Get-wmiobject -ComputerName $SCCMServer -NameSpace "ROOT\SMS\site_$SiteCode" -Class SMS_Collection -Filter "Name = '$CollectionName'" 

#Retrieve members of collection 
$registerNames = (Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\site_$SiteCode" -Query "SELECT * FROM SMS_FullCollectionMembership WHERE CollectionID='$($Collection.CollectionID)' order by name").Name 

#Iterate through each of the register names
foreach ($registerName in $registerNames) {

    Write-Host "Processing $registerName"

    #Check if register has a corresponding record in Active Directory
    $tempVar = Get-ADComputer $registerName
            
        if ($tempVar -like "Get-ADComputer : Cannot find an object with identity" ) { 
      
            Write-Host "Computer object NOT FOUND for $registerName"
            #REMOVE FROM SCCM

            }

        else {
                            
            Write-Host "Computer object $registerName exists"

            #Ping register name to see if it is currently on the network
            if (Test-Connection -ComputerName $registerName -Quiet -count 1) {

                Write-Host "$registerName is online"
                Add-Content $logfile "$registerName"

                }

            else {

                Write-Host "$registerName is offline and will be removed from AD and SCCM"
                Remove-ADComputer -Identity "$registerName" -Confirm:$false 
                #REMOVE FROM SCCM
                Add-Content $adlogfile "$registerName removed from Active Directory and SCCM"

                }

        } #else {

} #foreach ($registerName in $registerNames) {


NOTE: I will not have access to the Config Mgr cmdlets on the machine where I will be running this script.

To remove a device in SCCM via wmi you need to get the resource id and then remove it from SMS_R_System

$t =(Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\site_$SiteCode" -Query "SELECT * FROMSMS_CombinedDeviceResources WHERE Name = '$registerName'").ResourceID
Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\Site_$SiteCode" -class SMS_R_System -filter "ResourceID= '$t' "|Remove-WmiObject

Thank you Jonathan - I did see this as an option, but is that something I can simply add in the two places where I need it, within the loop and if/else statements?

for example:

 


[CmdletBinding()]
param (
	[Parameter(Mandatory = $true)]
	[System.String]
	$CommandLineFilePath
)

function Get-SCCMOldTPOS {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true)]
		[System.String]
		$FilePath
	)

        #Create file for logging TPOS
        $logfile = "C:\temp\SCCMTPOSLog.txt"
        $adlogfile = "C:\temp\RemovedfromAD.txt"
        $sccmlogfile = "C:\temp\RemovedfromSCCM.txt"

        #Create variables for SCCM
        $SCCMServer = "computer.company.net"
        $sitename = "P60"

        Write-Verbose "Retrieving register names from text file..."

	    #Retrieve a list of TPOS registers from text file and set to $registerNames
        $registerNames = Get-Content $FilePath 
        
        Write-Verbose "Checking SCCM records against AD..."

        #Iterate through each of the register names
	    foreach ($registerName in $registerNames) {

        Write-Verbose "Processing $registerName"

            #Check if register has a corresponding record in Active Directory
            $tempVar = Get-ADComputer $registerName
            
                if ($tempVar -like "Get-ADComputer : Cannot find an object with identity" ) { 
      
                Write-Host "Computer object NOT FOUND for $registerName"
                $resID = (Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\site_$sitename" -Query "SELECT * FROMSMS_CombinedDeviceResources WHERE Name = '$registerName'").ResourceID 
                Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\Site_$sitename" -class SMS_R_System -filter "ResourceID= '$resID' "|Remove-WmiObject
                Add-Content $sccmlogfile "$registerName removed from SCCM"

                }

                else {
                            
                    Write-Host "Computer object $registerName exists"

                    #Ping register name to see if it is currently on the network
                    if (Test-Connection -ComputerName $registerName -Quiet -count 1) {

                    Write-Host "$registerName is online"
                    Add-Content $logfile "$registerName"

                    }

                        else {

                        Write-Host "$registerName is offline and will be removed from AD and SCCM"
                        Remove-ADComputer -Identity "$registerName" -Confirm:$false 
                        $resID = (Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\site_$sitename" -Query "SELECT * FROMSMS_CombinedDeviceResources WHERE Name = '$registerName'").ResourceID 
                        Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\Site_$sitename" -class SMS_R_System -filter "ResourceID= '$resID' "|Remove-WmiObject
                        Add-Content $adlogfile "$registerName removed from Active Directory and SCCM"

                        }

                } #else {

    } #foreach ($registerName in $registerNames) {

} #function Get-SCCMOldTPOS {

Write-Verbose "Commands completed successfully"  
             
#Run the Get-SCCMOldTPOS function using the text file path that was passed to this script
Get-SCCMOldTPOS -FilePath $CommandLineFilePath -Verbose



You can add it like that or you could create another function that does the delete that is called from your current code.

Thank you Jonathan - I am running into one other issue now:

“Remove-WmiObject : Generic failure”

Any ideas there?

Thanks again, you are a great help. :slight_smile:

My first though would be some type of user access or remoting error via WMI. When I run the command in my lab even with multiple deletes on the same resourceid the remove-wmiobject completes without the error.

That was my thought too - but then wouldn’t my other WMI calls fail as well? Get-WMIObject, etc.

Well the other wmi calls are explicitly specifying the remote computer name and the remove is being passed a object containing it.

Another option is to try this

$resID = (Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\site_$sitename" -Query "SELECT * FROMSMS_CombinedDeviceResources WHERE Name = '$registerName'").ResourceID 
$SCCMClient = Get-WmiObject -ComputerName $SCCMServer -Namespace  "ROOT\SMS\Site_$sitename" -class SMS_R_System -filter "ResourceID= '$resID' "
$SCCMClient.Delete()

Good call! I will try this in the morning when I get back in. You are very kind and thank you for your help! :slight_smile:

Using that method, I get a new error:

Exception calling “Delete” with “0” argument(s): “Generic failure”

Check to be sure that the user running the script has the delete resource for collection assigned in sccm

You are a GENIUS. :slight_smile: Thank you!!! Everything works great now.