Shaun Cassells at MyITForum.com

SMS 2003 and ConfigMgr 2007, PowerShell, Scripting, Finance, Fitness and Fun

News

Locations of visitors to this page

Trickle Feed script update - Direct Memberships and Moves to reduce repeat instances

Their is another script out in the Code Repository of MyITForum.com.

10762Tricle_Feed.zip

  The orginal script uses queries and grabs a random (possibly repeating) number of clients from a source collection.  Then adds that query to the destination collection.  This works well when you do large number of machines... but does not work so well on smaller groups.

 

My version attached and below:

  • Does Direct Memberships
  • Outputs to a log to check whats going on
  1. Takes a Source Collection with PCs added (assumes machine names are instance names)
  2. Grabs Total # of machines / divides by number you want to move at a time = #
  3. Takes the calculated # (in above step) machine each to not make it random but evenly dispersed
  4. Adds those machine names as direct membership rules in destination collection

 

 

'Script Updated by Shaun Cassells 11072006
'scassells at aegonusa.com
'**************************************************************************************
' Add scheduled task on server to run script every 30 minutes!
' Prompts for
' SMS Server
' SMS Site Code
' Number of machines to be moved per call
' Source Collection
' Destination Collection
'**************************************************************************************

Option Explicit


Dim SourceCollection, SourceCollectionID, DestinationCollection, DestinationCollectionID
Dim SMSSiteServerName, SMSSiteCode, MaximumMachinePerInterval
Dim instCollection, instDirectRule, objArgs
Dim objLocator, objSMS, objEnumerator, strQuery, instance, instances, objNameDictionary, objResrouceIDDictionary

err.clear
set objArgs = WScript.Arguments

'Read in Input
If objArgs.Count <> 5 Then
 WScript.Echo "Missing arguements" & VbCrLf &_
 "Please pass Two Collection Names (in quotes)" & VbCrLf &_
 "  The SMS Server Name " & VbCrLf & _
 "  The Site Code " & VbCrLf & _
 "  # of machines to be migrated at each interval " & VbCrLf & _
 "  The Source Collection Name " & VbCrLf & _
 "  The Destination Collection Name "
 WScript.Quit
Else
 SMSSiteServerName = ObjArgs(0)
 SMSSiteCode = ObjArgs(1)
 MaximumMachinePerInterval = ObjArgs(2)
 SourceCollection = ObjArgs(3)
 DestinationCollection = ObjArgs(4)
End If

FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "  " & Date & " " & Time & " *******************************************************************************"
FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Starting Script"
FileAddLineToLogFile "MaximumMachinePerInterval = " & MaximumMachinePerInterval
FileAddLineToLogFile "SourceCollection = " & SourceCollection
FileAddLineToLogFile "DestinationCollection = " & DestinationCollection
FileAddLineToLogFile "SMSSiteServerName = " & SMSSiteServerName
FileAddLineToLogFile "SMSSiteCode = " & SMSSiteCode

FileAddLineToLogFile "connect to scripting WMI interface"
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
FileAddLineToLogFile "Connect to the server and Name space"
set objSMS=objLocator.ConnectServer(SMSSiteServerName, "root\sms\site_" & SMSSiteCode)
FileAddLineToLogFile "set the security level to use impersonation"
objSMS.Security_.ImpersonationLevel = 3

FileAddLineToLogFile "Get the SourceCollection contents"
strQuery =  "select CollectionID, Name from SMS_Collection where (Name in ('" & SourceCollection & "', '" & DestinationCollection & "'))"
Set instances = objSMS.ExecQuery(strQuery)
If instances.Count <> 2 Then
 FileAddLineToLogFile "Collection Name ID lookup failed on one of the 2"
  Wscript.QUIT
Else
 Dim CountInstance
  For Each instance In instances
  Select Case instance.Name
   Case SourceCollection
    SourceCollectionID = instance.CollectionID
   Case DestinationCollection
    DestinationCollectionID = instance.CollectionID
  End Select
 Next
 End If
FileAddLineToLogFile "SourceCollectionID = " & SourceCollectionID
FileAddLineToLogFile "DestinationCollectionID = " & DestinationCollectionID

FileAddLineToLogFile "Create Dictionary Object"
Set objNameDictionary = CreateObject("Scripting.Dictionary")
Set objResrouceIDDictionary = CreateObject("Scripting.Dictionary")
Dim objDicItem, TotalSourceCollection, InstancestoPull, PositionDictionary

FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Pull The Collection contents machine Names"
strQuery = "SELECT Name, ResourceID FROM SMS_CM_RES_COLL_" & SourceCollectionID
FileAddLineToLogFile strQuery
Set objEnumerator = objSMS.ExecQuery(strQuery)

FileAddLineToLogFile "Now we have all of the system Names and ResouceIDs in a Dictionary Object;"
For Each instance In objEnumerator
 FileAddLineToLogFile instance.Name
 FileAddLineToLogFile instance.ResourceID
Next
FileAddLineToLogFile "************************************************************************************************************************"
TotalSourceCollection = objEnumerator.Count
FileAddLineToLogFile "TotalSourceCollection = " & TotalSourceCollection
'Round to the nearest whole number
InstancestoPull = round((TotalSourceCollection / MaximumMachinePerInterval), 0)
FileAddLineToLogFile "MaximumMachinePerInterval = " & MaximumMachinePerInterval
'If value is less than 1 that means pull all remaing values
If InstancestoPull < 1 Then
  InstancestoPull = 1
End If
FileAddLineToLogFile "InstancestoPull = " & InstancestoPull
CountInstance = 0
PositionDictionary = 0
FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Get Values out into Dictionary Objects"
For Each instance in objEnumerator
 FileAddLineToLogFile "CountInstance mod InstancestoPull = " & (CountInstance mod InstancestoPull)
 FileAddLineToLogFile "CountInstance = " & CountInstance
 FileAddLineToLogFile "InstancestoPull = " & InstancestoPull
 If (CountInstance mod InstancestoPull) = 0 Then
  '-------------------------------------------------------------------
  'Get the Values and add to the Dictionary
  FileAddLineToLogFile instance.Name & " at place " & CountInstance
  objNameDictionary.Add PositionDictionary, instance.Name
  objResrouceIDDictionary.Add PositionDictionary, instance.ResourceID
  PositionDictionary = PositionDictionary + 1
 End If
 CountInstance = CountInstance + 1
Next

FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Time to remove objects out of SourceCollection"
FileAddLineToLogFile "Connect to the Source Collection = " & SourceCollection
FileAddLineToLogFile "Connect to the Source CollectionID = " & SourceCollectionID
Set instCollection = objSMS.Get("SMS_Collection.CollectionID=""" & SourceCollectionID & """")
FileAddLineToLogFile "Connect to the Direct Rule Source"
FileAddLineToLogFile "************************************************************************************************************************"
For Each objDicItem In objNameDictionary
 FileAddLineToLogFile "Remove Machine ResourceID from Source Collection = " & UCase(objResrouceIDDictionary.Item(objDicItem))
 Set instDirectRule = objSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_
 instDirectRule.ResourceID = UCase(objResrouceIDDictionary.Item(objDicItem))
 instCollection.DeleteMembershipRule instDirectRule
Next
FileAddLineToLogFile "Initiate a Refresh of Source Collection ONLY"
instCollection.RequestRefresh False
FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Free the Query from memory"
Set objEnumerator = Nothing
Set instDirectRule = Nothing
Set instCollection = Nothing
FileAddLineToLogFile "************************************************************************************************************************"

FileAddLineToLogFile "Now we have all of the system Names and ResouceIDSin a Dictionary Object;"
For Each objDicItem In objNameDictionary
 FileAddLineToLogFile UCase(objNameDictionary.Item(objDicItem))
 FileAddLineToLogFile UCase(objResrouceIDDictionary.Item(objDicItem))
Next
FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Connect to the Destination Collection = " & DestinationCollection
FileAddLineToLogFile "Connect to the Destination CollectionID = " & DestinationCollectionID
set instCollection = objSMS.Get("SMS_Collection.CollectionID=""" & DestinationCollectionID & """")
FileAddLineToLogFile "Connect to the Direct Rule"

For Each objDicItem in objNameDictionary
 Set instDirectRule = objSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_
 instDirectRule.ResourceClassName = "SMS_R_System"
        instDirectRule.ResourceID = UCase(objResrouceIDDictionary.Item(objDicItem))
        FileAddLineToLogFile "Adding ResourceID = " & instDirectRule.ResourceID
        instDirectRule.RuleName = UCase(objNameDictionary.Item(objDicItem))
 FileAddLineToLogFile "Adding RuleName = " & instDirectRule.RuleName
        instCollection.AddMembershipRule instDirectRule
        FileAddLineToLogFile "Adding Direct Rule"
Next

FileAddLineToLogFile "Initiate a Refresh of this Destination Collection ONLY"
instCollection.RequestRefresh False
FileAddLineToLogFile "************************************************************************************************************************"
FileAddLineToLogFile "Empty variables from memory"
Set instDirectRule = Nothing
Set instCollection = Nothing
Set objSMS = Nothing
Set objLocator = Nothing
Set objArgs = Nothing

FileAddLineToLogFile "Notify user of script completion"

'**************************************************************************************************************
Sub FileAddLineToLogFile (DataToAdd)
 'Function
  'Add a log entry to where the current script is located with extention of .log
 'Input
  'Data to be added to the log
 'Output
  'Log file in script directory contains the new log entry

 on error resume next
 Const ForAppending = 8
 Dim objFSO, objLogFile, LogFileName
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 LogFileName = wscript.scriptfullname & ".log"
 Set objLogFile = objFSO.OpenTextFile ( LogFileName, ForAppending, True)
 'Write the Data
 objLogFile.WriteLine Date & " " & Time & " " & DataToAdd
 'Close the file
 objLogFile.Close
End Sub

 

Comments

Chris Wimer said:

You have no idea how helpful this was...I spent three days trying to update a collection membership reading the ResourceId's from a RecordSet instead of an Array Object.  Here is my working module:

Option Explicit On

Module Module1

   Sub Main()

       Dim DestinationCollectionID

       Dim instCollection, instDirectRule, objArgs

       Dim objLocator, objSMS, objEnumerator, strQuery, objNameDictionary, objResrouceIDDictionary

       objLocator = CreateObject("WbemScripting.SWbemLocator")

       objSMS = objLocator.ConnectServer("xxxxxxxxx", "root\sms\site_xxx")

       objSMS.Security_.ImpersonationLevel = 3

       objNameDictionary = CreateObject("Scripting.Dictionary")

       objResrouceIDDictionary = CreateObject("Scripting.Dictionary")

       Dim objDicItem

       strQuery = "SELECT Name, ResourceID FROM SMS_CM_RES_COLL_xxxxxxx"

       objEnumerator = objSMS.ExecQuery(strQuery)

       DestinationCollectionID = "xxxxxxx"

       instCollection = objSMS.Get("SMS_Collection.CollectionID=""" & DestinationCollectionID & """")

       For Each objDicItem In objEnumerator

           instDirectRule = objSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_

           instDirectRule.ResourceClassName = "SMS_R_System"

           MsgBox(objDicItem.name)

           MsgBox(objDicItem.resourceid)

           instDirectRule.ResourceID = (objDicItem.resourceid)

           instDirectRule.RuleName = (objDicItem.name)

           instCollection.AddMembershipRule(instDirectRule)

       Next

       instCollection.RequestRefresh(False)

       instDirectRule = Nothing

       instCollection = Nothing

       objSMS = Nothing

       objLocator = Nothing

       objArgs = Nothing

   End Sub

End Module

# December 11, 2008 10:17 PM