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.
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!
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. Thank you!!! Everything works great now.