In an earlier post, I wrote about how you can leverage PowerShell to distribute application and packages to a Distribution Point Group. The script that I’m using in that post may work, but the code is not nearly of any kind of best practice, or to be frank, good looking. At one of my recent projects that I’ve been involved with, we’ve migrated a log of packages to the application model. So I had to create a script that the customer could leverage when they were gonna distribute all the new applications.

Since the customer had created some applications themselves, the script would had to take into account so that it would only distribute applications created within a certain time frame. It was also necessary to be able to specify which Site server to run the script against, as well for what Distribution Point Group should be targeted.

Script

<#
.SYNOPSIS
    Distributes all Applications created within a certain time frame to a Distribution Point Group
.DESCRIPTION
    Distributes all Applications created within a certain time frame to a Distribution Point Group
.PARAMETER SiteServer
    Primary Site server name
.PARAMETER DPGName
    Specify a Distribution Point Group name
.PARAMETER CreatedDaysAgo
    Specify the amount of days ago an Application was created. The script will only enumerate Applications created within the specified time frame.
.EXAMPLE
    Start to distribute all Applications created within the last day to a Distribution Point Group called 'All DPs' on a Site server called 'CM01':

    .\Start-ApplicationDistribution.ps1 -SiteServer "CM01" -DPGName "All DPs"
.EXAMPLE 
    Start to distribute all Applications created within the last 3 days to a Distribution Point Group called 'All DPs' on a Site server called 'CM01':

    .\Start-ApplicationDistribution.ps1 -SiteServer "CM01" -DPGName "All DPs" -CreatedDaysAgo 3
.NOTES
    Script name: Start-ApplicationDistribution.ps1
    Author:      Nickolaj Andersen
    Contact:     @NickolajA
    DateCreated: 2014-09-22
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [parameter(Mandatory=$true, HelpMessage="Specify the Primary Site server")]
    [ValidateScript({Test-Connection -ComputerName $_ -Count 2})]
    [string]$SiteServer = "$($env:COMPUTERNAME)",
    [parameter(Mandatory=$true, HelpMessage="Specify the name of a Distribution Point Group")]
    [string]$DPGName,
    [parameter(Mandatory=$false, HelpMessage="Specify the name of a Distribution Point Group")]
    [int]$CreatedDaysAgo = 1
)
Begin {
    # Determine SiteCode from WMI
    try {
        Write-Verbose "Determining SiteCode for Site Server: '$($SiteServer)'"
        $SiteCodeObjects = Get-WmiObject -Namespace "root\SMS" -Class SMS_ProviderLocation -ComputerName $SiteServer -ErrorAction Stop
        foreach ($SiteCodeObject in $SiteCodeObjects) {
            if ($SiteCodeObject.ProviderForLocalSite -eq $true) {
                $SiteCode = $SiteCodeObject.SiteCode
                Write-Debug "SiteCode: $($SiteCode)"
            }
        }
    }
    catch [Exception] {
        Throw "Unable to determine SiteCode"
    }
    # Load the Configuration Manager 2012 PowerShell module
    try {
        Write-Verbose "Importing Configuration Manager module"
        Write-Debug ((($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) + "\ConfigurationManager.psd1")
        Import-Module ((($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) + "\ConfigurationManager.psd1") -Force -ErrorAction Stop
        if ((Get-PSDrive $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) {
            New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer -ErrorAction Stop
        }
        # Set the location to the Configuration Manager drive
        Set-Location ($SiteCode + ":")
    }
    catch [Exception] {
        Throw $_.Exception.Message
    }
}
Process {
    # Validate specified Distribution Point Group
    try {
        $DPG = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_DistributionPointGroup -ComputerName $SiteServer -Filter "Name = '$($DPGName)'"
        if (($DPG | Measure-Object).Count -eq 1) {
            Write-Verbose "Found Distribution Point Group: $($DPG.Name)"
        }
        elseif (($DPG | Measure-Object).Count -gt 1) {
            Throw "Query for DPGs returned more than 1 object"
        }
        else {
            Throw "Unable to determine Distribution Point Group name from specified string for parameter 'DPGName'"
        }
    }
    catch [Exception] {
        Throw $_.Exception.Message
    }
    # Start Application distribution
    try {
        Write-Verbose "Enumerating applicable Applications"
        $Applications = Get-CMApplication | Select-Object LocalizedDisplayName, PackageID, DateCreated | Where-Object { $_.DateCreated -ge (Get-Date).AddDays(-$CreatedDaysAgo) }
        foreach ($Application in $Applications) {
            if (-not(Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_DPGroupDistributionStatusDetails -ComputerName $SiteServer -Filter "PackageID = '$($Application.PackageID)'" -ErrorAction SilentlyContinue)) {
                if ($PSCmdlet.ShouldProcess("$($DPG.Name)", "Distribute Application: $($Application.LocalizedDisplayName)")) {
                    $DPG.AddPackages($Application.PackageID) | Out-Null
                }
            }
        }
        Set-Location C:
    }
    catch [Exception] {
        Throw $_.Exception.Message
    }
}

How to use the script

Save the script above as Start-ApplicationDistribution.ps1 to a folder somewhere, e.g. C:\Scripts.

Let’s say that we have a scenario where we’ve created 100 new applications and we need to distribute them to a Distribution Point Group called Global. In addition, there’s already a bunch of applications that was created earlier in time. Since the script accepts a parameter called CreatedDaysAgo, we can specify a number that correlates to how many days ago the application that we’re targeting was created. As we know that we’ve created all of our 100 applications within the last 2 days, we can then specify the parameter CreatedDaysAgo as 2. Here’s how you’d do that:

1. Open an elevated PowerShell console and browse to where you have the script.
2. Run the following command:

.\Start-ApplicationDistribution.ps1 -SiteServer "CAS01" -DPGName "Global" -CreatedDaysAgo 2

As the script accepts advanced PowerShell functions, you can also specify the -WhatIf parameter as well for the -Confirm, -Debug or -Verbose.

111_1

I hope this script will be useful for you!

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.

(126)

There are no comments.

Leave a Reply