Introduction
If you work with Microsoft System Center Configuration Manager (SCCM / ConfigMgr) 2007 in any capacity, you probably are familiar with the concept of "collections" and how painful they can be to work with sometimes. The ConfigMgr console does not provide any method of moving a collection from one parent to another, and the GUI is pretty slow to work with.
So what’s the solution here? PowerShell, of course!
PowerShell Code
Here is a PowerShell function that will allow you to move a ConfigMgr collection either by name or by collection ID.
Note: Select all of the function text top-to-bottom, and you can retrieve the text that is cut off towards the right.
<# .Synopsis This function allows you to re-assing the parent for a ConfigMgr collection to a new collection ID .Author Trevor Sullivan (pcgeek86@gmail.com) .Example c:PS> Move-SccmCollection -SccmServer sccm01 -SiteCode LAB -CollectionID LAB00159 -ParentCollectionID LAB000150; Description ----------- This command moves the ConfigMgr collection with ID "LAB000159" to being a child of collection ID "LAB000150". .Example c:PS> Move-SccmCollection -SccmServer sccm01 -SiteCode LAB -CollectionName 'Visual Studio' -ParentCollectionID Microsoft; Description ----------- This command moves the ConfigMgr collection named "Visual Studio" to being a child of the collection named "Microsoft". Note that you do not need to specify quotes around the parameter value if it does not contain spaces. .Notes This function is untested with collection links. It is not known whether or not this will remove existing collection links. #> function Move-SccmCollection { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] ${SccmServer} , [Parameter(Mandatory = $true)] [string] ${SiteCode} , [Parameter(ParameterSetName = "ByCollectionID", Mandatory = $true)] [string] ${CollectionID} , [Parameter(ParameterSetName = "ByCollectionID", Mandatory = $true)] [string] ${ParentCollectionID} , [Parameter(ParameterSetName = "ByCollectionName", Mandatory = $true)] [string] ${CollectionName} , [Parameter(ParameterSetName = "ByCollectionName", Mandatory = $true)] [string] ${ParentCollectionName} ) # Set-PSDebug -Strict; # Ensure that ConfigMgr site server is available if (-not (Test-Connection -ComputerName $SccmServer -Count 1)) { return; } # Obtain references to collection and parent collection switch ($PSCmdlet.ParameterSetName) { # Use the "ByCollectionID" PowerShell parameter set to retrieve collection references by ID 'ByCollectionID' { ${CollectionRelationship} = @(Get-WmiObject -ComputerName $SccmServer -Namespace rootsmssite_$SiteCode -Class SMS_CollectToSubCollect -Filter "subCollectionID = '$CollectionID'")[0]; ${Collection} = @([wmi]("\{0}rootsmssite_{1}:SMS_Collection.CollectionID='{2}'" -f ${SccmServer}, ${SiteCode}, ${CollectionID}))[0]; ${ParentCollection} = @([wmi]("\{0}rootsmssite_{1}:SMS_Collection.CollectionID='{2}'" -f ${SccmServer}, ${SiteCode}, ${ParentCollectionID}))[0]; } # Use the "ByCollectionName" PowerShell parameter set to retrieve collection references by name 'ByCollectionName' { ${Collection} = [wmi](@(Get-WmiObject -ComputerName $SccmServer -Namespace rootsmssite_$SiteCode -Class SMS_Collection -Filter ("Name = '{0}'" -f ${CollectionName}))[0].__PATH); ${ParentCollection} = [wmi](@(Get-WmiObject -ComputerName $SccmServer -Namespace rootsmssite_$SiteCode -Class SMS_Collection -Filter ("Name = '{0}'" -f ${ParentCollectionName}))[0].__PATH); ${CollectionRelationship} = @(Get-WmiObject -ComputerName $SccmServer -Namespace rootsmssite_$SiteCode -Class SMS_CollectToSubCollect -Filter ("subCollectionID = '{0}'" -f ${Collection}.CollectionID))[0]; } } # If references to both the child and [new] parent collection were obtained, then move on if (${Collection} -and ${ParentCollection}) { Write-Verbose -Message ('Setting parent collection for {0}:{1} to {2}:{3}' -f ` ${Collection}.CollectionID ` , ${Collection}.Name ` , ${ParentCollection}.CollectionID ` , ${ParentCollection}.Name); ${CollectionRelationship}.parentCollectionID = ${ParentCollection}.CollectionID; # Create the new collection relationship (this [oddly] spawns a NEW instance of SMS_CollectToSubCollect), so we have to clean up the original one ${CollectionRelationship}.Put(); # Clean up all other collection relantionships for this collection ${OldCollectionRelationshipList} = @(Get-WmiObject -ComputerName $SccmServer -Namespace rootsmssite_$SiteCode -Class SMS_CollectToSubCollect -Filter ("subCollectionID = '{0}' and parentCollectionID <> '{1}'" -f ${Collection}.CollectionID, ${ParentCollection}.CollectionID)); foreach (${OldCollectionRelationship} in ${OldCollectionRelationshipList}) { ${OldCollectionRelationship}.Delete(); } } else { Write-Warning -Message 'Please ensure that you have entered a valid collection ID or name'; } }
Here is an example of how to use this function to move a collection based on their collection IDs:
Move-SccmCollection -SccmServer sccm01.mybiz.loc -SiteCode LAB -CollectionID LAB00011 -ParentCollectionID LAB00022;
Here is an example of how to use the function to move a collection based on the collection name:
Move-SccmCollection -SccmServer sccm01.mybiz.loc -SiteCode LAB -CollectionName ‘Visual Studio’ -ParentCollectionID Microsoft;
You’ll need the following to execute this simple script: