If you look at this post, I describe a my idea of a SCCM trickle install – that is X number of machines at a time. Rather that have the install hit the whole collection at once, I wanted to hit just 20 a night. That way if there is an error, we can put the breaks on the deployment. We create dynamic collections that use a “NOT IN” SQL statement – this results in all the machines that are in the collection need the specific software. This script copies X at a time from that collection to new collection.
In the previous post, I run a VBScript that loops through the first 10 (or X) number of machines in the collection and add them to a new collection that contains the assigned advertisement. The next night, the script runs again, and the next 10 (or X) are copied (since the source collection is dynamic, the machines from the night before are removed).
I wanted to do the same thing, but I wanted to use PowerShell. First up, a function to find a Collection’s Id.
FUNCTION JBM-SCCM-GetCollection { Param([parameter(Mandatory = $true)]$CollectionName, $SiteName="JBM", $SCCMServer="sccmserver.domain.com") $SCCMNameSpace="root\sms\site_$SiteName" $QUERY="Select CollectionID from SMS_Collection WHERE Name = '$CollectionName'" Return $(Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query $QUERY) }
Next a function to find all the machines in a collection:
FUNCTION JBM-SCCM-GetCollectionMembers{ Param([parameter(Mandatory = $true)]$CollectionID, $SiteName="JBM", $SCCMServer="sccmserver.domain.com") $SCCMNameSpace="root\sms\site_$SiteName" $QUERY="SELECT Name FROM SMS_FullCollectionMembership WHERE CollectionID = '$CollectionID'" Return $(Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query $QUERY) }
Next a function to remove all machines in a collection (the ones that are directly added)
FUNCTION JBM-SCCM-DeleteAllCollectionMembers{ Param([parameter(Mandatory = $true)]$CollectionID, $SiteName="JBM", $SCCMServer="sccmserver.domain.com") $SCCMNameSpace="root\sms\site_$SiteName" $Collection=[WMI]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_Collection.CollectionID='$CollectionID'" ForEach ($Rule in $Collection.CollectionRules ){ $Collection.DeleteMembershipRule($Rule) } }
Next, a function to add a machine to a Collection:
FUNCTION JBM-SCCM-AddCollectionMember{ Param([parameter(Mandatory = $true)]$CollectionID, $SiteName="JBM", $SCCMServer="sccmserver.domain.com", [parameter(Mandatory = $true)]$ComputerToAdd) $SCCMNameSpace="root\sms\site_$SiteName" $computer = gwmi -computer $SCCMServer -namespace $SCCMNameSpace -Query "select * from SMS_R_System where NetBiosName='$ComputerToAdd'" $Collection=[WMI]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_Collection.CollectionID='$CollectionID'" $ruleClass = [wmiclass]"\\$($SCCMServer)\$($SCCMNameSpace):SMS_CollectionRuleDirect" $newRule = $ruleClass.CreateInstance() $newRule.RuleName = $ComputerToAdd $newRule.ResourceClassName = "SMS_R_System" $newRule.ResourceID = $computer.ResourceID $null = $Collection.AddMembershipRule($newRule) }
Finally, a function to copy machines from one collection to another, using the functions above:
FUNCTION JBM-SCCM-CopyCollectionMembers { Param([parameter(Mandatory = $true)]$SourceCollectionName, [parameter(Mandatory = $true)]$DestinationCollectionName, [parameter(Mandatory = $true)]$NumberToCopy) $SrcCollID=JBM-SCCM-GetCollection($SourceCollectionName) $DstCollID=JBM-SCCM-GetCollection($DestinationCollectionName) $SrcCollMembers=JBM-SCCM-GetCollectionMembers($SrcCollID.CollectionID) JBM-SCCM-DeleteAllCollectionMembers($DstCollID.CollectionID) foreach ($Computer in $($SrcCollMembers | select -first $NumberToCopy)){ JBM-SCCM-AddCollectionMember -CollectionID $DstCollID.CollectionID -ComputerToAdd $Computer.Name } }
The result – a trickle install.