How to delete an SMS client throughout your hierarchy
Remember delmif.exe in SMS 1.2? It was a nice utility used to delete machines throughout your entire hierarchy. In SMS 2003 resource deletions do not flow from child sites up the hierarchy.
In SMS 2003 SP2 some improvements have been made to deal with this. Decommissioned DDRs now get created and sent to the parent site when a deletion occurs. This is not enabled by default.
To enable this feature, set the following registry value:
HKLM\Software\Microsoft\SMS\Components...
...\SMS_Discovery_Data_Manager:DecommissionNotification
to a value of 1.
You typically only want to use this feature on sites that require it (lower tier sites, only one per hierarchy branch recommended). When the parent site processes the decommissioned DDR the Decommissioned property in SMS_R_System class (System_DISC table) gets set from 0 to 1. You can then query and base collections on this property.
So what if this feature doesn't meet your needs or you don't have SP2? Well, you can manually delete the resources from each site in your hierarchy or run a script like the one attached against your central site and have it delete the resources in your hierarchy.
-Russ
'Script Name: DelClient.vbs
'Script Author: Rslaten
'Script Purpose: Delete a client throughout hierarchy
'Script Creation Date: 04/01/2005
'Script Version: 1.1
'Revision History
'Ver Date Person Description
'-----------------------------------------------------------------------------------------
'1.0 04/01/2005 rslaten Created Script
'1.1 02/14/2006 rslaten Added additional error checking to script
'Other Information
'Set globals
Dim sCenSiteServer, sDelClient, bEverywhere, sSMSCenNameSpace, SMSSites()
'Call to start program
Main
Sub Main
GetCommandLineArguments
sSMSCenNameSpace = GetSMSNameSpace(sCenSiteServer)
If bEverywhere Then
GetSiteList
DelClientLoop
Else
DelSingleClient
End If
End Sub
'Deletes single client
Sub DelSingleClient
On Error Resume Next
Dim oLocator, oServices, refItem, colClient
Set oLocator = CreateObject("WbemScripting.SWbemLocator")
WScript.Echo "Connecting to " &sCenSiteServer
Set oServices = oLocator.ConnectServer(sCenSiteServer, sSMSCenNameSpace,,,,,128)
If Err.number <> 0 Then
WScript.Echo "Unable to connect to " &sCenSiteServer
WScript.Echo Err.number & " - " &Err.Description
Else
Set colClient = oServices.ExecQuery("select * from SMS_R_System where NetbiosName =" _
& " '" &sDelClient& "'")
If colClient is Nothing or Err.Number <> 0 Then
WScript.Echo sDelClient& " doesn't exist at site " & sCenSiteServer
Else
For each refItem in colClient
refItem.Delete_()
If Err.number <> 0 Then
WScript.Echo "Failed to delete " &sDelClient& " on site " & sCenSiteServer
WScript.Echo Err.number & " - " & Err.Description
Else
WScript.Echo "Successfully deleted " &sDelClient& " on site " & sCenSiteServer
End If
Next
End If
End If
Set refItem = Nothing
Set colClient = Nothing
Set oServices = Nothing
Set oLocator = Nothing
End Sub
'Delete clients
Sub DelClientLoop()
On Error Resume Next
Dim oLocator, oServices, Namespace, refItem, colClient
Set oLocator = CreateObject("WbemScripting.SWbemLocator")
For i = 0 to UBound(SMSSites)
WScript.Echo "Connecting to " &SMSSites(i)
Namespace = GetSMSNamespace(SMSSites(i))
Set oServices = oLocator.ConnectServer(SMSSites(i), NameSpace,,,,,128)
If Err.number <> 0 Then
WScript.Echo "Unable to connect to " &SMSSites(i)
WScript.Echo Err.number & " - " &Err.Description
Else
Set colClient = oServices.ExecQuery("select * from SMS_R_System where NetbiosName =" _
&" '" &sDelClient& "'")
If colClient is Nothing or Err.Number <> 0 Then
WScript.Echo sDelClient& " doesn't exist at site " & SMSSites(i)
Else
For each refItem in colClient
refItem.Delete_()
If Err.number <> 0 Then
WScript.Echo "Failed to delete " &sDelClient& " on site " & SMSSites(i)
WScript.Echo Err.number & " - " & Err.Description
Else
WScript.Echo "Successfully deleted " &sDelClient& " on site " & SMSSites(i)
End If
Next
End If
End If
Set refItem = Nothing
Set colClient = Nothing
Set oServices = Nothing
Next
Set oLocator = Nothing
End Sub
'Gets list of SMS Sites in the hierarchy
Sub GetSiteList()
On Error Resume Next
WScript.Echo "Getting list of SMS Primary Sites from " &sCenSiteServer
Dim oLocator, oServices, colSites, refItem, i
Set oLocator = CreateObject("WbemScripting.SWbemLocator")
Set oServices = oLocator.ConnectServer(sCenSiteServer, sSMSCenNameSpace,,,,,128)
If Err.number <> 0 Then
WScript.Echo "Error connecting to " &sSMSCenNameSpace& " on " &sCenSiteServer& ": " _
&Err.Number
Set oLocator = Nothing
Set oServices = Nothing
WScript.Quit
End If
Set colSites = oServices.ExecQuery("select * from SMS_Site")
For Each refItem in colSites
If refItem.Type = "2" Then
ReDim Preserve SMSSites(i)
SMSSites(i) = refItem.ServerName
i = i + 1
End If
Next
Set colSites = Nothing
Set oLocator = Nothing
Set oServices = Nothing
End Sub
'Gets SMS namespace
Function GetSMSNameSpace(SiteServer)
On Error Resume Next
Dim colNameSpaceQuery, refitem, refWMI
Set refWMI = GetObject("winMgmts:\\" &SiteServer&"\root\sms")
If Err.number <> 0 Then
WScript.Echo "Error connecting to SMS namespace on " &SiteServer
WScript.Quit
End If
Set colNameSpaceQuery = refWMI.ExecQuery("select * from SMS_ProviderLocation")
For Each refitem in colNameSpaceQuery
GetSMSNameSpace = refitem.NamespacePath
Next
Set colNameSpaceQuery = Nothing
Set refitem = Nothing
Set refWMI = Nothing
End Function
'Gets Command line args
Sub GetCommandLineArguments
On Error Resume Next
Dim iParameterCount
iParameterCount = WScript.Arguments.Count
If iParameterCount < 2 Then
ShowHelp
Bailout
End If
If iParameterCount = 2 Then
bEverywhere = FALSE
Else
If Ucase(WScript.Arguments(2)) = "EVERYWHERE" Then
bEverywhere = TRUE
End If
End If
sCenSiteServer = WScript.Arguments(0)
sDelClient = WScript.Arguments(1)
End Sub
'Routine for quiting script
Sub Bailout
WScript.Quit
End Sub
'Displays syntax
Sub ShowHelp
WScript.Echo ""
WScript.Echo "DelClient v1.1"
WScript.Echo "Usage: cscript.exe DelClient.vbs <CenSiteServerName> <NameOfClient> EVERYWHERE"
WScript.Echo "Note, the EVERYWHERE parameter is optional."
WScript.Echo "If EVERYWHERE is used then it will delete the client from each lower tier site."
WScript.Echo "If EVERYWHERE is not used then this script will only delete from that server."
WScript.Echo "Example: cscript.exe DelClient.vbs myCentralSiteServer myDeletedClient"
WScript.Echo ""
End Sub
Comments
Anonymous
September 13, 2006
Can I use a txt document with the list of 40 to 50 machines to delete?Anonymous
September 13, 2006
You can either modify the script to accept a txt file instead of a single machine. Any easy way to make this work would be to read each value from the txt file, set sDelClient to that value, then call the delete function(s) in a loop. This isn't very efficient but would work. A better, more time consuming option, would be to modify both of the delete client functions to accept an array of clients (that way you don't have a reconnect to WMI each time).Anonymous
December 07, 2006
Hi, what will happen if I delete the entries in the SMS database like this "Delete from System_DISC where Name0 = '" "Delete from System_DATA where Name0 = "" THXAnonymous
December 12, 2006
If you delete directly from the system_disc table then the entries will be removed from SMS, but there is a chance you might orphan some data for that client in the DB. This really depends on how the triggers are setup on that table (haven't personally dug into this as it's not something we would recommend doing). The more appropriate way to delete a client is through the console or the SDK.Anonymous
August 30, 2007
Russ, one thing I was wondering was:- What would be the minimum security right that would allow a user to run this against a server?? Within SMS I see that the minimum requirement is a Class Security Right of Delete Resource against Collections. However, regarding NT security I can only seem to get it do work if I make the user running it a member of the local Administrators group. I've tried various other combinations e.g. adding user to "Distributed DCOM Users" or "Power Users", but haven't had any luck. The site server is running on Windows 2003 SP2. Other than that, its a wonderful script....Anonymous
August 30, 2007
The comment has been removedAnonymous
August 30, 2007
I tried doing it through dcomcnfg without luck. However.... I think I have found a way to do it, but am not sure if it maybe exposed security too much. Computer Management (on site server) Services and Applications WMI Control Then add the required users to the SMS namespace (and subnamespaces). So the question would be, is this too unsecure? What if this permission was given to "Domain Users"? My guess would be it is unsecure. But it would be extremely unlikely someone would connect to this mistakenly.Anonymous
August 30, 2007
If you can connect to rootcimv2 (using the ConnectServer() and/or GetObject methods) and not to rootsmssite_<sitecode> then it shouldn't be a DCOM thing and the focus should be on SMS permissions. Have you added the applicable user/group to the SMS Admins group on the server? That should give you rights to the SMS namespace, then you'll need the class permissions you mentioned earlier.