Since the release of ConfigMgr Current Branch (version 1511 and onward), the experience of updating ConfigMgr to the latest version has improved in between versions and with 1606 out, it’s better than ever. However, there’s a major piece missing that we’re still not able to perform just yet, which is to invoke an update of ConfigMgr through PowerShell. I’d assume that this is coming in a future release of the Configuration Manager Cmdlets Library, but we’re not there quite yet. In order to get around this, I’ve written a PowerShell script that is able to determine if there’s an update available for ConfigMgr, based on specified version input.

Ryan Ephing recently published a method where he triggers the UpdatePrereqAndStateFlags method on an instance from the SMS_CM_UpdatePackages class (great post Ryan!). I’ve been working on the same method, but added a few more verification steps in order to prevent unnecessary restarts of the SMS_EXECUTIVE service (which sometimes are required when the update package is stuck in the Downloading state, shown in the Updates and Servicing node of the ConfigMgr console).


Since this script is leveraging undocumented classes and methods in the SMS Provider, I’d urge you to use it with caution. Never run this script in your production environment before testing it in a lab environment first. Using the script is quite simply, where you specify your Primary Site server for the SiteServer parameter, a 4 characters long string for the Version parameter (1602 or 1606 for instance). That’s all you have to do basically. However, I’ve added some logic to enter a loop if the script detects that the Update Package found is either being downloaded or that Prerequisites Checks are being executed. To control the loop for these two scenarios, the script has two additional parameters that are not required (and have a default value of 120):

  • AvailabilityCheckCount
  • PrerequisiteCheckCount

By specifying for instance the AvailibilityCheckCount parameter with a value of 60, when the script enters the waiting for Update Package to become Available loop (it downloads before it becomes available). It will performs a sleep operation for 30 seconds up until the count hits what’s specified in AvailibilityCheckCount. When the loop hits 60, it will perform a restart of the SMS_EXECUTIVE service, hopefully bringing the Update Package out of the Downloading state, let it download if it hasn’t yet. The script will then continue when the state has changed to Available.

The same logic applies for the PrerequisitesCheckCount parameter, that is used in a loop to determine when the state has changed to Installing from Running Prerequisites Checks. Before this loop is entered though, the script has trigged the available Update Package to be installed.

In my lab environment, I have access to a rather fast pipe and therefor the download of the EasySetupPayload (Update Package, e.g. 1606) doesn’t take that much time (about a minute or so). This means that using the default counts for both the AvailibilityCheckCount and PrerequisitesCheckCount makes little sense. However, in an environment where the download of an Update Package may take some time (let’s say more than 1 hour), I’d advice that you don’t use the default values of these two parameters, and instead set your own values that suits your environment.

NOTE! Always perform the update and servicing of ConfigMgr from your top site server in your hierarchy. This applies when running this script as well.


You can grab the script from below and save it as e.g. Invoke-CMUpdatePackage.ps1. I’ve also uploaded it to my GitHub repository, if you want to grab it from there instead.

    Start installation of a Configuration Manager Update Package (servicing model for Current Branch)

    This script will attempt to start the installation of a specific version of Configuration Manager Current Branch.
    If an Update Package is available for the specified version of Configuration Manager, the Update Package will be validated
    for availability before any installation is started. The script supports restarting SMS_EXECUTIVE in the event that the
    Update Package is stuck in the Downloading state. You can control the amount of availibility checks to be performed with the
    AvailibilityCheckCount parameter, before the service is restarted. Default is 120.

    Site server name with SMS Provider installed.

    Specify a Configuration Manager version that should be installed. Valid format is e.g. 1602 or 1606.

.PARAMETER AvailabilityCheckCount
    Specify how many times the script will check if an UpdatePackage is available for installation.

.PARAMETER PrereqCheckCount
    Specify how many times the script will check if the prerequisite checks has completed for an UpdatePackage.

    Attempt to start the installation of Configuration Manager 1606, on a Primary Site server called 'CM01':
    .\Invoke-CMUpdatePackage.ps1 -SiteServer CM01 -Version 1606

    FileName:    Invoke-CMUpdatePackage.ps1
    Author:      Nickolaj Andersen
    Contact:     @NickolajA
    Created:     2016-08-06
    Updated:     2016-08-06
    Version:     1.0.0
    [parameter(Mandatory=$true, HelpMessage="Site server where the SMS Provider is installed.")]
    [ValidateScript({Test-Connection -ComputerName $_ -Count 1 -Quiet})]

    [parameter(Mandatory=$true, HelpMessage="Specify a Configuration Manager version that should be installed. Valid format is e.g. 1602 or 1606.")]
    [ValidateScript({$_.Length -eq 4})]

    [parameter(Mandatory=$false, HelpMessage="Specify how many times the script will check if an UpdatePackage is available for installation.")]
    [int]$AvailabilityCheckCount = 120,

    [parameter(Mandatory=$false, HelpMessage="Specify how many times the script will check if the prerequisite checks has completed for an UpdatePackage.")]
    [int]$PrerequisiteCheckCount = 120
Begin {
    # Determine SiteCode from WMI
    try {
        Write-Verbose -Message "Determining Site Code for Site server: '$($SiteServer)'"
        $SiteCodeObjects = Get-WmiObject -Namespace "root\SMS" -Class SMS_ProviderLocation -ComputerName $SiteServer -ErrorAction Stop
        foreach ($SiteCodeObject in $SiteCodeObjects) {
            if ($SiteCodeObject.ProviderForLocalSite -eq $true) {
                $SiteCode = $SiteCodeObject.SiteCode
                Write-Verbose -Message "Site Code: $($SiteCode)"
    catch [System.UnauthorizedAccessException] {
        Write-Warning -Message "Access denied" ; break
    catch [System.Exception] {
        Write-Warning -Message "Unable to determine Site Code" ; break
Process {
    # Define update check variables
    $UpdateCheckCount = 0
    $PrereqCheckCount = 0
    $UpdatePackageAvailibility = $false

    # Check for an available UpdatePackage matching the specified version
    $CMUpdatePackage = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_CM_UpdatePackages -ComputerName $SiteServer -Filter "(Name like 'Configuration Manager $($Version)%') AND (UpdateType = 0) AND (State != 196612)" -Verbose:$false
    if (($CMUpdatePackage | Measure-Object).Count -eq 1) {
        do {
            # Increment UpdateCheckCount

            # Query SMS_CM_UpdatePackages WMI class for UpdatePackage instance
            Write-Verbose -Message "Configuration Manager Servicing: Attempting to locate Update Package in SMS_CM_UpdatePackages matching 'Configuration Manager $($Version)'"
            $CMUpdatePackage = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_CM_UpdatePackages -ComputerName $SiteServer -Filter "(Name like 'Configuration Manager $($Version)%') AND (UpdateType = 0)" -Verbose:$false

            # Determine whether UpdatePackage is available for installation
            if ($CMUpdatePackage -eq $null) {
                Write-Verbose -Message "Configuration Manager Servicing ($($UpdateCheckCount) / $($AvailabilityCheckCount)): UpdatePackage was not found matching 'Configuration Manager $($Version)', sleeping for 30 seconds"
            else {
                Write-Verbose -Message "Configuration Manager Servicing ($($UpdateCheckCount) / $($AvailabilityCheckCount)): UpdatePackage found, validating if $($CMUpdatePackage.Name.TrimEnd()) is ready for installation"
                switch ($CMUpdatePackage.State) {
                    327682 {
                        Write-Verbose -Message "Configuration Manager Servicing ($($UpdateCheckCount) / $($AvailabilityCheckCount)): UpdatePackage state is Downloading, sleeping for 30 seconds"
                        if ($UpdateCheckCount -eq $AvailabilityCheckCount) {
                            Write-Verbose -Message "Configuration Manager Servicing ($($UpdateCheckCount) / $($AvailabilityCheckCount)): Downloading state detected for longer than $($AvailabilityCheckCount * 30 / 60) minutes, restarting SMS_EXECUTIVE service"
                            if ($PSCmdlet.ShouldProcess("SMS_EXECUTIVE", "Restart")) {
                                Restart-Service -Name "SMS_EXECUTIVE" -Force -Verbose:$false
                            $UpdateCheckCount = 0
                    262146 {
                        Write-Verbose -Message "Configuration Manager Servicing ($($UpdateCheckCount) / $($AvailabilityCheckCount)): UpdatePackage state is Available, attempting to initiate installation of $($CMUpdatePackage.Name.TrimEnd())"
                        $UpdatePackageAvailibility = $true

            # Wait until UpdatePackage is available
            if ($UpdatePackageAvailibility -eq $false) {
                Start-Sleep -Seconds 30
        while ($CMUpdatePackage.State -ne 262146)

        # Initiate UpdatePackage installation
        Write-Verbose -Message "Configuration Manager Servicing: Starting prerequisite checks for $($CMUpdatePackage.Name.TrimEnd())"
        $CMUpdatePackage = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_CM_UpdatePackages -ComputerName $SiteServer -Filter "(Name like 'Configuration Manager $($Version)%') AND (UpdateType = 0)" -Verbose:$false
        if ($CMUpdatePackage -ne $null) {
            if ($PSCmdlet.ShouldProcess($CMUpdatePackage.Name.TrimEnd(), "Install")) {
                $CMUpdatePackage.UpdatePrereqAndStateFlags(0,2) | Out-Null

        # Wait for prerequisite checks to complete, state 196609 equals Installing
        do {
            # Increment PrereqCheckCount

            # Query for UpdatePackage instance to get State for prerequisite checks
            if ($PrereqCheckCount -eq $PrerequisiteCheckCount) {
                Write-Verbose -Message "Configuration Manager Servicing ($($PrereqCheckCount) / $($PrerequisiteCheckCount)): Prerequisite checks has been in running state for $($PrerequisiteCheckCount * 30 / 60) min, restarting SMS_EXECUTIVE service"
                if ($PSCmdlet.ShouldProcess("SMS_EXECUTIVE", "Restart")) {
                    Restart-Service -Name "SMS_EXECUTIVE" -Force -Verbose:$false
                $PrereqCheckCount = 0
            else {
                Write-Verbose -Message "Configuration Manager Servicing ($($PrereqCheckCount) / $($PrerequisiteCheckCount)): Waiting for prerequisite checks to complete for $($CMUpdatePackage.Name.TrimEnd()), sleeping for 30 seconds"
                $CMUpdatePackage = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_CM_UpdatePackages -ComputerName $SiteServer -Filter "(Name like 'Configuration Manager $($Version)%') AND (UpdateType = 0)" -Verbose:$false

                # Wait until UpdatePackage prerequisite checks has completed
                Start-Sleep -Seconds 30
        while ($CMUpdatePackage.State -ne 196609)

        # Output that Configuration Manager Servicing has begun
        Write-Verbose -Message "Configuration Manager Servicing: Installation was successfully initated for $($CMUpdatePackage.Name.TrimEnd()), for more details, review the CMUpdate.log"        
    elseif (($CMUpdatePackage | Measure-Object).Count -gt 1) {
        Write-Warning -Message "Query for Update Packages returned more than 1 instance, please define your search with a specific version"
    else {
        Write-Warning -Message "Query for Update Packages did not return any instances"


You’d run this script like any other script that I’ve created, by opening a PowerShell console, browsing to location where you’ve stored it and then simply call it with a set of parameters. See an example below:

.\Invoke-CMUpdatePackage.ps1 -SiteServer CM01 -Version 1606

By adding the Verbose parameter to the command above, you’ll get some detailed information on what’s currently going on. If not, the script will simply just hang there until it’s capable of initiating the update package for installation. When you run the script, you’ll see that it’s looking for an Update Package. If an eligible Update Package is found, it will check the current state and determine the proper action, like shown in the picture below:

If the script determines that it have to restart the SMS_EXECUTIVE service, hopefully the download process for the Update Package should begin, like shown in the picture below:

Finally, when the Update Package has been downloaded and the prerequisites checks have been completed, the script will then quit once the state has been changed to Installing, meaning that the Update Package for ConfigMgr is being serviced and installed, like shown below:

You can now follow the installation progress for the Update Package in CMUpdate.log.


As you may have understood from reading the documentation part for this script, it’s probably “faster” to just leverage the ConfigMgr console to update to the desired version of ConfigMgr. So why should you use this script? To be honest, I’d be very careful when using it in your production environment, however, in a lab environment it makes more sense to be able to have an automated build of ConfigMgr that brings you to the latest bits. This script will help you accomplishing that, but depending on your environment, it could take a little while for it to initiate the update and servicing. Please let me know if you have any issues with this script, as it’s a work in progress and also due to the fact that the Updates and Servicing feature in ConfigMgr is always improving.

Nickolaj Andersen
Principal Consultant and Enterprise Mobility MVP since 2016. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows devices and deployments including automation. Currently working for TrueSec as a Principal Consultant. Awarded as PowerShell Hero in 2015 by the community for his script and tools contributions. Creator of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService to name a few. Frequent speaker at conferences and user groups.


  • René Kierstein
    Posted at 08:41 November 21, 2016
    René Kierstein

    Hi Nikolaj, great post and I agree with you we need an officiel cmdlet to handle the upgrade servicing.

    Did you test your script if it works with the KB’s offered in the servicing node? e.g

    • Nickolaj
      Posted at 08:55 November 25, 2016

      Hi Rene,

      I’ve only tested and verified for Update Packages, but essentially there should be no difference if they’re also made available in the same class.


  • Leave a Reply