4 min read

ConfigMgr - Phased Deployment using only one Deployment

ConfigMgr - Phased Deployment using only one Deployment
(C) Microsoft Corporation

The case was that i setup an IPU TS/Solution using OneVinn's TS Launcher, cause i find it really nice to use with IPU in bigger environments as i gives a nice user-experience. Check it, and many other nice goodies, over at

Onevinn - Featured

As part of setting it up you need to create an "Config.xml", and in it you enter the "DeploymentID" of ONE deployment, and what i usually do is i deploy everything to this collection and then one-by-one add/include another collection of devices to it as i roll out to a broader set of clients, when the time is right(when a % of the first collection devices has been successfully upgraded -> add next collection). But, of course this is something that you would want to automate, but using the builtin "Phased Deployment" doesn't really fit here, as it will create a new deployment, and with it, a new DeploymentID and there by the Config.xml in TSLauncher wont fit anymore, bang boom crash.

So, Powershell to the rescue!

<#
    DESCRIPTION:
    This script was made to make it possible to use "Phased deployment" but instead of making a new deployment with each phase, this script will add another collection into another 
    collection which has the deployment.
    
    e.g "Collection1" with 10 clients has "Deployment-X" deployed to it, when you 8/10 clients has successfully ran the deployment, you want "Collection2" to also have the deployment,
    but you dont want it to make another deployment for whatever reason, then this script will include "Collection2" in "Collection1", and those client will get the deployment aswell
    but there will be only one deployment.

    EXAMPLE:
    Run-NextPhaseDeployment -SiteCode "A01" -ProviderMachineName "mecmserver.corp.com" -MasterCollectionID "PS100123" -DeploymentID "PS120123" -MinPercentageForNextPhase "72" -PhaseCollectionNames "Phase-Collections-*"

#>

Param(
    [Parameter(HelpMessage = 'Enter your SiteCode', Mandatory = $True)]
    [String]$SiteCode,

    [Parameter(HelpMessage = 'Enter your siteserver FQDN', Mandatory = $True)]
    [String]$ProviderMachineName,

    [Parameter(HelpMessage = 'Enter the CollectionID of the collection to include other collections', Mandatory = $True)]
    [string]$MasterCollectionID,

    [Parameter(HelpMessage = 'Enter the DeploymentID of which to check success %', Mandatory = $True)]
    [string]$DeploymentID,

    [Parameter(HelpMessage = 'Enter threshold % of when to go into the next phase and include another collection', Mandatory = $True)]
    [string]$MinPercentageForNextPhase,

    [Parameter(HelpMessage = 'Enter a naming convetion of what collections to search for and get CollectionIDs that will be included when the next phase is ready', Mandatory = $True)]
    [string]$PhaseCollectionNames
) 

# Import the ConfigurationManager.psd1 module 
if((Get-Module ConfigurationManager) -eq $null) {
    Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams 
}

# Connect to the site's drive if it is not already present
if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
    New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
}

# Set the current location to be the site code.
Set-Location "$($SiteCode):\" @initParams

#Check MasteCollection for already included collections
$AlreadyIncluded = @()
[System.Collections.ArrayList]$Collections = Get-CMCollection -CollectionType Device -Name "$PhaseCollectionNames" | Select -Property CollectionID
    Foreach($Collection in $Collections){
        if(!(Get-CMCollectionIncludeMembershipRule -CollectionId $MasterCollectionID -IncludeCollectionId $Collection)){
            Write-output "$Collection- Eligible for inclusion..."
        }
        Else{
            Write-output "$Collection - Already included..."
            $AlreadyIncluded += $Collection
        }
    }
 
#Remove already included collections
Foreach($Included in $AlreadyIncluded){
    $Collections.Remove("$Included")
}

#Get collection ID to be included at next phase
$NextCollectionToInclude = $Collections | Select-Object -First 1
If(!$NextCollectionToInclude){
    Write-Output "No more collections to add for next phase..."
    Exit 0
}
Else{
    Write-Output "$NextCollectionToInclude will be added in next phase..."
}

#Check Percentage
$Deployment = Get-CMDeployment -DeploymentId $DeploymentID
$PercentSuccess = ($Deployment.NumberSuccess/$Deployment.NumberTargeted).ToString("P")
if($PercentSuccess -gt $MinPercentageForNextPhase){
    Write-Output "GO - Ready for next Phase!"
    Add-CMDeviceCollectionIncludeMembershipRule -CollectionId $MasterCollectionID -IncludeCollectionId $NextCollectionToInclude
    Write-Output "$NextCollectionToInclude - Added to master collection..."
}
Else{
    Write-Output "STOP - Success rate only at $PercentSuccess, not ready for next phase!"

} 

So, if i thought about this right, this will take a collection of collections, cycle through them and check against your "MasterCollectionID" (which has TSLauncher and IPU TS deployed to it) if any of them is included, if they are it will be removed from collections that can be included.

It pick the top-most collection ID from those that remain in "$Collections", and add it to "$NextCollectionToInclude". If all your collections, following the naming in "CollectionNames" is already added, it will stop the script, as there are no more to add, and exit 0.

It will then take the percentage-number you set as good enough success-rate when to add another collection to the master, calculate the current success % of the deployment, and compare these two to see if its time to add another collection or not. If the success-rate is higher then "$MinPercentageForNextPhase" it will than go on and add the next collection.

You can either run it from time to time manually, but this kinda ruins the thing with it. Or you set it up as scheduled task on you siteserver, make sure it runs with an account that has edit rights on the "MasterCollection" so the others can be included.

Test it

If you want to test it create one collection named eg. "Test IPU - Test" (make sure you have nothing else named like this, else it might be included aswell!), no members or anything, and the copy it a bunch of times. Then create a "mastercollection" the collection which you would deploy everything to, to try it you can manually include one of the earlier created collections to see that it wont add it again. And then just choose a random deployment to put in "DeploymentID" and set an % above or bellow the current one, run the script once if you want it to calculate the current % for you.

Or just these lines:

$Deployment = Get-CMDeployment -DeploymentId $DeploymentID
$PercentSuccess = ($Deployment.NumberSuccess/$Deployment.NumberTargeted).ToString("P")
GitHub - Love-A/EndpointManagement: Endpoint Management stuff galore!
Endpoint Management stuff galore! Contribute to Love-A/EndpointManagement development by creating an account on GitHub.