Create SCCM Software Package Collections

This PowerShell script will create both the mandatory and self-service collections for a software package/application.   The script must be run from an x86 PowerShell environment on a system with the SCCM 2012 Console installed and Cumulative Update 1 or later applied.

[powershell]

<#
.SYNOPSIS
Creates the mandatory and self-service collections for an NCSU Software Package
.DESCRIPTION
For a given software group name this script will create the mandatory and self-service collections.
The collections will have the following properties/settings:

– Limited by collection of the same name as the department prefix (included in software group name)
– Queries an Active Directory group of the same name (-SS appended for self-service) to populate members
– Scheduled refresh every two hours

Script relies on the SCCM PowerShell module that comes with the SCCM 2012 Console and it must be run
from an x86 PowerShell environment.
.PARAMETER softwareGroupName
A group name that follows the <UNIT>-<EX/SW/FW>-<Vendor>-<Title>-<Version> naming convention
.PARAMETER licenseRequired
A Yes/No parameter – for an EX package, if Yes is specified the script will append a group of the
same name as the softwareGroupName with ‘SW’ in place of ‘EX’ to account for the eventual promotion
of the package to production. Likewise, if No is specified the script will append a group of the
same name as the softwareGroupName with ‘SW’ in place of ‘EX’ to account for the eventual promotion
of the package to production.
.EXAMPLE
create_sccm_software_package_collections.ps1 -softwareGroupName ‘TEX-EX-Google-Google Drive-1.8.4’ -licenseRequired No
.LINK
How I found the ‘Software Package Collections’ folder container ID:
http://social.technet.microsoft.com/Forums/en-US/configmgrsdk/thread/787a84c9-79e0-41a3-8f85-2b2a0fa3b337/

Fix needed to allow a ‘RefreshSchedule’ to be added to the collection:
http://support.microsoft.com/kb/2817245

Move-CMObject Code:
http://cm12sdk.net/?p=1006
.NOTES
Author: Ryan Leap – srleap@ncsu.edu
Requires: SCCM 2012 Console PowerShell Module

SCCM SP1 Cumulative Update 1 required for this script to work properly (apply Refresh Schedule to
a Collection). To apply this to an admin machine with the SCCM Console extract the contents of
the CU1 package and run:
msiexec /p configmgr2012adminui-sp1-kb2817245-i386.msp

WMI SMS Provider:
Get-WmiObject -Namespace “root/SMS” -List -ComputerName OIT200SCCM-SS
Get-WmiObject -Namespace “ROOT\SMS\SITE_WUF” -Query “select name, containernodeid from SMS_ObjectContainerNode” -ComputerName OIT200SCCM-SS

Enhancements/Bug Fixes – 06/17/2013
1. Tests if SCCM PS module (file) is on system, issues error message if missing.
2. Support for 32 bit and 64 bit paths to SCCM PS Module
3. Tests if SCCM PS module is already loaded before attempting to import
4. Saves Current working directory and restores session to that location after script completes
5. Includes ‘EX’ in collection query even with SW or FW is supplied for the softwareGroupName

#>
# Set-StrictMode -Version latest

Param (
[parameter(Mandatory=$True,HelpMessage=’Enter a software group name as follows: <UNIT>-<EX/SW/FW>-<Vendor>-<Title>-<Version>’)] [string]$softwareGroupName = ”,
[parameter(Mandatory=$True,HelpMessage=’Does this software require a license (Yes/No)?’)] [string]$licenseRequired = ‘No’
)

#——————————————————————————————
#
# Code to move an SCCM object swiped from here:
#
# http://cm12sdk.net/?p=1006
#
#——————————————————————————————
Function Move-CMObject
{
[CmdLetBinding()] Param(
[Parameter(Mandatory=$True,HelpMessage=”Please Enter Site Server Site code”)] $SiteCode,
[Parameter(Mandatory=$True,HelpMessage=”Please Enter Site Server Name”)] $SiteServer,
[Parameter(Mandatory=$True,HelpMessage=”Please Enter Object ID”)] [ARRAY]$ObjectID,
[Parameter(Mandatory=$True,HelpMessage=”Please Enter current folder ID”)] [uint32]$CurrentFolderID,
[Parameter(Mandatory=$True,HelpMessage=”Please Enter target folder ID”)] [uint32]$TargetFolderID,
[Parameter(Mandatory=$True,HelpMessage=”Please Enter object type ID”)] [uint32]$ObjectTypeID
)

Try{
Invoke-WmiMethod -Namespace “Root\SMS\Site_$SiteCode” -Class SMS_objectContainerItem -Name MoveMembers -ArgumentList $CurrentFolderID,$ObjectID,$ObjectTypeID,$TargetFolderID -ComputerName $SiteServer -ErrorAction STOP
}
Catch{
$_.Exception.Message
}

}

#—————————————————————————————–
#
# Main Script
#
#—————————————————————————————–

# Perform some string validation against the group name and the license required parameter
$licenseRequired = $licenseRequired.ToLower()
$softwareGroupName = $softwareGroupName.Trim(””)
$akaSoftwareGroupName = $softwareGroupName
$parsedSoftwareGroupName = $softwareGroupName.Split(‘-‘)

If ($parsedSoftwareGroupName.Length -ne 5) {
Write-Host(”)
Write-Host ‘Software group name must adhere to the following naming convention:’ -ForegroundColor Red
Write-Host ‘<UNIT>-<EX/SW/FW>-<Vendor>-<Title>-<Version> where UNIT is a three-letter departmental prefix.’
}
ElseIf ( ($parsedSoftwareGroupName[0].Length -lt 2) -or
(!($parsedSoftwareGroupName[0] -match “^[a-z\s]+$”)) ) {
Write-Host(”)
Write-Host “Unit (department) name malformed: ” $parsedSoftwareGroupName[0] -ForegroundColor Red
}
ElseIf ( ($parsedSoftwareGroupName[1].CompareTo(‘EX’) -ne 0) -and
($parsedSoftwareGroupName[1].CompareTo(‘FW’) -ne 0) -and
($parsedSoftwareGroupName[1].CompareTo(‘SW’) -ne 0) ) {
Write-Host(”)
Write-Host “Software status not equal to EX, FW, or SW: ” $parsedSoftwareGroupName[1] -ForegroundColor Red
}
Else {
# Code relies on the SCCM PowerShell module distributed with the SCCM Console
[string] $ccmModuleName = ‘ConfigurationManager’
[string] $ccmModulePath = “C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\$ccmModuleName.psd1”
[boolean] $ccmModuleAvailable = Test-Path -Path $ccmModulePath -PathType Leaf
If ($ccmModuleAvailable -eq $false) {
$ccmModulePath = “C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\$ccmModuleName.psd1″
$ccmModuleAvailable = Test-Path -Path $ccmModulePath -PathType Leaf
}
If ($ccmModuleAvailable -eq $false) {
Write-Host(”)
Write-Host ‘SCCM PowerShell module not available for import!’ -ForegroundColor Red
}
Else {
# Load the SCCM PowerShell module as needed
If (-not (Get-Module -Name $ccmModuleName)) {
Import-Module $ccmModulePath
}

# Save the current working directory and change to the SCCM Drive
Push-Location -Path WUF:

# This should be the departmental root like ‘OIT’ or ‘COE’ or ‘TEX’
$limitingCollection = Get-CMDeviceCollection -Name $parsedSoftwareGroupName[0]

# Refresh schedule for software collections should be every two hours
$startDate = Get-Date -Format g
$collectionSchedule = New-CMSchedule -Start $startDate -RecurCount 2 -RecurInterval Hours
[string] $collectionComment = ‘Collection created via PowerShell Script. -sRL’

# The software package collections belong in the ‘Software Package Collections’ folder
[int] $collectionContainerId = 16777253
[string] $siteServer = “OIT200SCCM-SS”

# Build promoted name (EX -> FW or EX -> SW) into collection query
If ($parsedSoftwareGroupName[1].CompareTo(‘EX’) -eq 0) {
If ( ($licenseRequired.CompareTo(‘yes’) -eq 0) -or ($licenseRequired.CompareTo(‘y’) -eq 0) ) {
$akaSoftwareGroupName = $akaSoftwareGroupName.Replace(‘-EX-‘, ‘-SW-‘)
}
Else {
$akaSoftwareGroupName = $akaSoftwareGroupName.Replace(‘-EX-‘, ‘-FW-‘)
}
}
# They supplied FW or SW for the collection name, so go ahead and query an EX group too just in case
Else {
$akaSoftwareGroupName = $akaSoftwareGroupName.Replace(‘-SW-‘, ‘-EX-‘)
$akaSoftwareGroupName = $akaSoftwareGroupName.Replace(‘-FW-‘, ‘-EX-‘)
}

# Create the Mandatory Collection
[string] $queryName = ‘Mandatory’
[string] $queryADGroup = “select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.SystemGroupName = “”WOLFTECH\\$softwareGroupName”” or SMS_R_System.SystemGroupName = “”WOLFTECH\\$akaSoftwareGroupName”””
$deviceCollection = New-CMDeviceCollection -Comment $collectionComment -RefreshSchedule $collectionSchedule -RefreshType Periodic -LimitingCollectionId $limitingCollection.CollectionID -Name $softwareGroupName
Add-CMDeviceCollectionQueryMembershipRule -CollectionId $deviceCollection.CollectionID -RuleName $queryName -QueryExpression $queryADGroup
Move-CMObject -SiteCode WUF -SiteServer $siteServer -ObjectID $deviceCollection.CollectionID -CurrentFolderID 0 -TargetFolderID $collectionContainerId -ObjectTypeID 5000
Write-Host(”)
Write-Host “Mandatory collection created: $softwareGroupName”
Write-Host(”)
# Create the Self-Service Collection
$queryName = ‘Self-Service’
$queryADGroup = “select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.SystemGroupName = “”WOLFTECH\\$softwareGroupName-SS”” or SMS_R_System.SystemGroupName = “”WOLFTECH\\$akaSoftwareGroupName-SS”””
$deviceCollection = New-CMDeviceCollection -Comment $collectionComment -RefreshSchedule $collectionSchedule -RefreshType Periodic -LimitingCollectionId $limitingCollection.CollectionID -Name “$softwareGroupName-SS”
Add-CMDeviceCollectionQueryMembershipRule -CollectionId $deviceCollection.CollectionID -RuleName $queryName -QueryExpression $queryADGroup
Move-CMObject -SiteCode WUF -SiteServer $siteServer -ObjectID $deviceCollection.CollectionID -CurrentFolderID 0 -TargetFolderID $collectionContainerId -ObjectTypeID 5000
Write-Host(”)
Write-Host “Self-Service collection created: $softwareGroupName-SS”

# Return the script caller to the orignal working drive/location
Pop-Location
}
}

[/powershell]