Delete a successful Direct Member from an SMS 2003 / ConfigMgr 2007 collection based on a date in VB
In SMS 2003 and ConfigMgr (SCCM) 2007 you can create a Direct Member to a collection. This may or may not be the best option for you. We can debate that later. You have to be concerned about the number of Direct Memberships the SMS 2003 / ConfigMgr 2007 server must evaluate. The ColEval.log on the server could be overwhelmed if too many memberships are created and then the collection refreshed. Overwhelmed does not mean any errors, rather many tasks will be queued leaving you wondering why offers are not being produced. You can check to see if you have any collections refreshing with the following SQL Query:
select
CollectionName, ChangeCount, CurrentStatus, CurrentStatusTime From dbo.collections where Currentstatus not in ('0','1') order by CurrentStatusTimeWhat is the big deal about the Collection Evaluator NOT being multithreaded? This means when the collection is evaluated, the SMS 2003 / ConfigMgr 2007 server must do a SQL query to identify each individual record. As opposed to a query which can return results en mass (depending how it was written) This reason I created the following script to remove Direct Members for a successful application deployment before a certain user specified date. Example: You have a collection with 100 Direct Members. 90 of them have succeeded. 85 succeeded more than 3 months ago. Why do you still need those 85 successful 3 month old Direct Memberships? Best Practice appears to be 3 months. If the offer was successful for more than 3 months, you usually do not need to re-execute the advertisement on the client. Here is the code below (watch out for word wrap!)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' The following tool has several inputs and loops
' Inputs:
' Server Name
' Site Code
' Date to query on
' Blank or a capital Y
'
' This tool will query for direct memberships in all collections before date from input
'
' Created by Shaun Cassells
' http://myitforum.com/cs2/blogs/scassells/default.aspx
'
'
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim loc
Dim oArgs
Dim strComputer, ResID
Dim strServer, strSiteCode
'Dim Rules() As Variant 'Array of rules for DeleteMembershipRules
Dim total, TotalMembers
Set oArgs = WScript.Arguments
If oArgs.Count = 3 Then
WSCRIPT.ECHO "Please use 3/4 inputs"
WSCRIPT.ECHO " SMS Server"
WSCRIPT.ECHO " SMS Site Code"
WSCRIPT.ECHO " Date to display rules before -ex. '1/1/2008'"
WSCRIPT.ECHO " Blank displays results / Y = delete"
WSCRIPT.ECHO ""
End If
If (oArgs.Count < 3) or (oArgs.Count > 4) Then
WSCRIPT.ECHO "Please use 3/4 inputs"
WSCRIPT.ECHO " SMS Server"
WSCRIPT.ECHO " SMS Site Code"
WSCRIPT.ECHO " Date to display rules before -ex. '1/1/2008'"
WSCRIPT.ECHO " Blank displays results / Y = delete"
WSCRIPT.ECHO ""
WSCRIPT.QUIT
End If
strServer = oArgs(0)
strSiteCode = oArgs(1)
strDate = oArgs(2)
If oArgs.Count = 4 Then
bGO = oArgs(3)
End If
'convert extra chars in date to be correct format
strDate = replace(strDate, "\", "/")
strDate = replace(strDate, "-", "/")
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Set loc = CreateObject( "WbemScripting.SWbemLocator" )
Set WbemServices = loc.ConnectServer( strServer,"root\SMS\site_" & strSiteCode)
'WScript.Echo strComputer & " ResourceID in " & strServer & " is " & ResID
'Remove single or double quotes from date string
strDate = replace(strDate,"'","")
strDate = replace(strDate,"""","")
'wscript.echo strDate
'Query that finds count of successful direct members in all collections
'Excludes SUSFP and ITMU
'Excludes nonstandard resources
strQry = "SELECT dbo.v_AdvertisementInfo.CollectionID, dbo.v_AdvertisementInfo.CollectionName, COUNT(dbo.v_CollectionRuleDirect.ResourceID) AS Total " & _
" FROM dbo.v_CollectionRuleDirect INNER JOIN dbo.v_AdvertisementInfo ON dbo.v_CollectionRuleDirect.CollectionID = dbo.v_AdvertisementInfo.CollectionID INNER JOIN dbo.v_ClientAdvertisementStatus ON dbo.v_CollectionRuleDirect.ResourceID = dbo.v_ClientAdvertisementStatus.ResourceID AND dbo.v_AdvertisementInfo.AdvertisementID = dbo.v_ClientAdvertisementStatus.AdvertisementID " & _
" WHERE (dbo.v_ClientAdvertisementStatus.LastStateName = 'succeeded') AND (dbo.v_ClientAdvertisementStatus.LastStatusTime < CAST('" & strDate & "' AS DateTime)) AND (dbo.v_AdvertisementInfo.CollectionName NOT LIKE '%SUSFP%') AND (dbo.v_AdvertisementInfo.CollectionName NOT LIKE '%ITMU%') AND (dbo.v_CollectionRuleDirect.RuleName NOT LIKE 'ResourceID=%') " & _
" and (dbo.v_AdvertisementInfo.CollectionID like '" & strSiteCode & "%') " & _
" GROUP BY dbo.v_AdvertisementInfo.CollectionName, dbo.v_AdvertisementInfo.CollectionID " & _
" ORDER BY Total desc" 'dbo.v_AdvertisementInfo.CollectionID"
'wscript.echo strQry
'Connect SQL
Set cn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
constring = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SMS_" & strSiteCode & ";Data Source="& strServer
cn.ConnectionString = constring
cn.Open
Set cmd.ActiveConnection = cn
cmd.Prepared = True
cmd.CommandText = strQry
'wscript.echo strQry
Set rs = cmd.Execute
If rs.EOF Then
WScript.Echo "Query did not return any succesful direct members ! Please try again." & VBCrLF & "You entered date: " & strDate
Else
Wscript.ECHO "------------------------------------------------------------------------------"
Wscript.ECHO "Collection ID, Number of Identified Members, Collection Name"
Wscript.ECHO "------------------------------------------------------------------------------"
'Used to count loops - total number of collections (summary)
total = 0
'Used to show how many members returned (summary)
TotalMembers = 0
Do Until rs.EOF
total = total + 1
TotalMembers = TotalMembers + rs(2)
If bGO = "Y" Then
Wscript.ECHO "------------------------------------------------------------------------------"
End If
Wscript.Echo rs(0) & ", " & rs(2) & ", " & rs(1)
If bGO = "Y" Then
'Wscript.ECHO "SMS_Collection.CollectionID=""" & rs(0)& """"
Set instCollection = WbemServices.Get("SMS_Collection.CollectionID=""" & rs(0)& """")
'Query finds exact number of members to delete
strQry2 = "SELECT dbo.v_CollectionRuleDirect.RuleName, dbo.v_CollectionRuleDirect.ResourceID " & _
" FROM dbo.v_CollectionRuleDirect INNER JOIN dbo.v_AdvertisementInfo ON dbo.v_CollectionRuleDirect.CollectionID = dbo.v_AdvertisementInfo.CollectionID INNER JOIN dbo.v_ClientAdvertisementStatus ON dbo.v_CollectionRuleDirect.ResourceID = dbo.v_ClientAdvertisementStatus.ResourceID AND dbo.v_AdvertisementInfo.AdvertisementID = dbo.v_ClientAdvertisementStatus.AdvertisementID " & _
" WHERE (dbo.v_ClientAdvertisementStatus.LastStateName = 'succeeded') AND (dbo.v_ClientAdvertisementStatus.LastStatusTime < CAST('" & strDate & "' AS DateTime)) AND (dbo.v_CollectionRuleDirect.RuleName NOT LIKE 'ResourceID=%') AND (dbo.v_AdvertisementInfo.CollectionID = '" & rs(0) & "')"
'note array is ZERO to one minus total size
ReDim Rules((rs(2)-1)) '(0 to rs(2)) array must contain exact number of objects
i = 0
cmd.CommandText = strQry2
Set rs2 = cmd.Execute
If rs2.EOF Then
WScript.Echo "No succesfully completed direct members found! Please try again." & VBCrLF & "You entered: " & strDate
Else
Do Until rs2.EOF
Wscript.Echo rs2(0) & ", " & rs2(1)
' Identify and delete the direct rule.
Set instDirectRule = WbemServices.Get("SMS_CollectionRuleDirect").SpawnInstance_
instDirectRule.ResourceID = rs2(1)
Set Rules(i) = instDirectRule
i = i+1
'wscript.echo i
rs2.MoveNext
loop
End If
Wscript.ECHO "------------------------------------------------------------------------------"
WSCRIPT.ECHO "Deleting total of " & rs(2) & " members from " & rs(1)
' commit rules delete
'On Error Resume Next
instCollection.DeleteMembershipRules Rules
'On Error GoTo 0
'Wscript.ECHO "------------------------------------------------------------------------------"
'Wscript.Echo "*************************Pausing********************************"
'Wscript.ECHO "------------------------------------------------------------------------------"
'Wscript.Sleep(5000)
End If
Set rs2 = Nothing
rs.MoveNext
'The following can be used to limit the number of loops.
' useful to remove the process lock when doing lots of deletes
If (bGO = "Y") And (total > 100) Then
'Call Cleanup
End If
Loop
Wscript.ECHO "------------------------------------------------------------------------------"
Wscript.ECHO "Total collections = " & Total & VBCrLF & " Total Members = " & TotalMembers
Wscript.Echo " for successful direct rule collections before " & strDate
End If
Call Cleanup
Wscript.quit
Sub Cleanup
cn.Close
Set rs = Nothing
Set cmd = Nothing
Set cn = Nothing
Set instances = NOTHING
Set WbemServices = NOTHING
Set strQry = NOTHING
Set loc = Nothing
Wscript.quit
End Sub