Is there a way to script the installation of System Center Configuration Manager updates listed in Software Center?

We have a very tight outage window and for many of our systems, the servers must be rebooted in the correct order. Because of this, I would like to script our updates.

I have attempted to use this Powershell script found in the Microsoft Script Repository, however, for me it does not work remotely, doesn't always work using Invoke-Command and it starts the installation then returns without waiting for installation to complete. I would like each system rebooted after the installations are complete, this is difficult to script without the installation blocking or status information to block upon. After spending far too much time, attempting to make the CCM_SoftwareUpdate and CCM_SoftwareUpdatesManager WMI classes do what I need, I thought it was time to ask how others might be handling similar situations.

A friend of mine says his company solved this problem by using Shavlik, unfortunately, that is not an option here.

We are using SCCM 2012 and have a mix of 2003, 2008 and 2012 servers.


Yes. You can do this with powershell similar to what the script you posted tries to do. I came across that script a while back, can't remember if it worked or not but I did get something to work. don't know why his wouldn't work, it does use the same methods, but I was able to do this with .NET and WMI using C#, so I know it can be done with powershell.

private void InstallUpdates()
    {
        ManagementScope sc = new ManagementScope(@"\\.\root\ccm\clientsdk");
        ManagementClass c = new ManagementClass(@"CCM_SoftwareUpdatesManager");
        ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM CCM_SOFTWAREUPDATE WHERE COMPLIANCESTATE=0 AND EVALUATIONSTATE < 2");
        c.Scope = s.Scope = sc;

        ManagementObjectCollection col = s.Get();
        List<ManagementObject> lUpdates = new List<ManagementObject>();

        //Install each update individually and display progress
        int index = 1;

        //double progress = 5/10;

        //progressBar1.Value = progress;
        //this.Enabled = false;

        foreach (ManagementObject o in col)
        {

            System.Management.ManagementBaseObject[] args = { o };

            object[] methodArgs = { args };

            c.InvokeMethod("InstallUpdates", methodArgs);

            lblCurrentUpdate.Text = "Now Installing Update " + index + " of " + col.Count;

            UInt32 evalState = 0;
            progressBar1.Value = (int)(((index) / (double)col.Count)*100.0);

            //isCompleted = false;
            //backgroundWorker1.RunWorkerAsync(o);

            while (evalState < 7)
            {

                try
                {
                    o.Get();
                    evalState = (UInt32)o.Properties["EvaluationState"].Value;
                }

                catch (Exception ex)
                {
                    break;
                }

            }

            ++index;

        }

        //this.Enabled = true;

        //Restart Workstation
        System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0 -f");

        Application.Exit();

    }

In a nutshell, I used the WMI query "SELECT * FROM CCM_SOFTWAREUPDATE WHERE COMPLIANCESTATE=0 AND EVALUATIONSTATE < 2" and passed each update one by one to the InstallUpdates method, because I wanted to display the progress similar to how Microsoft does it. You must pass an array to the InstallUpdates method, even if you're only passing a single update object. You could pass the entire returned array if you want, and it will queue them up like it always does, installing them one by one.

Also, what about configuring a maintenance window for this collection, and telling sccm not to install updates outside the maintenance window? When one update is finished, if it's past the maintenance window then it will stop installing updates (in theory for me, I've never had the maintenance window luxury).

if you're a gimmiedehcodez kinda person, that code should compile in with .NET 4.0 and

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Management;
using System.Windows.Forms;

More info on the CCMClientSDK here


Here is what I put together from various web pages. Using Powershell. Please note that you will have better success using WinRM (winrm quickconfig on the remote servers to enable WinRM) which can use the Invoke-Command cmdlet instead of the Invoke-WmiMethod but this method works for me on Server 2008 and newer. For Server 2003, the Updates deployment evaluation scan works but Powershell will complain about something. Run the commands locally to work around that.

#Start the System Center Configuration Manager Software Updates Deployment Evaluation Scan
$trigger = '{00000000-0000-0000-0000-000000000108}'
$scan = Invoke-WmiMethod -ComputerName $server -Namespace root\ccm -Class sms_client -Name TriggerSchedule $trigger

[System.Management.ManagementObject[]] $CMMissingUpdates = @(GWMI -ComputerName $server -query "SELECT * FROM CCM_SoftwareUpdate WHERE ComplianceState = '0'" -namespace "ROOT\ccm\ClientSDK") #End Get update count.
(GWMI -ComputerName $server -Namespace "root\ccm\clientsdk" -Class "CCM_SoftwareUpdatesManager" -List).InstallUpdates($CMMissingUpdates)