Divide a collection into multiple smaller collections in ConfigMgr 2012 via PowerShell

This blog post will be about a question that I recently read on a forum and also already got a couple of times with different customers. That question is if it’s possible to simply create multiple smaller collections of one specific collection. This can be useful when a specific deployment has to be deployed in smaller groups then normally. Also, there are already a couple solution available in the community, like the SCCM Collection Splitter by Mickael Ponsot and the Planning an upgrade of an application  by Jörgen Nilsson, but as always, not every solution fits every customer. In my case(s) these solution didn’t fit, as it shouldn’t have to much options and it shouldn’t rely on static properties.

That’s why I created a simple PowerShell script that requires a collection and a number of collections as input. Based on that input this PowerShell script creates collections with random, but equally divided, collection members. The rest of this post will explain this PowerShell script and shows an example.

>> The complete function is available via download here on the TechNet Galleries! <<

Step 1: Get and set the start variables

The first step, like with every other script, is getting and setting variables to work with during the script. The collection name and the number of collections are input variables of this script and based on that input an array with devices will be created. I do this by using the Get-CMDevice cmdlet. Also, the number of devices per collection will be calculated. I do this by using the ceiling method of math. This will make sure that it will always round up, so we don’t have any leftovers after the script. This all together brings me to the following code:

$Devices = Get-CMDevice -CollectionName $CollectionName $NumberOfDevices = $Devices.Count $NumberOfDevicesPerCollection = ` [math]::ceiling($NumberOfDevices / $NummberOfCollections)

Step 2: Create the new collections

The second step is to create the new collections. Starting from this point the script will go through a for-loop for as many times as the number of collections to be created (see the complete script).  To make sure I create unique collections, I use the number of times it went through the for-loop as part of the collection name. Also, I simply use the New-CMDeviceCollection cmdlet to create the collections. This all together brings me to the following code:

$NewCollectionName = "Example Collection $i" New-CMDeviceCollection -Name $NewCollectionName ` -LimitingCollectionName $CollectionName

Step 3: Get and add the collection members

The third step is to get the collections members and to add them to the newly created collections. To be able to select a number of devices I use the Get-Random cmdlet that allows me to just select a specific number of random devices from an array. After that I can simply loop through those devices and create a direct membership rule per device, by using the Add-CMDeviceCollectionDirectMembershipRule cmdlet. This all together brings me to the following code:

$NewDevices = Get-Random -InputObject $Devices ` -Count $NumberOfDevicesPerCollection foreach ($NewDevice in $NewDevices) { Add-CMDeviceCollectionDirectMembershipRule ` -CollectionName $NewCollectionName -Resource $NewDevice }

Step 4 : Prepare for the next collection

The fourth, and last step, is to make all the variables ready for the next round through the for-loop. This means I’ve got to make sure that the devices that are added to the previous collection, are removed from the the array with devices. Also, it’s important to recalculate the number of devices per collection. This is to make sure that I won’t end-up with a really small collection, or, in some cases, a collection without members. This all together brings me to the following code:

$Devices = $Devices | Where-Object { $NewDevices -notcontains $_ } $NumberOfDevicesLeft = $Devices.Count $NummberOfCollectionsLeft = $NummberOfCollections-$i if ($NummberOfCollectionsLeft -gt 0) { $NumberOfDevicesPerCollection = ` [math]::ceiling($NumberOfDevicesLeft / $NummberOfCollectionsLeft) }

Result

At the end there’s nothing better then looking at a successful result. In the following screenshot the script is executed for the All Desktop and Server Clients collection to create four smaller (equally sized) collections.

ExampleCollections

11 thoughts on “Divide a collection into multiple smaller collections in ConfigMgr 2012 via PowerShell”

  1. I just got a question, is it suppose to be slow. on my system, i have a collection of 1669 machines and i am deviding it up by 4, but so far it’s only on the 2 collection and its already been 20 minutes. Just checking to see if that is normal or not

    Reply
  2. I just tried the script and it works but agree there is a performance issue. I was trying to split a collection of 3500 members into 4 collections. After 5 minutes of the script running, it had only added 150 members to the first collection.

    I looked in the help for Add-CMDeviceCollectionDirectMembershipRule, Intellisense indicates you can pass an array of ResourceID’s to the ResourceID parameter but in practice/the help documentation says otherwise. Kept throwing errors when I would try to run it.

    I ended up using a query rule that filtered the members of the original collection based on the device SMSUniqueIdentifier attribute. That attribute uses hexadecimal characters so I filtered from 0-3, 4-7, 8-B, C-F in each query rule.

    Reply
  3. This script looks very helpful indeed… I am currently trying to create multiple collections from a .txt file but I must be doing something wrong because my script only creates 1 collection. Any suggestions?

    Reply
  4. Hi Peter
    I’m looking for your full script since Technet is dead.
    Can you tell me where I could get it please?
    Thanks

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.