Creating Vista, Windows 7, Server 2008 Collections for SCCM SP2 using VBScript.

Service Pack 2 for Configuration Manager 2007 delivers new platform support for Windows 7, Windows Vista SP2, Windows Server 2008 R2 and Windows Server 2008 SP2.

After installing SP2 you will need to create collections for Windows 7, Server 2008 R2 and possibly Windows Vista and Server 2008 if you have not already done so, I used the following script to create 4 new collections:

Click View Source to view\copy script

The script does not check for existing collections and I have only used it in a test environment so use at your own risk.

' Modified CreateDynamicCollection script from SCCM SDK.
' winDeploy 2009
Set swbemLocator=CreateObject("WbemScripting.SWbemLocator")
Set swbemconnection=swbemLocator.ConnectServer(".", "root\sms")
Set providerLoc=swbemconnection.InstancesOf("SMS_ProviderLocation")

For Each Location In providerLoc
    If location.ProviderForLocalSite = True Then
        Set swbemconnection = swbemLocator.ConnectServer(Location.Machine, "root\sms\site_" + Location.SiteCode)
        Exit For
    End If
Next

Call CreateCollection(swbemconnection, "All Windows Vista Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Workstation 6.0%'")
Call CreateCollection(swbemconnection, "All Windows 7 Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Workstation 6.1%'")
Call CreateCollection(swbemconnection, "All Windows Server 2008 Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Server 6.0%'")
Call CreateCollection(swbemconnection, "All Windows Server 2008 R2 Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Server 6.1%'")

Sub CreateCollection(connection, newName, queryForRule)
	'Update this collection on a schedule.
	Set Token = swbemconnection.Get("Sms_St_RecurInterval")
	Token.DaySpan = 1 'Use Token.HourSpan = 1 or for Token.MinuteSpan = 30 for test environment
	Token.StartTime = GetStartTime()

    ' Create the collection.
    Set newCollection = connection.Get("SMS_Collection").SpawnInstance_
    newCollection.Name = newName
	newCollection.Comment = newName + "."
    newCollection.OwnedByThisSite = true
	newCollection.RefreshSchedule = Array(Token)
	newCollection.RefreshType = 2

    ' Save the new collection and save the collection path for later.
    Set collectionPath = newCollection.Put_    

   ' IMPORTANT: If you do not specify the relationship, the new collection will not be visible in the console.
    Set newSubCollectToSubCollect = connection.Get("SMS_CollectToSubCollect").SpawnInstance_
    newSubCollectToSubCollect.parentCollectionID = "COLLROOT" ' Define to what collection the new collection is subordinate.
    newSubCollectToSubCollect.subCollectionID = CStr(collectionPath.Keys("CollectionID"))
    newSubCollectToSubCollect.Put_  ' Save the subcollection information.

    ' Create a new collection rule object for validation.
    Set queryRule = connection.Get("SMS_CollectionRuleQuery")
    validQuery = queryRule.ValidateQuery(queryForRule)   ' Validate the query (good practice before adding it to the collection). 

    ' Continue with processing, if the query is valid.
    If validQuery Then
        ' Create the query rule.
        Set newQueryRule = QueryRule.SpawnInstance_
        newQueryRule.QueryExpression = queryForRule
        newQueryRule.RuleName = newName + "." 

        ' Add the new query rule to a variable.
        Set newCollectionRule = newQueryRule

        ' Get the collection.
        Set newCollection = connection.Get(collectionPath.RelPath)
        newCollection.AddMembershipRule newCollectionRule ' Add the rules to the collection.
        newCollection.RequestRefresh False ' Call RequestRefresh to initiate the collection evaluator.
	  Else
	    MsgBox("Invalid Query: " + queryForRule)
     End If
End Sub

Function GetStartTime()
  Set objSWbemServices = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
  Set colTimeZone = objSWbemServices.ExecQuery ("SELECT * FROM Win32_TimeZone")

  For Each objTimeZone in colTimeZone
   strBias = objTimeZone.Bias
  Next

  dtmCurrentDate = Date
  GetStartTime = Year(dtmCurrentDate)

  dtmMonth = Month(dtmCurrentDate)
  If Len(dtmMonth) = 1 Then
   dtmMonth = "0" & dtmMonth
  End If

  GetStartTime = GetStartTime & dtmMonth

  dtmDay = Day(dtmCurrentDate)
  If Len(dtmDay) = 1 Then
   dtmDay = "0" & dtmDay
  End If

  If Len(Hour(Now())) = 1 Then
   Hours = "0" & Hour(Now())
  Else
   Hours = Hour(Now())
  End If

  If Len(Minute(Now())) = 1 Then
   Minutes = "0" & Minute(Now())
  Else
   Minutes = Minute(Now())
  End If

  GetStartTime = GetStartTime & dtmDay & Hours & Minutes & "00.00000"
  GetStartTime = GetStartTime & Cstr(strBias)
  GetStartTime = GetStartTime & "+***"
End Function

You can follow any responses to this entry through the RSS 2.0 feed. You can skip to the end and leave a response. Pinging is currently not allowed.

14 Comments »

 
  • ChrisC says:

    Great work here! I have looked everyone for something like this. However, I tried to execute it and I am getting a “Type Mismatch” on line 21 “Set Token = swbemconnection.Get(“Sms_St_RecurInterval”)

  • Tone says:

    Hi Chris, Are you running the script on the sccm server or remotely?

    Think the problem is due to you not making a valid connection to SCCM.

    The original scripts and more info can be found here:
    http://msdn.microsoft.com/en-us/library/cc145272.aspx
    http://msdn.microsoft.com/en-us/library/aa393720(VS.85).aspx
    http://msdn.microsoft.com/en-us/library/cc143744.aspx

  • bitdoctor says:

    I have to agree with ChrisC – I copied the code exactly and I ran it on my SCCM server; and I also get the “type mismatch.
    Mine says “Line 23, Character 2, Type Mismatch, Code: 80041005, Source: SWbemObjectEx”

    So, there is definitely/clearly something wrong with your posted code. It would be kind of you to take the code and run it (modify the collection on your test server to “TestColl” and comment out the Vista, Win7 & Win Server collections; and you will see the error. (YES, I KNOW: THE THREAD/RESPONSES ARE OVER A YEAR OLD :-)

    Eventually, I will figure it out, and I also am referencing some of the links you mentioned; as well as other expert links regarding programmatically creating collections. It’s just extremely frustrating to have wonderful code like this that does not work, due to possibly one single line and/or some object/connection not being properly made/created.

    The error is, as ChrisC mentioned, right around the swbemconnetion.Get command:

    Sub CreateCollection(connection, newName, queryForRule)
    ‘Update this collection on a schedule.
    Set Token = swbemconnection.Get(“Sms_St_RecurInterval”)
    Token.DaySpan = 1 ‘Use Token.HourSpan = 1 or for Token.MinuteSpan = 30 for test environment
    Token.StartTime = GetStartTime()

    ‘ Create the collection.
    Seems to be the “Set Token” line – I tried changing Sms_St to SMS_ST, as that is the ‘official’ beginning designation of that class, but the problem seems to be a bit deeper than that.

    So, the error seems to point back to the “Set swbemconnection command at the very beginning:

    Set swbemLocator=CreateObject(“WbemScripting.SWbemLocator”)
    Set swbemconnection=swbemLocator.ConnectServer(“.”, “root\sms”)
    Set providerLoc=swbemconnection.InstancesOf(“SMS_ProviderLocation”)

    Any hints or clues would be greatly appreciated; either way, I am still researching.

    Cheers!
    Jeff Mason
    MDHA System Administrator
    Nashville, TN, US

  • bitdoctor says:

    Ok, your “For Each Location In providerLoc” loop is not based on an iterative query, so I think I found it; I think you forgot your “SELECT * From SMS_ProviderLocation,” as in this similar example:

    Set objLoc = CreateObject(“WbemScripting.SWbemLocator”)
    Set objSMS= objLoc.ConnectServer(strSMSServer, “root\sms”)
    Set Results = objSMS.ExecQuery _
    (“SELECT * From SMS_ProviderLocation WHERE ProviderForLocalSite = true”)
    For each Loc in Results
    If Loc.ProviderForLocalSite = True Then
    Set objSMS = objLoc.ConnectServer(Loc.Machine, “root\sms\site_” & _
    Loc.SiteCode)
    strSMSSiteCode = Loc.Sitecode
    end if
    Next

  • Tone says:

    Hi Bitdoctor,

    I just copied and pasted from the blog onto a dev site server and the script ran fine and created the collections.

    Glad you got it sorted though and posted a fix for others.

  • bitdoctor says:

    Ok, maybe not exactly. You did use “InstancesOf” – so, I am not exactly sure, but that may allow the ‘For Next’ loop to proceed properly.

    BUT, I did find a spelling/syntax error: You had “location” vs. “Location” – and those are two completely separate strings, as far as I know; here is the place where one discrepancy resides:

    For Each Location In providerLoc
    If location.ProviderForLocalSite = True Then
    Set swbemconnection = swbemLocator.ConnectServer(Location.Machine, “root\sms\site_” + Location.SiteCode)
    Exit For
    End If
    Next

    So, you have the “For Each Location” (upper-case “L”), but then you have “If location” (lower-case “l”).

    Okay, I am still researching and still unable to get this to run. Either way, Thanks again for posting it!

  • bitdoctor says:

    Very curious how it gives 2 of the readers here (myself and ChrisC) a “Type mismatch” and yet it works for you?

    I am on Windows Server 2003, SP2.
    I am guessing you are on Server 2008.

    Does that make a difference?

  • bitdoctor says:

    And I am on SCCM 2007 R2.

  • bitdoctor says:

    A couple thinks I found.
    Actually on a Russian Systemcenter site:
    http://systemscenter.ru/sccm_sdk.en/html/966d74a2-ccf5-4a43-9298-4ee7d9de66bd.htm

    Turns out you must call such module/snippets using a ‘wrapper’ file from the SDK?

    Also note: RUN the SDK wrapper VIA “CSCRIPT” ! Else the Wscript.StdOut.Write and Wscript.StdIn.ReadLine commands do not work!

    I wrongly assumed you (we) could just save your code as “create-collection.vbs” and run it standalone; but, apparently, that is not the case?

    Here is the note from the top of that Russian link:

    “The following code samples show how to set up the calling code for the code examples that are used throughout the System Center Configuration Manager 2007 Software Development Kit (SDK).

    Replace the SNIPPETMETHOD snippet with the snippet that you want to run. In most cases you will need to make changes, such as adding parameters, to make the code work.”

    Does that sound correct? Are indeed using the SDK wrapper VBScript that is mentioned?

  • bitdoctor says:

    In above comment, I meant to ask: “Are [you] indeed using the wrapper that is mentioned?”

  • bitdoctor says:

    Okay, here is the troubleshooting
    It never progresses past the “SMS_ST_RecurInterval” command:

    Sub CreateCollection(connection, newName, queryForRule)

    Wscript.Echo “Made it INTO the ‘CreateCollection’ subroutine!”
    [I see the above echo just fine]
    ‘Update this collection on a schedule.
    –> Set Token = swbemconnection.Get(“Sms_St_RecurInterval”)

    [I never see ANY of the subsequent echo commands, so the "Set Token/RecurInterval," as suspected, seems to be the issue, at least for me; and apparently for ChrisC]

    wscript.Echo “past swbemconnection.Get cmd”
    Token.DaySpan = 1 ‘Use Token.HourSpan = 1 or for Token.MinuteSpan = 30 for test environment
    wscript.echo “attempting to call function GetStartTime…”
    Token.StartTime = GetStartTime()

    Wscript.Echo “Made it PAST Token setup”

  • bitdoctor says:

    And yes, I placed the “–>” in the above for emphasis only. It does not exist in the script. Again, tried with SMS_ST (upper-case) as well.

    Clues? Hints? Help?

  • bitdoctor says:

    Okay, I commented out the section “Update collection on a schedule”
    Now, it bombs at the “newCollection.Put_” command:

    Wscript.Echo “Made it PAST Token setup”

    ‘ Create the collection.
    Set newCollection = connection.Get(“SMS_Collection”).SpawnInstance_
    newCollection.Name = newName
    newCollection.Comment = newName + “.”
    newCollection.OwnedByThisSite = true
    newCollection.RefreshSchedule = Array(Token)
    newCollection.RefreshType = 2

    Wscript.Echo “Made it past CREATE COLLECTION”

    [NOTE: I see the above ECHO, but no echos after that!]

    ‘ Save the new collection and save the collection path for later.
    Set collectionPath = newCollection.Put_

    [THEREFORE, it is crashing on the above "Put_" statement]

    Wscript.Echo “Entering the SAVE NEW COLLECTION area…”

  • arboc66 says:

    This worked for me (two problems with original script, typo in the CreateCollection function and wrong date format for the starttime argument of the token):


    ' Modified CreateDynamicCollection script from SCCM SDK.
    ' winDeploy 2009
    Set swbemLocator=CreateObject("WbemScripting.SWbemLocator")
    swbemLocator.Security_.AuthenticationLevel = 6 'Packet Privacy
    Set swbemconnection=swbemLocator.ConnectServer(".", "root\sms")
    Set providerLoc=swbemconnection.InstancesOf("SMS_ProviderLocation")

    For Each Location In providerLoc
    If location.ProviderForLocalSite = True Then
    WScript.Echo Location.Machine
    WScript.Echo Location.SiteCode
    WScript.Echo "Connecting..."
    Set swbemconnection = swbemLocator.ConnectServer(Location.Machine, "root\sms\site_" & Location.SiteCode)
    If Err.Number0 Then
    Wscript.Echo "Couldn't connect: " & Err.Description
    WScript.Quit
    End If
    Exit For
    End If
    Next

    Call CreateCollection(swbemconnection, "All Windows Vista Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Workstation 6.0%'")
    Call CreateCollection(swbemconnection, "All Windows 7 Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Workstation 6.1%'")
    Call CreateCollection(swbemconnection, "All Windows Server 2008 Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Server 6.0%'")
    Call CreateCollection(swbemconnection, "All Windows Server 2008 R2 Systems", "select sms_r_system.ResourceID,sms_r_system.ResourceType,sms_r_system.Name,sms_r_system.SMSUniqueIdentifier,sms_r_system.ResourceDomainORWorkgroup,sms_r_system.Client from sms_r_system where OperatingSystemNameandVersion like '%Server 6.1%'")

    Sub CreateCollection(connection, newName, queryForRule)
    'Update this collection on a schedule.
    Set Token = connection.Get("Sms_St_RecurInterval")
    Token.DaySpan = 1 'Use Token.HourSpan = 1 or for Token.MinuteSpan = 30 for test environment
    Token.StartTime = GetStartTime()

    ' Create the collection.
    Set newCollection = connection.Get("SMS_Collection").SpawnInstance_
    newCollection.Name = newName
    newCollection.Comment = newName + "."
    newCollection.OwnedByThisSite = true
    newCollection.RefreshSchedule = Array(Token)
    newCollection.RefreshType = 2

    ' Save the new collection and save the collection path for later.
    Set collectionPath = newCollection.Put_

    ' IMPORTANT: If you do not specify the relationship, the new collection will not be visible in the console.
    Set newSubCollectToSubCollect = connection.Get("SMS_CollectToSubCollect").SpawnInstance_
    newSubCollectToSubCollect.parentCollectionID = "COLLROOT" ' Define to what collection the new collection is subordinate.
    newSubCollectToSubCollect.subCollectionID = CStr(collectionPath.Keys("CollectionID"))
    newSubCollectToSubCollect.Put_ ' Save the subcollection information.

    ' Create a new collection rule object for validation.
    Set queryRule = connection.Get("SMS_CollectionRuleQuery")
    validQuery = queryRule.ValidateQuery(queryForRule) ' Validate the query (good practice before adding it to the collection).

    ' Continue with processing, if the query is valid.
    If validQuery Then
    ' Create the query rule.
    Set newQueryRule = QueryRule.SpawnInstance_
    newQueryRule.QueryExpression = queryForRule
    newQueryRule.RuleName = newName + "."

    ' Add the new query rule to a variable.
    Set newCollectionRule = newQueryRule

    ' Get the collection.
    Set newCollection = connection.Get(collectionPath.RelPath)
    newCollection.AddMembershipRule newCollectionRule ' Add the rules to the collection.
    newCollection.RequestRefresh False ' Call RequestRefresh to initiate the collection evaluator.
    Else
    MsgBox("Invalid Query: " + queryForRule)
    End If
    End Sub

    Function GetStartTime()

    Set objSWbemServices = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
    Set colTimeZone = objSWbemServices.ExecQuery ("SELECT * FROM Win32_TimeZone")

    For Each objTimeZone in colTimeZone
    strBias = objTimeZone.Bias
    Next

    dtmCurrentDate = Date
    GetStartTime = Year(dtmCurrentDate)

    dtmMonth = Month(dtmCurrentDate)
    If Len(dtmMonth) = 1 Then
    dtmMonth = "0" & dtmMonth
    End If

    GetStartTime = GetStartTime & dtmMonth

    dtmDay = Day(dtmCurrentDate)
    If Len(dtmDay) = 1 Then
    dtmDay = "0" & dtmDay
    End If

    If Len(Hour(Now())) = 1 Then
    Hours = "0" & Hour(Now())
    Else
    Hours = Hour(Now())
    End If

    If Len(Minute(Now())) = 1 Then
    Minutes = "0" & Minute(Now())
    Else
    Minutes = Minute(Now())
    End If

    GetStartTime = GetStartTime & dtmDay & Hours & Minutes & "00.000000"
    GetStartTime = GetStartTime & Cstr(strBias)
    'GetStartTime = GetStartTime & "+***"

    End Function

    Good luck!

 

Leave a Reply

You must be logged in to post a comment.