Udostępnij za pośrednictwem


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:

  1. Create prestage content files for all content on the source distribution point
  2. Run the ExtractContent.exe tool on the target DP to load the pre-stage content into the content library
  3. 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.

image

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.

image

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!