Menu

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

January 22, 2010 - Microsoft System Center Configuration Manager 2007, SCCM

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 viewcopy 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(".", "rootsms")
Set providerLoc=swbemconnection.InstancesOf("SMS_ProviderLocation")

For Each Location In providerLoc
    If location.ProviderForLocalSite = True Then
        Set swbemconnection = swbemLocator.ConnectServer(Location.Machine, "rootsmssite_" + 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}!\.rootcimv2")
  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

14 thoughts on “Creating Vista, Windows 7, Server 2008 Collections for SCCM SP2 using VBScript.

ChrisC

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

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

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(“.”, “rootsms”)
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

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, “rootsms”)
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, “rootsmssite_” & _
Loc.SiteCode)
strSMSSiteCode = Loc.Sitecode
end if
Next

Tone

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

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, “rootsmssite_” + 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

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

And I am on SCCM 2007 R2.

bitdoctor

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

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

bitdoctor

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

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

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

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(".", "rootsms")
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, "rootsmssite_" & 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}!\.rootcimv2")
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