Migrating the Content Library between Distribution Points in SCCM 2012 SP1
I recently had a very good question from one of my customers regarding how to migrate content from one DP to another, avoiding the need to re-distribute content over the WAN. In the SMS 2003 and SCCM 2007 days, we used the preloadpkgonsite.exe tool to accomplish the job. With the switch to the content library in SCCM 2012, however, that is no longer an option. In today’s blog, we’re going to cover how to accomplish this same task with PowerShell. If you would like to download the script to follow along, you can find it in the Technet Gallery.
The process for migrating content from the content library of one DP to another can be broken down into three basic steps:
- Create prestage content files for all content on the source distribution point
- Run the ExtractContent.exe tool on the target DP to load the pre-stage content into the content library
- Assign the content for distribution to the target DP
The workhorse for step 1 of this task will be the new “Publish-CMPrestageContent” commandlet released with the SP1 update of the SCCM PowerShell module. This commandlet was not around in the RTM release of SCCM 2012, so you must be on SP1, at a minimum.
Before we get too heavily into the code, a couple of prerequisites should be mentioned.
First, the PowerShell module for Configuration Manager is a 32-bit module, so you will need to make sure you are running the 32-bit version of PowerShell.
Second, the Publish-CMPrestageContent command will actually download the content from the source DP to the computer that is running the PowerShell module. If you run this command from your workstation that is across the WAN, it will have the unintended consequence of transferring all of our package content across the WAN as well. To avoid this, you will need to have the SCCM console installed on the DP you will be using as your source DP.
Third, our script uses environment variables to automatically detect where the console is installed. This allows us to handle cases where it is not installed to the default folder, but requires that the environment variable has been created on the system. If you have freshly installed the SCCM console, you’ll need to log out and back in to ensure that the environment variable can be read by PowerShell.
Step 1) – Create prestage content files
In our example script, we’ll execute the script in prestage mode with the required parameters:
PS C:\>.\CloneDP.ps1 -Prestage -SourceDP sccm01.contoso.com -TargetDP
DP01.contoso.com -ContentShare \\dp01.contoso.com\c$\pkgx
In this example, we’re cloning all of the content from the SCCM01 DP to the DP01 DP. The prestage files will be put in the “Pkgx” folder on DP02 using the admin share, though you can select any network share on the LAN to store the prestage content that we will later import.
Following along in the example script, you can see that before we can begin creating our prestage commands, we need to grab a list of deployment packages that have been deployed to our source DP so that we can begin to loop through them:
$DeploymentPackages = Get-CMDeploymentPackage -DistributionPointName $SourceDP
One of the key things to note with the Publish-CMPrestageContent commandlet is that there is a different parameter you must specify depending on the type of content you are prestaging. As a result, we’ll use a variable ($command) and build the command syntax as we go along. To start, we’ll add the commandlet to the variable:
$command = "Publish-CMPrestageContent "
We can then use a switch statement to build the parameters required depending on what type of deployment package we are currently working with:
Switch ($DeploymentPackage.ObjectTypeID) {
2 { $command += "-PackageID $($DeploymentPackage.PackageID) " }
14 { $command += "-OperatingSystemInstallerId $($DeploymentPackage.PackageID) "}
18 { $command += "-OperatingSystemImageId $($DeploymentPackage.PackageID) "}
19 { $command += "-BootImageId $($DeploymentPackage.PackageID) "}
23 { $command += "-DriverPackageID $($DeploymentPackage.PackageID) "}
24 { $command += "-DeploymentPackageID $($DeploymentPackage.PackageID) "}
31 { $command += "-ApplicationName '$($DeploymentPackage.Name)' "}
}
All of the parameters for the various content types will use the PackageID to identify what content we are looking to prestage, with the exception of the Application content type. In this case, the application name is the most easily accessible property gathered by the Get-CMDeploymentPackage commandlet, so we use that instead. See the table below for a list of ObjectTypeIDs and the content types they refer to:
Name |
PackageType |
Package |
2 |
Driver Package |
23 |
Task Sequence Package |
20 |
Software Updates Package |
24 |
Device Setting Package |
21 |
Virtual App |
31 |
Application |
31 |
Image Package |
18 |
Boot Image Package |
19 |
Operating System Install Package |
14 |
Finally, we can add the parameters that are universal to all of the various content types. For these parameters, we’ll have the pre-stage file initially created in the %temp% folder and get the content from the source DP passed via the script parameters:
$command += "-FileName '$($env:TEMP)\$($DeploymentPackage.PackageID).pkgx'” `
+ “ -DistributionPointName $($SourceDP)"
Now that our command syntax is fully built, we’ll call the command using Invoke-Expression before finally using Move-Item to move the prestage file to a share on our target DP:
Invoke-Expression $command
Move-Item "$($env:TEMP)\$($DeploymentPackage.PackageID).pkgx" `
"$($ContentShare)\$($DeploymentPackage.PackageID).pkgx" -Force
At this point, we should have a folder full of prestage content files on our target DP that should look something like the image below.
Step 2) – Extract the prestage files
For this step we’re going to use the ExtractContent.exe utility that is automatically installed when you install the DP role on a server. It will be located in the tools folder in the DP install directory, which in our case is “c:\SMS_DP$\sms\Tools\ExtractContent.exe” . If you have UAC enabled, be sure to run your command prompt with administrative credentials.
As you can see from the image above, the basic argument we want to give the ExtractContent.exe tool is the /P command to point it at our folder of prestage packages. A nice feature to note is that we can point this at either an individual “.pkgx” file or an entire folder of them, which in our case will be “c:\Pkgx”.
We’ll run “ExtractContent.exe /P:c:\Pkgx” to extract the content out of our “.pkgx” files and into the content library. The output isn’t very verbose, but you can monitor the “PrestageContent.log” in the log folder of the DP install directory while the command is running.
Once everything is complete and you have reviewed the “PrestageContent.log” file, you can delete the folder containing all of your “.pkgx” files, as they are no longer needed.
Step 3) – Assign content to your target DP
If you are using distribution point groups to assign your content rather than selecting individual DP’s, at this point you can add the target DP to the distribution point group. Otherwise, we’ll use the finalize mode of the sample script to target all of the content that has been prestaged to the target DP. Using either method will utilize the extracted content on the target DP rather than re-distributing the files from the primary site.
PS C:\>.\CloneDP.ps1 -Finalize -SourceDP SCCM01.contoso.com
-TargetDP DP01.contoso.com
When in finalize mode, we once again use the Get-CMDeploymentPackage to get a listing of packages on the source DP. We will once again use the $command variable to build our syntax:
"Start-CMContentDistribution "
The Start-CMContentDistribution commandlet uses the same parameters to identify the content ID as the Publish-CMPrestageContent commandlet, so we reuse the same switch statement to include those parameters into our command line.
Finally, we complete the $command string with the target DP and then Invoke-Expression to initiate the deployment:
$command += "-DistributionPointName $($TargetDP)"
Invoke-Expression $command
Get the code!
If you haven’t already done so, you can grab the code for the sample script from the TechNet Gallery!
Comments
Anonymous
January 01, 2003
@Kathrynjl, Yes, this is the best use case for my process, at this point. If you are going to have both DPs online at the same time and you are at least SP1, it makes more sense to just use a PullDP to migrate the packages. If, as in your case, the servers won't exist at the same time (or the same name is being used) you should do step 1, perform your hardware refresh, then complete steps two and three on the new hardware.Anonymous
January 01, 2003
The comment has been removedAnonymous
January 01, 2003
The comment has been removedAnonymous
January 01, 2003
I am running Step 1, Create prestage content files and after about 6 or 7 hours the script stops and returns a command prompt. No errors in the log. It just hasn’t processed all of the content. It looks like it prestaged 995 packages. Is there a resultset size or OutBuffer switch that needs to be set?Anonymous
January 01, 2003
The comment has been removedAnonymous
August 02, 2013
The comment has been removedAnonymous
August 05, 2013
I found this very helpful. The easy-to-follow instructions guided me through with ease. Thank you, Ken!Anonymous
September 17, 2013
This worked out nicely, but driver packages fail during the extraction process.Anonymous
July 04, 2014
Great script, thank you :)
Regarding pull-dps, I also thought that would be much simpler, but unfortunately it does not work when using HTTPS (well it does, if you are willing to mess around with the SDK and WMI...)Anonymous
September 15, 2014
The comment has been removedAnonymous
December 02, 2014
The comment has been removedAnonymous
February 13, 2015
Thanks its been very useful. I do have a question would this script allow me to perform a prestage of content if the files have been restore from backup?Anonymous
May 20, 2015
The comment has been removedAnonymous
August 16, 2015
The comment has been removed