If you’ve migrated Applications or Packages from an old ConfigMgr hiearchy into a new one, or perhaps you’ve just create a bunch of stuff that you’d like to distribute, distribution can rather quickly become a nightmare of mouse clicks. But not if you do it with PowerShell. In this post I’ll show you how it’s possible to distribute either all Packages or Applications at the same time, and with some logic to it.

Overview

  • Distribute all Packages to a Distribution Point Group
  • Distribute all Applications to a Distribution Point Group
  • Distribute all non-distributed Packages to a Distribution Point Group
  • Distribute all non-distributed Applications to a Distribution Point Group

Distribute all Packages to a Distribution Point Group

This script will simply just locate all Packages and try to distribute it to the specified Distribution Point Group. It does not contain any logic to see if the Packages are already present in the Distribution Point Group. In order to use this script in your environment, edit the following variables:

$SiteServer – This should be the Primary Site server’s NetBIOS name.
$SiteCode – The Site code of your Primary Site server.
$DistributionGroup – This variable should contain the name of a desired Distribution Point Group.

$SiteServer = "<netbios_name>"
$SiteCode = "<site_code>"
$DistributionGroup = "<DP_Group_name>"

$ModulePath = (($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) + '\ConfigurationManager.psd1'
Import-Module $ModulePath -Force
if ((Get-PSDrive $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) {
    New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer
}
$SiteDrive = $SiteCode + ":"
Set-Location $SiteDrive

$Packages = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Package -ComputerName $SiteServer
$Packages | ForEach-Object {
    $PackageName = $_.Name
    Write-Output "Starting distribution of: $($PackageName)"
    Start-CMContentDistribution -PackageName $PackageName -DistributionPointGroupName $DistributionGroup | Out-Null
}

Set-Location C:

Distribute all Applications to a Distribution Point Group

As with the script above, this does the same but for all Applications instead. There’s no logic in this script either, so use it with caution. Edit the following variables to use it in your environment:

$SiteServer – This should be the Primary Site server’s NetBIOS name.
$SiteCode – The Site code of your Primary Site server.
$DistributionGroup – This variable should contain the name of a desired Distribution Point Group.

$SiteServer = "<netbios_name>"
$SiteCode = "<site_code>"
$DistributionGroup = "<DP_Group_name>"

$ModulePath = (($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) + '\ConfigurationManager.psd1'
Import-Module $ModulePath -Force
if ((Get-PSDrive $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) {
    New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer
}
$SiteDrive = $SiteCode + ":"
Set-Location $SiteDrive

$Applications = Get-WmiObject -ComputerName $SiteServer -Namespace root\SMS\site_$SiteCode -class SMS_Application | Where-Object {$_.IsLatest -eq $True} 
$Applications | ForEach-Object {
    $AppName = $_.LocalizedDisplayName
    Write-Output "Starting distribution of: $($AppName)"
    Start-CMContentDistribution -ApplicationName $AppName -DistributionPointGroupName $DistributionGroup  | Out-Null
}

Set-Location C:

Distribute all non-distributed Packages to a Distribution Point Group

This script however will only distribute Packages that are not currently distributed to the specified Distribution Point Group. Change the following variables to use the script in your environment:

$SiteServer – This should be the Primary Site server’s NetBIOS name.
$SiteCode – The Site code of your Primary Site server.
$DistributionGroup – This variable should contain the name of a desired Distribution Point Group.

$SiteServer = "<netbios_name>"
$SiteCode = "<site_code>"
$DistributionGroup = "<DP_Group_name>"

$ModulePath = (($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) + '\ConfigurationManager.psd1'
Import-Module $ModulePath -Force
if ((Get-PSDrive $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) {
    New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer
}
$SiteDrive = $SiteCode + ":"
Set-Location $SiteDrive

$PackageIDs = @()
$PackagesToDistribute = @()

$DPGroupPackages = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_DPGroupPackages -ComputerName $SiteServer
$DPGroupPackages | ForEach-Object {
    $DPGroupPackageID = $_.PkgID
    $PackageIDs += $DPGroupPackageID
}

$Packages = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Package -ComputerName $SiteServer
$Packages | ForEach-Object {
    $PackageID = $_.PackageID
    $PackageName = $_.Name
    if ($PackageIDs -notcontains $PackageID ) {
        $PackagesToDistribute += $PackageID        
    }
}

if ($PackagesToDistribute.Count -ge 1) {
    Write-Output "Found a total of $($PackagesToDistribute.Count) Packages to distribute:`n"
    $PackagesToDistribute | ForEach-Object {
        $ID = $_
        $CurrentPackageName = (Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Package -ComputerName $SiteServer | Where-Object { $_.PackageID -like "$($ID)" }).Name
        Write-Output "Distributing: $($CurrentPackageName)"
        Start-CMContentDistribution -PackageName $CurrentPackageName -DistributionPointGroupName $DistributionGroup | Out-Null
    }
}
else {
    Write-Output "Distribution Point Group: $($DistributionGroup)"
    Write-Output "Results: No undistributed Packages found"
}

Set-Location C:

If you have Packages that are currently not distributed when running this script, you’ll receive the following message and it will start to distribute the packages:

44_2

If one of the Packages does not contain any Source files, the following message will appear:

44_1

And if you run the script when all your Packages have already been distributed, you’ll get this:

44_3

Distribute all non-distributed Applications to a Distribution Point Group

The same logic applies here as to the script just right above, it will only distribute Applications that are not distributed yet (or is in progress). It determines if the Application is distributed by checking Status Messages from the Distribution Point Group. Remember to edit the following variables in order for the script to work in your environment:

$SiteServer – This should be the Primary Site server’s NetBIOS name.
$SiteCode – The Site code of your Primary Site server.
$DistributionGroup – This variable should contain the name of a desired Distribution Point Group.

$SiteServer = "<netbios_name>"
$SiteCode = "<site_code>"
$DistributionGroup = "<DP_Group_name>"

$ModulePath = (($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) + '\ConfigurationManager.psd1'
Import-Module $ModulePath -Force
if ((Get-PSDrive $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) {
    New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer
}
$SiteDrive = $SiteCode + ":"
Set-Location $SiteDrive

$i = 0
$DPGroupArray = @()
$AppsToDistribute = @()

$DPGroupStatus = Get-WmiObject -ComputerName $SiteServer -Namespace root\SMS\site_$SiteCode -class SMS_DPGroupDistributionStatusDetails -Filter "ObjectType = 512 AND MessageState = 1 OR MessageState = 2" | Select-Object ObjectID
$DPGroupStatus | ForEach-Object {
    $i++
    $ObjectID = $_.ObjectID
    Write-Progress -id 1 -Activity "Getting Status Messages from Distribution Point Group" -Status "Adding object $($i) of $($DPGroupStatus.Count) to array" -PercentComplete (($i / $DPGroupStatus.Count)*100)
    $DPGroupArray += $ObjectID
}

$Applications = Get-WmiObject -ComputerName $SiteServer -Namespace root\SMS\site_$SiteCode -class SMS_Application | Where-Object {$_.IsLatest -eq $True} 
$Applications | ForEach-Object {
    $AppName = $_.LocalizedDisplayName
    $ModelName = $_.ModelName
    if ($DPGroupArray -notcontains $ModelName ) {
        $AppsToDistribute += $ModelName
    }
}

if ($AppsToDistribute.Count -ge 1) {
    Write-Output "Found a total of $($AppsToDistribute.Count) Applications to distribute:`n"
    $AppsToDistribute | ForEach-Object {
        $ID = $_
        $CurrentAppName = (Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Application -ComputerName $SiteServer | Where-Object { $_.ModelName -like "$($ID)" }).LocalizedDisplayName
        Write-Output "Distributing: $($CurrentAppName)"
        Start-CMContentDistribution -ApplicationName $CurrentAppName -DistributionPointGroupName $DistributionGroup | Out-Null
    }
}
else {
    Write-Output "Distribution Point Group: $($DistributionGroup)"
    Write-Output "Results: No undistributed Applications found"
}

Set-Location C:

The output from the script when it finds an Application to distribute looks like this:

44_4

When there are no Applications to distribute, the output will look like this:

44_5

I hope this helps you distributing stuff in ConfigMgr 2012 SP1!

Nickolaj Andersen
Principal Consultant and Enterprise Mobility MVP. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows deployments and Automation. In 2015 Nickolaj was awarded as PowerShell Hero by the community for his script and tools contributions. Author of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService and a frequent speaker at user groups.

(710)

comments
  • George R. Jenkins
    Posted at 00:41 June 25, 2014
    George R. Jenkins
    Reply
    Author

    Do you know of a way to run the Configurationmanager module without installing the SCCM console? I’d like to automatically add new domain computers to various collections so they could get their deployable software associated with the collections. Thanks for your advice.

    • Nickolaj
      Posted at 20:34 June 27, 2014
      Nickolaj
      Reply
      Author

      Hi George,

      In what scenario would you like to make use of the ConfigMgr module, in a OSD scenario or something else? To my knowledge it’s not possible to run it without installing the console, since the module is combined with the console installation package. If you tell me a bit more about the scenario you’re dealing with, perhaps I can be of assistance.

      Regards,
      Nickolaj

  • Richie Schuster
    Posted at 17:33 August 20, 2015
    Richie Schuster
    Reply
    Author

    Out Standing! saved me from RSI on my index finger! 🙂

  • Leave a Reply