Depending on how you’ve automated your monthly patching solution you may be faced with a continuing challenge. How do I keep my software update packages manageable.

Within the community there has always been a lot of discussion and arguments around how content for patches should be provisioned in an environment. I have always fallen on the side of organizing your content has a lot to do with how strong your environment is. The stronger and more organized your environment is with automation the better you can groom and maintain your content.

Lets say we have a simple environment where we only patch our major operating systems. When our ADR’s run we’ve got two options for how to store the content in a software update package. We can either, create a new one, which generates a new package the first time an ADR runs and then uses the same package for every sequential run, or we can manually intervene to update and create a new package every month.

So after doing some research and digging through old notes on ConfigMgr and WMI I came up with an idea on how to automate creation of my own software update packages, update ADRs all with my own naming standard which would allow me to better manage automation for clean up of software update packages in the future.

You can download and test the below PowerShell module to see if it would help you automate your monthly process!

CMUpdateManagement PowerShell

Below is a simple function that confirms the ConfigMgr module is present and then creates a new Software Update Deployment Package and returns the PackageID, this will allow you to run the function and save the returned value to be used later on when we set the ADR Deployment Package.

function New-ADRDeploymentPackage
{
    [CMdletbinding()]
    Param
    (
        [Parameter(Mandatory = $true)]
        [String]$PackageName,
        [Parameter(Mandatory = $true)]
        [String]$Path,
        [Parameter(Mandatory = $true)]
        [String]$Description
    )
    if(Test-Module -ModuleName ConfigurationManager)
    {
        write-Verbose "ConfigurationManager Module is loaded"
        Write-Verbose "Checking if current drive is a CMDrive"
        if((Get-location).Path -ne (Get-location -PSProvider 'CmSite').Path){throw "You are not currently connected to a CMSite Provider Please Connect and try again"}
        write-Verbose "Succesfully validated connection to a CMProvider"
        $PSFriendlyNetworkPath = "FileSystem::" + $Path
        If(Test-path -path $PSFriendlyNetworkPath)
        {
            write-Verbose "Path Exists continue on"
        }
        else
        {
            try
            {
                write-Verbose "Path Does not Exist attempting to create"
                new-item -ItemType Directory -ErrorAction Stop -path $PSFriendlyNetworkPath | out-Null
                write-Verbose "Create new folder for content to exist in"
            }
            catch
            {
                throw "Could not create directory for the new pacakge."
            }
        }
        $PackageName = [String](Get-Date).Year + " - " + [string](Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month) + " - $PackageName" 
        Try 
            {
                Write-Verbose "Attempting to create new package in ConfigMgr"
                $NewPackageID = New-CMSoftwareUpdateDeploymentPackage -Name $PackageName -Description $Description -Path $Path -verbose:$false
                write-Verbose "Package created succesfully"
                return $NewPackageID.PackageID
            }
        catch
            {
                Throw "The Package likely already exists please troubleshoot the existing package."
            }

    }
}

Using this function produces results like this:

Next we need to get the ADR we want to edit so we can update the software update package we want to use so I’ve created ‘Get-ADRInfo” which returns a WMI object that we can then take and use to edit the package information in our final function. Note that you need to provide a site code. The site code would be the three digit code (CAS, PR1,) as examples.

function Get-ADRInfo
{
    [CMdletbinding()]
    Param
    (
        [Parameter(Mandatory = $true)]
        [string]$ADRName,
        [Parameter(Mandatory = $true)]
        [string]$SiteCode
    )
    try 
    {
        $Namespace = "root/sms/site_" + $siteCode
        [wmi]$ADR = (Get-WmiObject -Class SMS_AutoDeployment -Namespace $Namespace | Where-Object -FilterScript {$_.Name -eq $ADRName}).__PATH
        return $ADR 
    }
    catch 
    {
        throw 'Failed to Get ADRInfo'
    }
}

Finally, we can take the PackageID and the ADR information and set the information using the function below.

function Set-ADRDeploymentPackage
{
    [CMdletbinding()]
    Param
    (
        [Parameter(Mandatory = $true)]
        [wmi]$ADRObject,
        [Parameter(Mandatory = $true)]
        [string]$PackageID
        
    )
    try {
        $ContentTemplateXML = $ADRObject.ContentTemplate
        $ContentTemplateXML.ContentActionXML.PackageID = $PackageID
        $ADRObject.ContentTemplate = $ContentTemplateXML.OuterXml
        $ADRObject.Put() | Out-Null
        Write-Verbose "Succesfully commited updated PackageID"
    }
    catch {
        throw "Something went wrong setting the value"
    }

}

A quick review will show that we have created a new Software Update Deployment Package and edited our ADR to use the new package for content, using these functions you should be able to easily create a quick scheduled task to update this on a monthly basis to ensure that your software update packages are kept new fresh and as small as possible without having to manually touch your ADRs.

Something important to note, when you create the package you will still have to assign it for content distribution at this time I have not yet tackled adding the package to the distribution points or groups.

If you test this out in your lab or find it useful let me know! I’ve got several updates for the code planned as time allows!

 

(1093)

Jordan Benzing

Jordan has been working in the Industry since 2009. Since starting he’s worked with Active Directory, Group Policy, SCCM, SCOM and PowerShell. Jordan currently works in the healthcare industry as an SCCM Infrastructure Team lead supporting over 150,000 endpoints. Most recently his focus has been in SQL Reporting for SCCM, creation of PowerShell scripts to automate tasks and PowerBI.

There are no comments.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.