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.
I hope this script will be useful for you!
Add comment