Automating Software Updates

Published Jan 21 2019 06:29 PM 1,008 Views

First published on MSDN on Jun 11, 2014

The monthly process of preparing and deploying software updates is familiar territory for every ConfigMgr administrator. But, monthly software update management is not only about deployment. Maintenance of the software update environment is a critical activity needed to foster ongoing predictable and healthy operation. The amount of monthly time invested in deployment and maintenance will vary by environment but it is safe to say an average at least 2-6 hours per month is not unrealistic.


Most environments that I’ve seen perform monthly software update tasks manually. The tasks required for software update management are generally the same month after month and involve acquiring the updates, adding the updates to appropriate software update groups, creating deployments as needed, validating software update groups are purged of expired and, in some cases, superseded patches and, finally, validating the updates in the various deployment packages remain valid in the environment. There may also be a need to evaluate deployments or a collection to determine updates being managed in a certain scenario. Any time there are administrative tasks that are routine the opportunity for automation should be considered. That is definitely the case for software update maintenance. In fact, Automated Deployment Rules, automation already built into ConfigMgr 2012, work to address the first two maintenance items. One question that may arise is ‘why automate’? Isn’t it better for administrators to manually vet the content that is being deployed or to do maintenance manually so errors can be avoided? Ah, exactly the point. Automation, done correctly, eliminates human error and frees up administrative time for other less routine tasks. And, to me, building and maintaining the automation is far more interesting than monthly performing the same tasks again and again.


This discussion will demonstrate several potential automation points in the software update management process. The goal of this discussion is NOT to provide carte blanche automation mechanisms for production use but to demonstrate automation in action and spur thinking about how the automation examples could be tweaked for a specific environment and how automation can bring about efficiency for any environment.


For the discussion seven sample PowerShell scripts will be presented. For automation purposes these sample scripts could be leveraged standalone, deployed through ConfigMgr to run on a recurring schedule, set as scheduled tasks, leveraged through an Orchestrator workflow or using whatever other trigger mechanism would be of interest. These scripts were created using the PowerShell ISE interface and executing against a ConfigMgr 2012 R2 infrastructure. No testing was done to vet these scripts may with previous versions of ConfigMgr.


NOTE: Scripts are provided as samples only! They are provided ‘as is’ without warranty. They are not intended for use in any specific production setting but are provided as illustration of what could be automated and to stimulate your own ideas. Any script should be fully evaluated, tested and modified for specific environments before implementation.


NOTE: All sample scripts are written to run on the site server directly!


This script could be leveraged in environments that deploy software updates leveraging pairs of software update groups. The first member of the pair, shown here as monthly, would be a group containing the set of updates to be deployed for the current month. The second member of the pair, shown here as persistent, would be a group used for ongoing deployment of updates that have been in the environment for a while. The idea of this approach is that the monthly group will contain new updates that have never been in the environment where it is expected to see compliance rapidly rise after deployment while the persistent group will contain updates that should already be deployed in the environment but need to remain deployed to cover any systems that might get added to the network and need to be patched or to handle reimaged systems. With the persistent group the expectation is that the compliance values will remain fairly static.


Many customers use this type of strategy but with their own tweaks to make it fit for them. For example, some prefer to use a quarterly group instead of monthly and some prefer to have group pairs by operating system that needs to be patched. I prefer the later approach – organizing by operating system. Why? The main reason is ensuring that deployments are only ever targeted to systems that actually might need the deployment. In terms of software updates then that means only targeting Windows 8 patches to Windows 8 machines, Windows 2012 patches to Windows 2012 machines and so on. Operating in this manner achieves the goal of properly scoping update deployment and also gives the advantage of being able to track compliance by operating system at a glance. Of course, such an approach could be taken to the extreme where multiple update groups within a class of operating systems are leveraged. Such an approach would quickly become unwieldy. After all, the ConfigMgr client is capable of sorting out applicability of patches so even if an update is targeted that doesn’t apply it will not be loaded. And, this approach mindset really only works for operating system specific updates. There are a number of updates that could equally apply to Windows 8, Windows 7, Windows 2012, etc. The .NET updates or application updates are great examples of this. Because of this another update group pair – one for updates that are not operating system specific – makes sense.


When using the update group pair approach there is routine maintenance that will need to be done. Maintenance should factor proper handling of expired updates, proper handling of superseded updates and proper handling of updates exceeding a specific age threshold. In the monthly/persistent example maintenance would need to be done each month to move the updates in the monthly group to the persistent group so the monthly group is clear and ready to deploy the next batch of updates. Performing this type of maintenance is typically done manually. Instead of manual operation the desire is to bring automation to bear! On to the script.


The UpdateGroupPairMaintenance.ps1 script allows the administrator to manage the pair of update groups and optionally remove expired updates, optionally remove superseded updates and optionally manage aged updates from one group to another. In the example there are a number of updates in the monthly update group but currently none in the persistent group. In the monthly group the expired updates are highlighted in yellow, the superseded updates are highlighted in pink and the aged updates are highlighted in purple. Note that for this sample run the script is configured to consider any update over 1 days in age to be beyond the age threshold. In production the value would be longer.



The persistent update group does not currently contain any members. In production this would not likely be the case but is good to show as an example.



With this configuration it is time to run the script to perform maintenance. In this run the script will be configured to purge expired and superseded updates and to move any update that is older than 1 day to the persistent update group.


NOTE: In most production environments the persistent group would already contain updates. In that case the persistent group would also be purged of expired or superseded updates based on the configuration.



If the update groups are reviewed post script execution the changes are evident. Monthly is now empty – because all of the updates there were either expired, superseded or outside of the age threshold (since the age threshold was artificially set to 1 day) - and the persistent group now contains the aged updates but none that were expired or superseded. This now resets the monthly update group to receive the next batch of updates without a need to manually track those that have been expired, superseded or aged out of consideration.




This script is identical to the one just described except that the focus is simply the maintenance of an individual software update group. This script is applicable to those environments that choose not to leverage software update group pairs but would still like to use automation to maintain group membership.


This script is designed to run routinely to flag any update groups that are approaching the 1000 update per deployed update group limit. Instead of being surprised when deployments cannot be configured or when Automated Deployment Rules fail due to the number of updates in a group this script will examine every deployed update group to determine if each contains greater than 900 updates (by default) and, if so, will note that group in the output. While the script itself does not do any type of email alerting it would be very easy to add this script to an Orchestrator workflow that would send an email alerting to the potential problem if it is encountered.



NOTE: The script will only scan deployed software update groups. Having greater than 1000 updates in a software update group that is NOT deployed is permitted and has potential uses in reporting as will be discussed next. It is important also to note that Automated Deployment Rules ALWAYS configure a deployment so when update group membership exceeds 1000 updates Automated Deployment Rules configured against that update group will always fail even if configured to create disabled deployments.


Some organizations prefer to maintain a top level software update group for the purpose of reporting. This group is not and never will be deployed. The membership of this reporting group is a composite of all updates configured in any software update group in the environment. The challenge with this approach is making sure the membership of this top level group truly reflects the membership of all other groups. This script helps ensure this is the case by scanning every software update group other than the target group for reporting purposes and editing membership to reflect the software updates found in the other groups. As presented this script does not check to see if a group is deployed before combining updates into the reporting group but could easily be modified to make such a distinction and an example of testing a group to validate whether it is deployed is available in the EvaluateNumberofUpdatesinGroups.ps1 script.


A sample run of the script will show how it works. In the test environment there are five update groups, monthly, persistent, base, test accuracy and reportinggroup. Each group contains members as shown. Note that there are some members in common but there are others that are unique to the group they are in. When executed the script should result in the reportinggroup containing a composite membership based on all of the groups.







The script is executed and the result is as shown.






Many ConfigMgr administrators spend hours every month simply creating the required deployments for their environment. Often these deployments differ very little from the previous month. The task of creating deployments is very routine and can get boring. Accordingly, a great candidate for automation to remove monotony and potential human error. For the example script a text file is used as input. The idea of this text file (or the script could be changed to leverage an excel spreadsheet, SharePoint website or whatever other input mechanism is preferred) is to provide a single non-ConfigMgr place to store all configurations for software update deployments.



If tweaks need to be made it is very easy to change the text file. The sample text file contains three items – the name of the update group for the deployment, the name of the deployment being created and the target collection. Each of these values is separated by a comma. There are many other options that can be specified for a deployment so it may be that extending the text file is desired. That is very easy to do. Simply adjust the text file as needed and then adjust the section of the script where the text file contents are processed to accommodate the new additions. Then simply pass those items to the appropriate cmdlet parameter.


ForEach ($Detail in $DeploymentDetail)
$UpdateGroupName = $Split[0]
$DeploymentTitle = $Split[1]
$TargetCollection = $Split[2]


Start-CMSoftwareUpdateDeployment -SoftwareUpdateGroupName $UpdateGroupName -CollectionName $TargetCollection -DeploymentName $DeploymentTitle -Description "Deployment Created by Powershell" -DeploymentType Available -VerbosityLevel AllMessages -TimeBasedOn UTC -DeploymentAvailableDay 2014/1/1 -UserNotification DisplayAll -DownloadFromMicrosoftUpdate $True -AllowUseMeteredNetwork $False


Executing the script is very easy and results in the configured deployments being created, as shown. It is important to understand that deployments cannot be created for a software update group where any update content has not been downloaded – so be sure that is taken care of. If the deployment attempt has been made and there were updates in the target update group where content had not been downloaded then the deployment creation would have failed and a message would have been logged indicating that some content had not been downloaded yet.





As environments age it is probable that clutter will persist in certain places that should be cleaned up. That is certainly the case for software updates. It could be, for example, that there are updates remaining in the update deployment packages that are not configured in any software update group. The reverse could also be true – that updates exist in the software update groups but do not exist in any deployment packages. Both situations are cause for concern. In the former the deployment package contains unnecessary updates consuming space on distribution points and, in the case of an expired update, potentially causing issues with compliance results. In the latter case updates in update groups but not in deployment packages may cause compliance results to be reduced more than needed since some updates that may be targeted can’t be deployed because content is not available. This script is designed to address both situations. In the first case where updates are in a deployment package but not in any update groups the script will remove the mismatched updates from the deployment package and update the distribution point. In the case of updates in update groups but not in deployment packages the script will simply output the results without adding the updates to a deployment package. The choice of which deployment package should contain the updates is an administrator decision.


In the test environment there are two deployment packages, each with updates that are not contained in software update groups.




Reviewing the source directory for one of the deployment packages, Deployment Package 2, reveals quite a number of folders present even though there are only 6 updates. This is because there is not always a 1:1 relationship between the updates that appear in the console and the downloaded content. Deployment Package 2 is shown here because every update in this group should be purged when the maintenance script is run and it will be easier to check the results vs. leveraging Deployment Package 1 where some updates will remain.


As we run the cleanup script our hope is to purge any mismatched updates from the console AND from the deployment packages.



Wait! What is that ugly red – must be an error! Never fear, the script operated as expected. From time to time you may see an error like this. When encountered do be sure to check script operation. But this really shouldn’t be a big deal and doesn’t happen all the time. Referring to the MSDN article on the removecontent method used in the script we see that in some cases this method reports an error in VBScript so not totally surprised that happens here too.


To accommodate for this possibility the script was adjusted to continue in the event of an error just ahead of calling this method and then reset to stop on error just after this method is finished. The line where the script is configured to continue is as follows.


$ErrorActionPreference = "Continue"


The results of this run of the script clearly show that the process worked as expected. Both deployment packages are cleaned up and the source directory is purged as well.







This script is designed to take one or more collection ID’s as input and then loop through the list of collections to determine what software update deployments are targeted to them. The script will the list out all updates in the deployments. A specific scenario where this script is useful would be for environments where a different business unit has a need to know specifically what updates have been deployed to their systems. In this case the deployments for the business groups systems are broken down into 3 collections. To provide the update information the script needs to examine all software update deployments against the specific collections and list out all updates that are in the deployed software update groups while avoiding listing software update groups multiple times (in case a software update group may be deployed to multiple collections that are being scanned).


The collection details are provided in the input text file as shown.



The script runs and stores all output in a file.



The output file lists all of the software update groups deployed to any of the collections and all updates that are members of a given group.



And that’s it! Hopefully your mind is buzzing with automation possibilities! Happy software updating!

Version history
Last update:
‎Apr 07 2020 11:40 AM
Updated by: