Last week I read a forum question about downloading updates in a software update group. I thought that I could create an easy example, but it wasn’t all as easy as I thought it would. As there is no cmdlet available that performs this specific action, I went back to WMI. In WMI there is a method AddUpdateContent in the SMS_SoftwareUpdatesPackage that should do the trick. After playing around with it for a while I noticed that this method is not as straight-forward as it looks.
The main problem I had with this method, was the documentation, or better, the lack of documentation. The SDK only contains a very old example that also doesn’t seem to use the right order for the parameters. Let’s start with what the parameters should be and walkthrough them in the order that they should be used:
- A boolean to indicate whether or not the content has to be replicated to the distribution points.
- An array that contains the IDs of the content that has to be added to the deployment package.
- An array that contains the source path where the content files are located.
- Note: The content of the updates have to be downloaded to a local, or network path already.
With these three parameters, it is possible to invoke the AddUpdateContent method, of the SMS_SoftwareUpdatesPackage class on a specific PackageID. An easy way to do that would be invoking the method on the WMI object path to the specific deployment package. This makes the following example:
Invoke-WmiMethod -Path "\\$($SiteServer)\root\sms\site_$($SiteCode):` SMS_SoftwareUpdatesPackage.PackageID='$PackageID'" ` -Name AddUpdateContent ` -ArgumentList @($false,$UpdateContentIDs,$UpdateContentSourcePaths)
To use this method it’s necessary to fill those parameters and to do that it’s necessary to collect some information. As I don’t think it’s very user-friendly to supply a CI ID as a function parameter, I will first search the CI ID of the software update group based on its display name in the SMS_AuthorizationList class.
$UpdateGroupCIID = (Get-WmiObject -Namespace root/SMS/site_$($SiteCode)` -ComputerName $SiteServer -Query "SELECT * FROM SMS_AuthorizationList ` WHERE LocalizedDisplayName='$SoftwareUpdateGroup'").CI_ID
With that CI ID I can find the software updates that are a member of the software update group. The easiest way to do that is to “join” the SMS_CIRelation class with the SMS_SoftwareUpdate class. This will provide a list with all the software updates that are a member of the specific software update group (a big thanks here to the SMSProv.log for providing me with the main part of the query).
$Updates = Get-WmiObject -Namespace root/SMS/site_$($SiteCode) ` -ComputerName $SiteServer -Query "SELECT upd.* FROM SMS_SoftwareUpdate` upd, SMS_CIRelation cr WHERE cr.FromCIID='$UpdateGroupCIID' AND` cr.RelationType=1 AND upd.IsContentProvisioned=0 AND upd.CI_ID=cr.ToCIID"
After finding the updates we can use the CI ID of the updates to find the associated content information. To get this information the easiest and quickest way is to use a “join” again, but this time between the SMS_CIToContent class and the SMS_CIContentFiles class. This will provide a list with the source locations of the software updates.
$UpdateContent = Get-WmiObject -Namespace root/SMS/site_$($SiteCode) ` -ComputerName $SiteServer -Query "SELECT fil.* FROM SMS_CIToContent ` con, SMS_CIContentFiles fil WHERE con.CI_ID='$UpdateCIID' AND ` con.ContentID=fil.ContentID"
The content IDs can now be used to fill the first array of the AddUpdateContent method. The second array has to be filled with the location to were the content IDs are downloaded. The complete script including the missing, and not explained, little bits-and-pieces and including a download function is available via the TechNet Galleries.
Download the complete script and run it with a command line like .\Add-UpdateToPackage.ps1 <DeploymentPackage> <SoftwareUpdateGroup> <SiteCode> <SiteServer>. After the script starts the AddUpdateContent method the result can be followed in the SMSProv.log.