We've been running with an old file server and a new file server for our SCCM package sources for a while now, with all the new software being put on the new server, and obsolete software being deleted from the old server as it goes out of use. Over time the old server should be used less and less as a package source, until it falls out of use and is decommissioned, but we really need to get a shift on with getting everything off the old hardware, and onto the new one. To make things easier for future moves the new one's referenced in all our systems with a fairly generic DNS name (rather than an old and obscure machine naming scheme), which should also make future server changes easier to manage.
So the first thing that I need to do is trundle through SCCM and work out what software is still using the old server as its source. There are a few main categories of bulk content that could be referencing files on that old server:
- Programs (using the Package Model)
- Driver Packages
- Applications (using the Application model)
Any of those could have their content files stored on either server. Packages are fairly easy as you can add a column to the console called "Package Source Path" and then sort by that. Applications are not so easy; each Deployment Type within an app has its own individual source path, and you have to drill right into the Deployment Type's properties to see it, there's no quick and easy way to see a list. (Obviously things like OS Images, Boot Images, etc could also be on the old server but we've only got single digit numbers of each of those, so they're just as quick to check one by one).
Packages (and Programs)
First the easy options, Packages and Driver Packages. Packages have one Package Source Path for the whole Package, which is used by each Program in the Package. All we need to do is use a cmdlet to retrieve all of the packages, then just pull out the properties from each that we're interested in, and finally dump that to a file that we can open in Excel and work our way through:
(All of the below PowerShell commands to be executed from a Config Manager PowerShell window, or a normal PowerShell command prompt with the ConfigurationManager module loaded and the current location changed to the Config Manager PSDrive for your site).
PS ABC:\> $Packages = Get-CMPackage
PS ABC:\> $Packages | Select-Object -Property PackageID, Name, PkgSourcePath | Export-Csv -Path C:\temp\PkgSrc.csv -NoTypeInformation
Driver Packages
These are very, very similar to normal packages. So similar that you may not even notice there's six extra letters in the initial cmdlet.
PS ABC:\> $DriverPackages = Get-CMDriverPackage
PS ABC:\> $DriverPackages | Select-Object -Property PackageId, Name, PkgSourcePath | Export-Csv -Path c:\Temp\DriverPkgSrc.csv -NoTypeInformation
Both of the above (Get-CMPackage
and Get-CMDriverPackage
) are relatively quick, they took less than a minute even running them from a remote machine against a site with a large number of [driver] packages .
Application model applications
Ok, here we go, here's the big one. Each Application can have multiple Deployment Types, each of those deployment types (which can each use a different deployment style) has its own, individual Content Location. To add to this, these queries are slower than their equivalents in the Package model (we're talking multiple minutes rather than seconds), long enough that there's some progress text output during this one, just to let you know that it's actually doing something. Then finally details of the app's Deployment Type(s) are all listed in a big XML property of the Application object, rather than each being their own object properties.
Here we are. Firstly we get the full list of apps from the site (which is the part that I've seen take 10 to 15 minutes on a site with around 800 app model apps), then iterate over them, pulling the relevant properties out of the XML (including iterating over each Deployment Type in that app), then finally output all of that as an object which we write to a CSV file:
$CSVOutPath = 'c:\temp\AppSrc.csv'
#Change to your site's ConfigMgr PSDrive before running this script
#Get each Application, then get the source path from each Applications's Deployment Types
Write-Host "Fetching application details - this takes a few minutes, please wait...`n"
$Applications = Get-CMApplication
$AppCount = $Applications.Count
Write-Host "$AppCount applications found.`n"
#Iterate over the apps list pulling out the details for each app. Takes a couple of minutes.
$i = 1
$AppSourceList = ForEach($App in $Applications)
{
Write-Progress -Activity 'Checking apps and deployment types' -Id 1 -PercentComplete $(($i / $AppCount) * 100) -CurrentOperation "app $i / $AppCount"
$PackageXml = [xml]$App.SDMPackageXML
#An app can have multiple Deployment Types, each with their own source location. DT details are stored in the XML properties
ForEach($DT in $PackageXml.AppMgmtDigest.DeploymentType) {
$DtTitle = $DT.Title.'#text' #need to quote property names with hashes in them, normal backtick escaping doesn't work
$DtTech = $DT.Technology
$DtLocation = $DT.Installer.Contents.Content.Location
New-Object -TypeName psobject -Property (@{AppDisplayName = $App.LocalizedDisplayName; PackageID = $App.PackageID;
CiId = $app.CI_ID; Enabled = $app.IsEnabled; Superseded = $app.IsSuperseded; HasContent = $app.HasContent;
DepTitle = $DtTitle; DepTypeTech = $DtTech; DepTypeSrcLocation = $DtLocation})
}
$i++
}
#$AppSourceList | Out-GridView
$AppSourceList | Export-Csv -Path $CSVOutPath -NoTypeInformation
Download the Get-ApplicationSources.ps1 here: GitHub Get-ApplicationSources.ps1
(No download for the Package and Driver Package sources, as they're basically just one-liners).