Distribution Point Migration Tool-Kit

, , , , , , , , , , ,
The Distribution Point Migration toolkit can be downloaded from my Technet Gallery HERE
This post is a long time in coming, but creating something robust enough to work in most environments that’s still user friendly (with associated documentation) can take a little bit of time.  In the course of one contract I’ve worked, we realized that we needed a way to convert old Secondary SCCM sites into Distribution Point, but we wouldn’t be given any new servers to migrate to. We also knew that the WAN links connecting these remote sites back to our headquarters were severely lacking.  Our solution was to prestage all the content currently stored on the content libraries so we could strip off all the roles (which would clear the SCCM content library), remove unneeded programs and features, add the servers back as Distribution Point, and then reload the prestaged content so it wouldn’t have to transfer over our unspeakably slow WAN connection. We got a peek at this work with my last post of the SCCM Universal Prestage script, but this post will give you the other pieces of the puzzle.

The Core Functions of Distribution Point Migration Tool-kit

                This is the first function you call if you’re running the Migration Kit from a PowerShell window you didn’t summon up from inside the Configuration Manager console.  This function will verify that you have Administrator rights, will seek out and import the Configuration Manager module, and will map your CMSite PSDrive if you don’t already have it mapped. This function is also called within every other function after a quick check to make sure that the CMSite drive is mapped.  If it isn’t mapped, it calls the Initialize-Toolkit function and maps it.
 Console run without admin rights
Console run without admin rights
After the drive has been created
                The second function in the toolkit will query our primary site server and return a list of all content that is assigned to the distribution point we provided.  There are multiple ways to get this information. I’ve seen it done with Get-CMDeploymentPackage cmdlet since that will also return package type information that we’ll need later.   However, I chose to do it via the SMS_DPContentInfo WMI class because I find that it returns the same level of information, but does so in roughly 1/3 the time.  It also means that you can run the command without needing to be connected to the CMSite drive if you don’t want to fully initialize everything.
 A simple report of package ID’s and names
An example of the data stored by SMS_DPContentInfo
                This is one of the ‘heavy lifters’ of the toolkit.  This function requires a package ID number, the Distribution Point containing the package, and the folder you want it dumped to after creation. What this creates is a PKGX file named with the package ID of whatever you prestaged.  The way it decides what to prestage is based on the PackageType value that comes from WMI’s SMS_PackageBaseClass. Again, you can get a package type identifier from Get-CMDeploymentPackage if you’d rather go that way, but I like WMI.  Once it’s pulled the PackageType value, it runs it through a SWITCH command and runs the appropriate Publish-CMPrestageContent command.  I don’t do any special logging with this function since Publish-CMPrestageContent already does a good job of it.
 Prestaging a single file
Prestaging multiple packages with a For Loop
                This function is one of the main reasons I like to save my prestage files with the PackageID as the name.  You input the folder containing the prestage files as well as the name of the Distribution Point they need to be assigned to, and this will get the package type information for that package, run the same switch as Prestage-Content, and issue the Start-CMContentDistribution command with the appropriate flags.  Just to save time, it will also query the Get-DPContent function to make sure that it isn’t trying to reassign packages that are already assigned.
Packages were already assigned in SCCM
 Package distribution in progress
                This function calls upon Microsoft’s ExtractContent.exe tool to run, and is designed to be run locally from whatever DP you’re importing the package to.  The only flag you need to specify is the location of the prestaged content folder.  It takes the hostname of the computer it’s running from and makes a WMI query to see any packages assigned to it that aren’t in State 0.  If the package shows as state 0, then there’s no further work to be done, and we can just work on the others.  There are multiple ways you can run the extractcontent.exe tool, but I’ve found some to work better than others.   Whether you run it specifying a single package to extract or you run it with an entire folder targeted, I’ve found that when I check the Distribution Point Configuration Status in the SCCM console, there’s always some that still show “waiting for prestage content.”  In almost every case where that’s happened, just re-prestaging the content cleared it up. I don’t know if this is a limitation of the extractcontent.exe tool, my impatience, or what, but it works for me.  Because of that, I actually have my Extract-Content function run through the Prestage content folder one item at a time, so you can re-run the function, it will re-query for unsuccessful packages, and only attempt to extract the packages that didn’t make it the first time.
ExtractContent running


                I put this together for our SCCM architect who wanted something that he could quickly and easily run while logged into our Secondary Site Server that was being migrated.  What this does is query the local DP for all assigned content, export it with the Prestage-Content function, and give you a progress bar to show you how far along you are.

Universal SCCM Content Prestager

, , , ,

Prestage SCCM Content

PS1 file can be found at my TechNet gallery: HERE

The Use Case
Prestaging content is a fact of life in the SCCM world.  Whether you’re standing up a new site, cloning a DP, or sending packages to a site with really bad bandwidth, there are a variety of reasons you need to create prestage packages.  At multiple contracts I worked, these packages were created by finding the content in the Configuration Manager GUI, right clicking, selecting Create Prestage Content File, and going through the wizard.  While this is technically a correct way to do things, it’s cumbersome, requires you to remember where everything is in the menu structure, and ties up your console while you do packages one at a time.   I could see using this method for one or two packages every now and then, but you’re on a PowerShell blog. Here, we’re all about scale.

Not pictured: efficiency

Making it happen
The Configuration Manager module actually comes with a prestage cmdlet built right in, but this cmdlet is one of the most poorly written ones in all of PowerShell.  It has no real intelligence of its own, requiring you to spell out exactly what package type you want to back up. Since every package has a unique PackageID value, I never understood why they didn’t just make it use that number and get on with life, but they didn’t.  Feel free to download the script and follow along.

I actually couldn’t fit them all on one screen

The Script
The first thing we need to do is declare our variables. This script needs to know what the package ID number is (which can be found literally everywhere the package is mentioned in the SCCM console or WMI interface),  what DP we’re pulling the content from, and where the file needs to be saved. All of these are mandatory, so you’ll be prompted for them if you don’t put them inline.  Also, depending on the prestage location, you’ll need admin rights to move files there, so we just check for those at the outset.  We’ll also make sure you’re connected to your CMSite PSDrive. I also have the script make sure the package isn’t already there.  Something else to keep in mind is that the DP name needs to be a FQDN when the command runs. If you enter it with just the hostname, the script will sort that out for you, so no worries.


     After all the pre-reqs have checked out, the real logic comes in. The first thing it does is try to run get-cmpackge with the package ID, if that comes back as $NULL, meaning there was no package with that ID, it starts down the list of available content types. It checks if it’s a software update package, application, boot image, OS image, or driver package.  Until it finds something that actually returns an object, it’ll keep checking. Then, it makes a mental note of what it found so we can use it later.  For troubleshooting and debugging reasons, I like to output the name of the package as well as its source path, but this isn’t necessary. It will also tell you where it’s going and what it will be named.  Then, we use a Switch  statement with the count variable (our mental note from earlier) to select the correct Publish-CMPrestageContent flags that actually do the prestaging work for us.

Figuring out what you wanted
Actually prestaging it

Actually Using It
     On its own, it’s a nice function to have loaded in my shell. Being able to generate a prestage file without tying up my GUI is always handy, and depending on the organizational skills of the previous SCCM admins, not having to dig around to find a package in their menus can be a real time saver.  Where this script comes into its own, however, is when it’s chained together with other commands, which is what we’ll discuss in our next post.

Rebuild site servers without redistributing content over the WAN

, , , , , , , , , ,

Rebuild site servers without redistributing content over the WAN:

Outlining the Project


                In order to support the Windows 10 Migration project for this customer the hierarchy needed to be upgraded to a level to support deploying/managing of windows 10v1607. The current level of the environment is 2012 R2 SP1 and we will move to CB1606 and upgrade to CB1610. During this time I took the opportunity to simplify the architecture as there were dozens of unnecessary secondary sites. These locations would have the site replaced with a single distribution point. There was no getting around these secondary sites as the pre-req check would fail due to the unsupported version of SQL server express installed on the systems. SCCM does support in place upgrade of SQL on a site server but that is limited to full SQL and not the express version. The best practice would be to spin up the new servers, configure them as Pull Distribution Points, pull the content from the old servers, and then smoothly transition between the two. In this environment, however, we were not provided with new servers to use, and we were faced with the added difficulty of prohibitively slow WAN connections, requiring us to come up with an alternative solution.




Best Practice/Worst Practice


                What we came up with was a series of PowerShell scripts that eventually evolved into the Distribution Content Migration Tool-Kit module.  This module takes queries WMI to pull a list of all content assigned to a Distribution Point and runs on the Distribution Point to create prestage packages for all of that content.  Once the required roles have been removed, reconfigured, and added back to the server, the module then allows all of that content to be reassigned to the Distribution Point and subsequently extracted to complete the migration.



Prerequisite Components


                Because portions of this module had to run locally on our Secondary servers, we needed the Configuration Manager libraries loaded as well as the most recent version of the Windows Management Framework.  While it is possible to just copy over the required DLL files and import them into PowerShell, we did want to stick with something more reliable and consistent, so we installed .NET 4.5, WMF 5, which is required to install the Configuration Manager Console. These updates were all copied to the server and then installed to the clients with a quick PowerShell query to find all servers with the Secondary Site role installed piped into a Copy command.  A few reboots later, and the servers were primed to migrate.



Before Removing Roles


                Modify the site assignment and site server referenced on your boundary groups to talk to another site system server. This is set for your boundary by the boundary group applied to it. I changed the site assignment to my primary site server. I changed my site system servers to the MP on my primary and I left the DP blank as this was only an expected outage of less than 2 hours. Once the conversion is complete I will place my DP here for the boundary group. If you do not want to leave that blank you can use the closest DP that has open ports for communication. Remember do not remove any of the roles until we create the pre-staged content locally on the site server.



Prepare server for role removal


                The tool-kit is made up of four separate scripts written out as the functions Get-DPContent, Prestage-Content, Restage-Content, and Extract-Content.  



Script Step 1: Get-DPContent


                The Get-DPContent function requires you to specify a Distribution Point and will pull a list of every piece of content SCCM has assigned to it.  It returns an unformatted array of WMI SMS_PackageBaseClass objects which can look a little daunting, but can be easily formatted for reporting or further processing.


Title: A single DP Content Info object - Description: This is the raw dump of the information returned when you get the SMS DPContentInfo class


Figure 1 – Raw data produced by the SMS_DPContentInfo Class




Figure 2 – Table-formatted values for just PackageID and Name


                I’ve seen some guides online use Get-CMDeploymentPackage to get package info, but I’ve found that WMI works up to 3x faster when querying large data sets, and it runs without needing a connection to a CMSite drive, so it’s become my preferred method.



Script Step 2: Prestage-Content


                This function does the actual work of creating a prestage PKGX file based on the package ID you provide it, the Distribution Point that holds the content, and the location of the folder that will store the package for later use.  The ConfigurationManager PowerShell module actually comes with a cmdlet called Publish-CMPrestageContent, but because that cmdlet requires you to specify the type of item you’re prestaging, we wrote this function to make the WMI call, examine the package type, and issue the correct command for you.  For one off package prestaging, this is still far and away superior to going through right click menus, but where this function shines is when it’s used in conjunction with the Get-DPContent function. 



Figure 3 – Prestaging a single package





Figure 4 – Prestaging multiple packages via For loop


Remove roles from SCCM console.


After you successfully create the pre-staged content locally on the server we can move forward.   In our case, we needed to remove all roles assigned to the server and only add the DP role back. This action required us to remove the DP, MP, and SUP. After these roles are removed we can go ahead and remove the site server.


Note: when you are decommissioning the secondary site this will also uninstall the DP role naturally. Out of habit I recommend to remove all soles prior to uninstallation of the Site.


  • Validated via the distmgr.log on the primary site server
  • Validated by no longer being seen in distribution point configuration status in the console





Removing the site server


                From the console Administration > Expand Overview > Expand Site Configuratoin > Sites > Select the site and “Delete”. This will create a new dialog box and it is important that you read the differences btwn uninstall and remove. We will choose to uninstall.





From here you can see the state of the secondary site server has moved to “Deleting”



How to monitor and the site server uninstallation process


On your secondary site server you can monitor this from C:ConfigMgrSetup.log. The site server uninstallation process is roughly as follows.


1. ConfigMgr2012 Setup is started by system with command line options /deinstall / msg2parent /nouserinput

2. Information is checked, this will be things such as the following. FQDN, OS is verified, Checks for existing setup information, existing SQL information, existing configmgr installation and version number, etc.



3. removes SQL alias for sccm

4. Starts uninstallation of secondary site by first cleaning up SQl server replication data, start uninstallation of local dp (if applicable) Remove content SCCMContentLib, SMSPKG, SMSPKGF$, SMSSIG$ directories from the server. The process will also move through list of all SCCM Services and stop/uninstall them if present and then stop WMI



After services/connections are removed you will see a number of redlines in the log file. This is only b/c connection can not be established which is expected right after stopping WMI




5. Connect to database, drop schema SMS_SiteSystemToSQLConnection, drop database, and uninstall SQL (if applicable)



NOTE: ONLY If your admin installed SQL instead of letting SCCM perform the uninstall action during site install you will see this message



6. Attempt unregister list of Binaries



7. Attempt delete remaining folders/files from within the configmgr installation directory



8. remove registry keys, restart WMI, and other services then complete uninstallation of Configuration Manager Site.



NOTE: After site is uninstalled you might run into issues where the secondary server is still showing “Deleting” this can be resolved by my other blogpost HERE where I had to use the hierarchy maintenance tool.



Remove unnecessary items


Start by uninstalling SQL (if applicable) the only time you will have to uninstall this is if the admin installed / configured SQL on the secondary site instead of letting SCCM do this action. Remove any other roles/features that are no longer needed. For this environment I also removed WSUS as it is no longer needed nor will be able to patch win 10 when the server is on server 2008R2 w/ WSUS 3.0
since we uninstalled SQL this freed up two extra drives on the machine that stored the database and the log files. These were then reclaimed by the storage team. For the entire project this allowed 1200 GB to be reclaimed. Uninstall the sccm console as it is no longer needed.



Before reinstalling DP


I have performed a number of conversions in the past where there were problems reinstalling the DP role. Typically this process goes just fine but in rare instances I ran into issues and have to completely remove the client / delete from database / rediscover / reinstall client / reinstall role, so I recommend doing the following.  


  1. Completely uninstall SCCM Client
  2. Remove the following registry HIVE “HKEY_Local_MachineSoftwareMicrosoftSMS”
  3. Reinstall SCCM client



Reinstall DP Role


                There should not be any additional configuration needed as this server previously had the DP role. Make sure this is not configured for pull dp and you enable this for pre-staged content. You can track the installation process in 2 logs: DISTMGR.LOG on the primary site server installation path and and SMSDPPROV.LOG located SMS_DP$smslogs. You can also Track through monitoring on the console


Track though the distmgr.log on your primary server and smsdpprov.log on the DP.





Script Step 3: Restage-Content


                The Restage-Content function crawls through the list of packages we saved and tells SCCM to re-assign the content.  While the Prestage-Content and Extract-Content functions need to be run on the DP you’re migrating, this command, along with Get-DPContent, can be run from any computer as it is only interacting with meta-data on the SCCM server. All you need to specify here is the location of the prestage files and the name of the distribution point they’ll be assigned to.  



Figure 5 – Content restaging in progress



Figure 6 – Existing content will not waste time trying to reassign



Script Step 4: Extract-Content


This function takes input in the form of the prestaged content location and uses Microsoft’s ExtractContent.exe program to manually add them to the content library.  While we messed with the idea of having it prompt you for the location of the ExtractContent.exe utility, we eventually decided that it was simpler to just require the exe file to be in the same directory as the prestage packages.  This takes a while to run depending on the quantity and size of your PKGX files, and in the event that some do not sync properly when you check your Distribution Point Configuration Status messages, you can run this function again, and it will only try to extract content that isn’t flagged as State=0 (successful).



Figure 7 – Content extracting one package at a time




Final Product


In conclusion, while there are some tools and packages out there that are more “double click and go” automation, we’ve found that every environment is too different for one solution to work for everybody. With that in mind, we focused on developing a toolkit that could be adjusted and tweaked for any environment and then used that to simplify our infrastructure to make life easier for the local admins.  Our next step in this project is to begin the upgrade from SCCM 2012 R2 SP1 to Current Branch 1606, and eventually to Current Branch 1610.    When all is said and done, we’ll have converted nearly three dozen secondary sites, all with their own Distribution Point, Software Update Point, and Management Point roles over to just Distribution Points.  In addition to saving several hundred GB of content distribution traffic this conversion will have eliminated much of the unnecessary SQL and WSUS traffic we saw. The storage team was also thrilled to realize 1.2TB of storage can now be reclaimed.
ALSO SEE : Lockstate Object