Tagged: Collections

Keep a list of user/computer groups in registry

In the migration to ConfigMgr 2012 we are aiming at just keeping one collection for software distribution and instead rely on global conditions.
We do want to keep the option to add a user to a group and with that do a automagic distribution.

So, the examples below are snippets from the logonscript.

Here is the short version:
– Recursive search for group membership for user
– If group-list changed, update the reg key
(Then do the same for computer groups)
– If there are any changes to groups, trigger the ConfigMgr agent

– Create a global condition in ConfigMgr
– Use the condition like “If MyGlobalCondition contains SwDistGroupName”

$userDN = "CN=MyUser,OU=Users,DC=snowland,DC=se"
$computerDN = "CN=CyComputer,OU=Computers,DC=snowland,DC=se"

Function Get-DistGroups {
	PARAM (
		$ObjectDN,
		$nameFilter = "SwDist_*"
	)

	$distGroups = @()
	$AdSearch=([ADSISearcher]"LDAP://")
	$AdSearch.pagesize=512
	$AdSearch.Filter="(&(member:1.2.840.113556.1.4.1941:=$($ObjectDN))(name=$($nameFilter)))"
	$AdSearch.findAll() | ForEach-Object {
		Write-Verbose "Found group: $($_.Properties.Item('Name'))"
		$distGroups += $_.Properties.Item("Name")
	}

	Return $distGroups
}

# Standard setting
$runConfigMgrActions = $false

# Store DIST groups in registry
Write-Host "Reading User DIST groups"
$userDistGroups = Get-DistGroups -ObjectDN $userDN | Sort-Object
$CurrKeys = Read-RegKey -Key "HKCU:\Software\SSAB\SoftwareDistribution" -Name "UserGroups" | Sort-Object
If ((Compare-Object -ReferenceObject $CurrKeys -DifferenceObject $userDistGroups) -ne $null) {
	Write-Host "Found added/removed user groups, writing new list to registry"
	New-ItemProperty "HKCU:\Software\snowland\SoftwareDistribution" -Name "UserGroups" -Value $userDistGroups -PropertyType "MultiString" -Force | Out-Null

	$runConfigMgrActions = $true
} else {
	Write-Verbose "No changes in user groups"
}

Write-Host "Reading computer groups"
$computerDistGroups = Get-DistGroups -ObjectDN $computerDN | Sort-Object
$CurrKeys = Read-RegKey -Key "HKLM:\Software\SSAB\SoftwareDistribution" -Name "ComputerGroups" | Sort-Object

If ((Compare-Object -ReferenceObject $CurrKeys -DifferenceObject $computerDistGroups) -ne $null) {
	Write-Host "Found added/removed computer groups, writing new list to registry"
	New-ItemProperty "HKLM:\Software\snowland\SoftwareDistribution" -Name "ComputerGroups" -Value $computerDistGroups -PropertyType "MultiString" -Force | Out-Null
	$runConfigMgrActions = $true
} else {
	Write-Verbose "No changes in computer groups"
}

# Trigger ConfigMgr client actions if groups have changed
If ($runConfigMgrActions -eq $true) {
	Write-Verbose "Changes to DIST groups, running ConfigMgr Actions"
	(New-Object -ComObject CPApplet.cpAppletMgr).GetClientActions() | Where-Object {$_.Name -like "Application Global Evaluation Task*" -or $_.Name -like "Request & Evaluate*"} | Sort-Object Name | ForEach-Object {
		Write-Host "Starting ConfigMgr action: $($_.Name)"
		$_.PerformAction()
	}
}

(To do this you need to set a security GPO to the HKLM-key so that your users are allowed to write there.)

Get ConfigMgr Collection rules

I’m in the process of installing Forefront Endpoint Protection and wanted to look at some of the collection queries that was created… but with the ConfigMgr console you cant view them…

So Powershell it is.

Did a function that you can use on any collection (with subcollections) to view the WQL.

Import-Module SCCM\SCCM-Functions -Force
Function Get-CollectionRules {
	PARAM (
		$parentCollection,
		$spacer,
		$sccm
	)

	$subCollections = Get-SCCMSubCollections -SccmServer $sccm -CollectionID $parentCollection
	
	if ($subCollections -ne $null) {
		$subCollections | ForEach-Object {
			$collection = Get-SCCMCollection -Filter "CollectionID='$($_.subCollectionID)'" -SccmServer $sccm
			Write-Host "$($spacer) Name: " -ForegroundColor Yellow -NoNewline
			Write-Host "$($collection.CollectionID) - $($collection.Name)"

			$collectionRule = (Get-SCCMCollectionRules -SccmServer ( Connect-SCCMServer ) -CollectionID $collection.CollectionID)
			if ($collectionRule -ne $null) {
				Write-Host "$($spacer)Limit: " -ForegroundColor Yellow -NoNewline
				if ($collectionRule.LimitToCollectionID.Length -gt 0) {
					Write-Host "$($collectionRule.LimitToCollectionID)" -ForegroundColor White
				} else {
					Write-Host "<No limit to collection>" -ForegroundColor Gray
				}

				Write-Host "$($spacer)  WQL: " -ForegroundColor Yellow -NoNewline
				Write-Host "$($collectionRule.QueryExpression)"
			} else {
				Write-Host "$($spacer)<no rule present on collection>" -ForegroundColor Gray
			}
			Write-Host ""

			Get-CollectionRules -parentCollection $_.subCollectionID -spacer "   $($spacer)" -sccm $sccm
		}
	}
}

Get-CollectionRules -parentCollection "XYZ00123" -spacer "" -sccm (Connect-SCCMServer)

A small warning: It will loop all of the subcollections, and the subcollections subcollections, and so on…

SCCM PoSH

Changelog

  • 2013-05-09 (Ricardo Cheing)
    Bugfix: Add-SCCMDirUserCollectionRule (Corrected Get-User to Get-SCCMUser)
  • 2010-10-29 (Rikard Ronnkvist)
    New functions: Update-SCCMDriverPkgSourcePath, Update-SCCMPackageSourcePath, Update-SCCMDriverSourcePath
  • 2010-10-06 (Stefan Ringler)
    New and updated functions from http://www.stefanringler.com/?p=150 (New-SCCMPackage, New-SCCMAdvertisement, New-SCCMProgram, Add-SCCMDistributionPoint)
  • 2010-09-13 (Rikard Ronnkvist)
    Bugfix: Get-SCCMCollectionMembers (Thanks to Milos)
    Bugfix: Add-SCCMCollectionRule (Thanks to Luigi)
  • 2010-03-26 (Rikard Ronnkvist)
    Separate page on snowland.se
    New function: New-SCCMPackage
  • 2010-03-23 (Rikard Ronnkvist)
    Fixed some small bugs
    Added limitToCollectionId in Add-SCCMCollectionRule
  • 2010-03-10 (Rikard Ronnkvist)
    Major makeover
    First snowland.se release
  • 2009-04-07 (Michael Niehaus)
    Original code posted at http://blogs.technet.com/mniehaus/

Usage:

  • Save the file as SCCM-Commands.psm1
  • PS:>Import-Module SCCM-Commands
  • PS:>Get-SCCMCommands

SCCM-Commands.psm1

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                                                            Rikard Ronnkvist / snowland.se
#  Usage:
#   Save the file as SCCM-Commands.psm1
#   PS:>Import-Module SCCM-Commands
#   PS:>Get-SCCMCommands
#
#  2009-04-07   Michael Niehaus     Original code posted at http://blogs.technet.com/mniehaus/
#  2010-03-10   Rikard Ronnkvist    Major makeover and first snowland.se release
#  2010-03-23   Rikard Ronnkvist    Fixed some small bugs and added limitToCollectionId in Add-SCCMCollectionRule
#  2010-03-26   Rikard Ronnkvist    New function: New-SCCMPackage
#  2010-09-13   Rikard Ronnkvist    Bugfixes to Add-SCCMCollectionRule and Get-SCCMCollectionMembers (Thanks to comments on snowland.se from Milos and Luigi)
#  2010-10-06   Stefan Ringler      New and updated functions from http://www.stefanringler.com/?p=150 (New-SCCMPackage, New-SCCMAdvertisement, New-SCCMProgram, Add-SCCMDistributionPoint)
#  2010-10-29   Rikard Ronnkvist    New functions: Update-SCCMDriverPkgSourcePath, Update-SCCMPackageSourcePath, Update-SCCMDriverSourcePath
#  2013-05-09   Ricardo Cheing      Bugfix: Add-SCCMDirUserCollectionRule (Corrected Get-User to Get-SCCMUser)
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Get-SCCMCommands {
	# List all SCCM-commands
	[CmdletBinding()]
	PARAM ()
	PROCESS {
		return Get-Command -Name *-SCCM* -CommandType Function  | Sort-Object Name | Format-Table Name, Module
	}
}

Function Connect-SCCMServer {
	# Connect to one SCCM server
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$false,HelpMessage="SCCM Server Name or FQDN",ValueFromPipeline=$true)][Alias("ServerName","FQDN","ComputerName")][String] $HostName = (Get-Content env:computername),
		[Parameter(Mandatory=$false,HelpMessage="Optional SCCM Site Code",ValueFromPipelineByPropertyName=$true )][String] $siteCode = $null,
		[Parameter(Mandatory=$false,HelpMessage="Credentials to use" )][System.Management.Automation.PSCredential] $credential = $null
	)

	PROCESS {
		# Get the pointer to the provider for the site code
		if ($siteCode -eq $null -or $siteCode -eq "") {
			Write-Verbose "Getting provider location for default site on server $HostName"
			if ($credential -eq $null) {
				$sccmProviderLocation = Get-WmiObject -query "select * from SMS_ProviderLocation where ProviderForLocalSite = true" -Namespace "root\sms" -computername $HostName -errorAction Stop
			} else {
				$sccmProviderLocation = Get-WmiObject -query "select * from SMS_ProviderLocation where ProviderForLocalSite = true" -Namespace "root\sms" -computername $HostName -credential $credential -errorAction Stop
			}
		} else {
			Write-Verbose "Getting provider location for site $siteCode on server $HostName"
			if ($credential -eq $null) {
				$sccmProviderLocation = Get-WmiObject -query "SELECT * FROM SMS_ProviderLocation where SiteCode = '$siteCode'" -Namespace "root\sms" -computername $HostName -errorAction Stop
			} else {
				$sccmProviderLocation = Get-WmiObject -query "SELECT * FROM SMS_ProviderLocation where SiteCode = '$siteCode'" -Namespace "root\sms" -computername $HostName -credential $credential -errorAction Stop
			}
		}

		# Split up the namespace path
		$parts = $sccmProviderLocation.NamespacePath -split "\\", 4
		Write-Verbose "Provider is located on $($sccmProviderLocation.Machine) in namespace $($parts[3])"

		# Create a new object with information
		$retObj = New-Object -TypeName System.Object
		$retObj | add-Member -memberType NoteProperty -name Machine -Value $HostName
		$retObj | add-Member -memberType NoteProperty -name Namespace -Value $parts[3]
		$retObj | add-Member -memberType NoteProperty -name SccmProvider -Value $sccmProviderLocation

		return $retObj
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Get-SCCMObject {
	#  Generic query tool
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipelineByPropertyName=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="SCCM Class to query",ValueFromPipeline=$true)][Alias("Table","View")][String] $class,
		[Parameter(Mandatory=$false,HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		if ($Filter -eq $null -or $Filter -eq "")
		{
			Write-Verbose "WMI Query: SELECT * FROM $class"
			$retObj = get-wmiobject -class $class -computername $SccmServer.Machine -namespace $SccmServer.Namespace
		}
		else
		{
			Write-Verbose "WMI Query: SELECT * FROM $class WHERE $Filter"
			$retObj = get-wmiobject -query "SELECT * FROM $class WHERE $Filter" -computername $SccmServer.Machine -namespace $SccmServer.Namespace
		}

		return $retObj
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Get-SCCMPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Package" -Filter $Filter
	}
}

Function Get-SCCMCollection {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Collection" -Filter $Filter
	}
}

Function Get-SCCMAdvertisement {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Advertisement" -Filter $Filter
	}
}

Function Get-SCCMDriver {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Driver" -Filter $Filter
	}
}

Function Get-SCCMDriverPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_DriverPackage" -Filter $Filter
	}
}

Function Get-SCCMTaskSequence {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_TaskSequence" -Filter $Filter
	}
}

Function Get-SCCMSite {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_Site" -Filter $Filter
	}
}

Function Get-SCCMImagePackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_ImagePackage" -Filter $Filter
	}
}

Function Get-SCCMOperatingSystemInstallPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_OperatingSystemInstallPackage" -Filter $Filter
	}
}

Function Get-SCCMBootImagePackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Optional Filter on query")][String] $Filter = $null
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_BootImagePackage" -Filter $Filter
	}
}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function Get-SCCMComputer {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Filter on SCCM Resource ID",ValueFromPipelineByPropertyName=$true)][int32] $ResourceID = $false,
		[Parameter(Mandatory=$false, HelpMessage="Filter on Netbiosname on computer",ValueFromPipeline=$true)][String] $NetbiosName = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on Domain name",ValueFromPipelineByPropertyName=$true)][Alias("Domain", "Workgroup")][String] $ResourceDomainOrWorkgroup = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on SmbiosGuid (UUID)")][String] $SmBiosGuid = "%"
	)

	PROCESS {
		if ($ResourceID -eq $false -and $NetbiosName -eq "%" -and $ResourceDomainOrWorkgroup -eq "%" -and $SmBiosGuid -eq "%") {
			throw "Need at least one filter..."
		}

		if ($ResourceID -eq $false) {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_System" -Filter "NetbiosName LIKE '$NetbiosName' AND ResourceDomainOrWorkgroup LIKE '$ResourceDomainOrWorkgroup' AND SmBiosGuid LIKE '$SmBiosGuid'"
		} else {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_System" -Filter "ResourceID = $ResourceID"
		}
	}
}

Function Get-SCCMUser {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Filter on SCCM Resource ID",ValueFromPipelineByPropertyName=$true)][int32] $ResourceID = $false,
		[Parameter(Mandatory=$false, HelpMessage="Filter on unique username in form DOMAIN\UserName",ValueFromPipelineByPropertyName=$true)][String] $UniqueUserName = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on Domain name",ValueFromPipelineByPropertyName=$true)][Alias("Domain")][String] $WindowsNTDomain = "%",
		[Parameter(Mandatory=$false, HelpMessage="Filter on UserName",ValueFromPipeline=$true)][String] $UserName = "%"
	)

	PROCESS {
		if ($ResourceID -eq $false -and $UniqueUserName -eq "%" -and $WindowsNTDomain -eq "%" -and $UserName -eq "%") {
			throw "Need at least one filter..."
		}

		if ($ResourceID -eq $false) {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_User" -Filter "UniqueUserName LIKE '$UniqueUserName' AND WindowsNTDomain LIKE '$WindowsNTDomain' AND UserName LIKE '$UserName'"
		} else {
			return Get-SCCMObject -sccmServer $SccmServer -class "SMS_R_User" -Filter "ResourceID = $ResourceID"
		}
	}
}

Function Get-SCCMCollectionMembers {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="CollectionID", ValueFromPipeline=$true)][String] $CollectionID
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_CollectionMember_a" -Filter "CollectionID = '$CollectionID'"
	}
}

Function Get-SCCMSubCollections {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="CollectionID",ValueFromPipeline=$true)][Alias("parentCollectionID")][String] $CollectionID
	)

	PROCESS {
		return Get-SCCMObject -sccmServer $SccmServer -class "SMS_CollectToSubCollect" -Filter "parentCollectionID = '$CollectionID'"
	}
}

Function Get-SCCMParentCollection {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="CollectionID",ValueFromPipeline=$true)][Alias("subCollectionID")][String] $CollectionID
	)

	PROCESS {
		$parentCollection = Get-SCCMObject -sccmServer $SccmServer -class "SMS_CollectToSubCollect" -Filter "subCollectionID = '$CollectionID'"

		return Get-SCCMCollection -sccmServer $SccmServer -Filter "CollectionID = '$($parentCollection.parentCollectionID)'"
	}
}

Function Get-SCCMSiteDefinition {
	# Get all definitions for one SCCM site
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer
	)

	PROCESS {
		Write-Verbose "Refresh the site $($SccmServer.SccmProvider.SiteCode) control file"
		Invoke-WmiMethod -path SMS_SiteControlFile -name RefreshSCF -argumentList $($SccmServer.SccmProvider.SiteCode) -computername $SccmServer.Machine -namespace $SccmServer.Namespace

		Write-Verbose "Get the site definition object for this site"
		return get-wmiobject -query "SELECT * FROM SMS_SCI_SiteDefinition WHERE SiteCode = '$($SccmServer.SccmProvider.SiteCode)' AND FileType = 2" -computername $SccmServer.Machine -namespace $SccmServer.Namespace
	}
}

Function Get-SCCMSiteDefinitionProps {
	# Get definitionproperties for one SCCM site
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer
	)

	PROCESS {
		return Get-SCCMSiteDefinition -sccmServer $SccmServer | ForEach-Object { $_.Props }
	}
}

Function Get-SCCMIsR2 {
	# Return $true if the SCCM server is R2 capable
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer
	)

	PROCESS {
		$result = Get-SCCMSiteDefinitionProps -sccmServer $SccmServer | ? {$_.PropertyName -eq "IsR2CapableRTM"}
		if (-not $result) {
			return $false
		} elseif ($result.Value = 31) {
			return $true
		} else {
			return $false
		}
	}
}

Function Get-SCCMCollectionRules {
	# Get a set of all collectionrules
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="CollectionID", ValueFromPipeline=$true)][String] $CollectionID
	)

	PROCESS {
		Write-Verbose "Collecting rules for $CollectionID"
		$col = [wmi]"$($SccmServer.SccmProvider.NamespacePath):SMS_Collection.CollectionID='$($CollectionID)'"

		return $col.CollectionRules
	}
}

Function Get-SCCMInboxes {
	# Give a count of files in the SCCM-inboxes
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server",ValueFromPipeline=$true)][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$false, HelpMessage="Minimum number of files in directory")][int32] $minCount = 1
	)

	PROCESS {
		Write-Verbose "Reading \\$($SccmServer.Machine)\SMS_$($SccmServer.SccmProvider.SiteCode)\inboxes"
		return Get-ChildItem \\$($SccmServer.Machine)\SMS_$($SccmServer.SccmProvider.SiteCode)\inboxes -Recurse | Group-Object Directory | Where { $_.Count -gt $minCount } | Format-Table Count, Name -AutoSize
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Function New-SCCMCollection {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Collection Name", ValueFromPipeline=$true)][String] $name,
		[Parameter(Mandatory=$false, HelpMessage="Collection comment")][String] $comment = "",
		[Parameter(Mandatory=$false, HelpMessage="Refresh Rate in Minutes")] [ValidateRange(0, 59)] [int] $refreshMinutes = 0,
		[Parameter(Mandatory=$false, HelpMessage="Refresh Rate in Hours")] [ValidateRange(0, 23)] [int] $refreshHours = 0,
		[Parameter(Mandatory=$false, HelpMessage="Refresh Rate in Days")] [ValidateRange(0, 31)] [int] $refreshDays = 0,
		[Parameter(Mandatory=$false, HelpMessage="Parent CollectionID")][String] $parentCollectionID = "COLLROOT"
	)

	PROCESS {
		# Build the parameters for creating the collection
		$arguments = @{Name = $name; Comment = $comment; OwnedByThisSite = $true}
		$newColl = Set-WmiInstance -class "SMS_Collection" -arguments $arguments -computername $SccmServer.Machine -namespace $SccmServer.Namespace

		# Hack - for some reason without this we don't get the CollectionID value
		$hack = $newColl.PSBase | select * | out-null

		# It's really hard to set the refresh schedule via Set-WmiInstance, so we'll set it later if necessary
		if ($refreshMinutes -gt 0 -or $refreshHours -gt 0 -or $refreshDays -gt 0)
		{
			Write-Verbose "Create the recur interval object"
			$intervalClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_ST_RecurInterval"
			$interval = $intervalClass.CreateInstance()
			if ($refreshMinutes -gt 0) {
				$interval.MinuteSpan = $refreshMinutes
			}
			if ($refreshHours -gt 0) {
				$interval.HourSpan = $refreshHours
			}
			if ($refreshDays -gt 0) {
				$interval.DaySpan = $refreshDays
			}

			Write-Verbose "Set the refresh schedule"
			$newColl.RefreshSchedule = $interval
			$newColl.RefreshType=2
			$path = $newColl.Put()
		}   

		Write-Verbose "Setting the new $($newColl.CollectionID) parent to $parentCollectionID"
		$subArguments  = @{SubCollectionID = $newColl.CollectionID}
		$subArguments += @{ParentCollectionID = $parentCollectionID}

		# Add the link
		$newRelation = Set-WmiInstance -Class "SMS_CollectToSubCollect" -arguments $subArguments -computername $SccmServer.Machine -namespace $SccmServer.Namespace

		Write-Verbose "Return the new collection with ID $($newColl.CollectionID)"
		return $newColl
	}
}

Function Add-SCCMCollectionRule {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true,  HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true,  HelpMessage="CollectionID", ValueFromPipelineByPropertyName=$true)] $collectionID,
		[Parameter(Mandatory=$false, HelpMessage="Computer name to add (direct)", ValueFromPipeline=$true)] [String] $name,
		[Parameter(Mandatory=$false, HelpMessage="WQL Query Expression", ValueFromPipeline=$true)] [String] $queryExpression = $null,
		[Parameter(Mandatory=$false, HelpMessage="Limit to collection (Query)", ValueFromPipeline=$false)] [String] $limitToCollectionId = $null,
		[Parameter(Mandatory=$true,  HelpMessage="Rule Name", ValueFromPipeline=$true)] [String] $queryRuleName
	)

	PROCESS {
		# Get the specified collection (to make sure we have the lazy properties)
		$coll = [wmi]"$($SccmServer.SccmProvider.NamespacePath):SMS_Collection.CollectionID='$collectionID'"

		# Build the new rule
		if ($queryExpression.Length -gt 0) {
			# Create a query rule
			$ruleClass = [WMICLASS]"$($SccmServer.SccmProvider.NamespacePath):SMS_CollectionRuleQuery"
			$newRule = $ruleClass.CreateInstance()
			$newRule.RuleName = $queryRuleName
			$newRule.QueryExpression = $queryExpression
			if ($limitToCollectionId -ne $null) {
				$newRule.LimitToCollectionID = $limitToCollectionId
			}

			$null = $coll.AddMembershipRule($newRule)
		} else {
			$ruleClass = [WMICLASS]"$($SccmServer.SccmProvider.NamespacePath):SMS_CollectionRuleDirect"

			# Find each computer
			$computer = Get-SCCMComputer -sccmServer $SccmServer -NetbiosName $name
			# See if the computer is already a member
			$found = $false
			if ($coll.CollectionRules -ne $null) {
				foreach ($member in $coll.CollectionRules) {
					if ($member.ResourceID -eq $computer.ResourceID) {
						$found = $true
					}
				}
			}
			if (-not $found) {
				Write-Verbose "Adding new rule for computer $name"
				$newRule = $ruleClass.CreateInstance()
				$newRule.RuleName = $name
				$newRule.ResourceClassName = "SMS_R_System"
				$newRule.ResourceID = $computer.ResourceID

				$null = $coll.AddMembershipRule($newRule)
			} else {
				Write-Verbose "Computer $name is already in the collection"
			}
		}
	}
}

Function Add-SCCMDirUserCollectionRule {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(ValueFromPipelineByPropertyName=$true)][String] $CollectionID,
		[Parameter(ValueFromPipeline=$true)][String] $UserName
	)

	PROCESS {
		$coll = [wmi]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_Collection.CollectionID='$CollectionID'"
		$ruleClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_CollectionRuleDirect"

		$RuleClass
		$UserRule=Get-SCCMUser "userName='$UserName'"
		$NewRuleName=$UserRule.name
		$NewRuleResourceID = $UserRule.ResourceID
		$newRule = $ruleClass.CreateInstance()

		$newRule.RuleName = $NewRuleName
		$newRule.ResourceClassName = "SMS_R_User"
		$newRule.ResourceID = $NewRuleResourceID

		$null = $coll.AddMembershipRule($newRule)
		$coll.requestrefresh()
		Clear-Variable -name oldrule -errorAction SilentlyContinue
		Clear-Variable -name Coll -errorAction SilentlyContinue
	}
}

Function New-SCCMPackage {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Package Name", ValueFromPipeline=$true)][String] $Name,

		[Parameter(Mandatory=$false, HelpMessage="Package Version")][String] $Version = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Manufacturer")][String] $Manufacturer = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Language")][String] $Language = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Description")][String] $Description = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Data Source Path")][String] $PkgSourcePath = "",
		[Parameter(Mandatory=$false, HelpMessage="Package Sharename")][String] $PkgShareName = ""
	)

	PROCESS {
		$packageClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_Package"
		$newPackage = $packageClass.createInstance() 

		$newPackage.Name = $Name
		if ($Version -ne "") 		{ $newPackage.Version = $Version }
		if ($Manufacturer -ne "") 	{ $newPackage.Manufacturer = $Manufacturer }
		if ($Language -ne "") 		{ $newPackage.Language = $Language }
		if ($Description -ne "") 	{ $newPackage.Description = $Description }

		if ($PkgSourcePath -ne "") {
			$newPackage.PkgSourceFlag = 2  # Direct (3 = Compressed)
			$newPackage.PkgSourcePath = $PkgSourcePath
			if ($PkgShareName -ne "") {
				$newPackage.ShareName = $PkgShareName
				$newPackage.ShareType = 2
			}
		} else {
			$newPackage.PkgSourceFlag = 1  # No source
			$newPackage.PkgSourcePath = $null
		}
		$newPackage.Put()

		$newPackage.Get()
		Write-Verbose "Return the new package with ID $($newPackage.PackageID)"
		return $newPackage
	}
}

Function New-SCCMAdvertisement {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true)] $AdvertisementName,
		[Parameter(Mandatory=$true)] $collectionID,
		[Parameter(Mandatory=$true)] $PackageID,
		[Parameter(Mandatory=$true)] $ProgramName,
		[Switch] $Download,
		[Parameter(Mandatory=$false, HelpMessage="YYYYMMDDhhmm")] $StartTime,
		[Parameter(Mandatory=$false, HelpMessage="YYYYMMDDhhmm")] $EndTime,
		[Parameter(Mandatory=$false, HelpMessage="YYYYMMDDhhmm")] $MandatoryTime
	)
	PROCESS {
		$strServer = $SccmServer.machine
		$strNamespace= $SccmServer.namespace
		$AdvClass = [WmiClass]("\\$strServer\" + "$strNameSpace" + ":SMS_Advertisement")
		if ($Download) {
			$RemoteClientFlags = "3152"
		} else {
			$RemoteClientFlags = "3208"
		}
		if ($StartTime -ne $null) {
			$PresentTime = $StartTime + "00.000000+***"
		} else {
			$PresentTime = "20200110000000.000000+***"
		}
		if ($EndTime -ne $null) {
			$ExpirationTime = $Endtime + "00.000000+***"
			$ExpirationTimeEnabled = $true
		} else {
			$ExpirationTime = "20200113000000.000000+***"
			$ExpirationTimeEnabled = $false
		}
		if ($MandatoryTime -ne $null) {
			$Deadline = $MandatoryTime + "00.000000+***"
		} else {
			$Deadline = $null
		}

		# Get the all the Advertisement Properties
		$newAdvertisement = $AdvClass.CreateInstance()
		$newAdvertisement.AdvertisementName = $AdvertisementName
		$newAdvertisement.CollectionID = $collectionID
		$newAdvertisement.PackageID = $PackageID
		$newAdvertisement.ProgramName = $ProgramName
		$newAdvertisement.RemoteClientFlags = $RemoteClientFlags
		$newAdvertisement.PresentTime = $PresentTime
		$newAdvertisement.ExpirationTime = $ExpirationTime
		$newAdvertisement.ExpirationTimeEnabled = $ExpirationTimeEnabled
		$newAdvertisement.Priority = "2"
		$newAdvertisement.IncludeSubCollection = $false

		# Create Advertisement
		$retval = $newAdvertisement.psbase.Put()
		if ($Deadline -ne $null) {
			# Create Mandatory Schedule
			$wmiClassSchedule = [WmiClass]("\\$strServer\" + "$strNameSpace" + ":SMS_ST_NonRecurring")
			$AssignedSchedule = $wmiClassSchedule.psbase.createinstance()
			$AssignedSchedule.starttime = $Deadline
			if ($Download) {
				$newAdvertisement.RemoteClientFlags = "9296"
			} else {
				$newAdvertisement.RemoteClientFlags = "9352"
			}
			$newAdvertisement.AssignedSchedule = $AssignedSchedule
			$newAdvertisement.AssignedScheduleEnabled = $true
			$newAdvertisement.psbase.put()
			$NewAdvertisementProperties = $newAdvertisement.AssignedSchedule
			foreach ($Adv in $NewAdvertisementProperties) {
				write-verbose "Created Advertisement. Name = $($newAdvertisement.AdvertisementName)"
				write-verbose "Created Advertisement. ID = $newAdvertisement"
				Write-Verbose "Mandatory Deadline created: $($Adv.StartTime)"
			}
		} else {
			write-verbose "Created Advertisement. Name = $($newAdvertisement.AdvertisementName)"
			write-verbose "Created Advertisement. ID = $newAdvertisement"
			write-verbose "No Mandatory-Deadline defined"
		}
	}
}

Function New-SCCMProgram {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Program Name")][String] $PrgName = "",
		[Parameter(Mandatory=$true, HelpMessage="Program PackageID")]$PrgPackageID,
		[Parameter(Mandatory=$false, HelpMessage="Program Comment")][String] $PrgComment = "",
		[Parameter(Mandatory=$false, HelpMessage="Program CommandLine")][String] $PrgCommandLine = "",
		[Parameter(Mandatory=$false, HelpMessage="Program MaxRunTime")]$PrgMaxRunTime,
		[Parameter(Mandatory=$false, HelpMessage="Program Diskspace Requirement")]$PrgSpaceReq,
		[Parameter(Mandatory=$false, HelpMessage="Program Working Directory")][String] $PrgWorkDir = "",
		[Parameter(Mandatory=$false, HelpMessage="Program Flags")] $PrgFlags
	)
	PROCESS {
		$programClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_Program"
		$newProgram = $programClass.createInstance()
		$newProgram.ProgramName = $PrgName
		$newProgram.PackageID = $PrgPackageID
		if ($PrgComment -ne "") { $newProgram.Comment = $PrgComment }
		if ($PrgCommandLine -ne "") { $newProgram.CommandLine = $PrgCommandLine }
		if ($PrgMaxRunTime -ne $null) { $newProgram.Duration = $PrgMaxRunTime} else { $newProgram.Duration = "0" }
		if ($PrgSpaceReq -ne $null) { $newProgram.DiskSpaceReq = $PrgSpaceReq }
		if ($PrgWorkDir -ne "") { $newProgram.WorkingDirectory = $PrgWorkDir }
		if ($PrgFlags -ne $null) { $newProgram.ProgramFlags = $PrgFlags} else { $newProgram.ProgramFlags = "135290880" }
		$newProgram.Put()
		$newProgram.Get()
		Write-Verbose "Return the new program for Package $($newProgram.PackageID)"
		return $newProgram
	}
}

Function Add-SCCMDistributionPoint {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="PackageID")][String] $DPPackageID,
		[Parameter(Mandatory=$false, HelpMessage="DistributionPoint Servername")][String]$DPName = "",
		[Parameter(Mandatory=$false, HelpMessage="All DistributionPoints of SiteCode")][String] $DPsSiteCode = "",
		[Parameter(Mandatory=$false, HelpMessage="Distribution Point Group")][String] $DPGroupName = "",
		[Switch] $AllDPs
	)
	PROCESS {
		if ($DPName -ne "") {
			$Resource = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point' and Servername = '$DPName'"
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			$newDistributionPoint.ServerNALPath = $Resource.NALPath
			$newDistributionPoint.SiteCode = $Resource.SiteCode
			$newDistributionPoint.Put()
			$newDistributionPoint.Get()
			Write-Verbose "Assigned Package: $($newDistributionPoint.PackageID)"
		}
		if ($DPsSiteCode -ne "") {
			$ListOfResources = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point' and SiteCode = '$DPsSiteCode'"
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			foreach ($resource in $ListOfResources) {
				$newDistributionPoint.ServerNALPath = $Resource.NALPath
				$newDistributionPoint.SiteCode = $Resource.SiteCode
				$newDistributionPoint.Put()
				$newDistributionPoint.Get()
				Write-Verbose "Assigned Package: $($newDistributionPoint.PackageID)"
			}
		}
		if ($DPGroupName -ne "") {
			$DPGroup = Get-SCCMObject -sccmserver $SccmServer -class SMS_DistributionPointGroup -Filter "sGroupName = '$DPGroupName'"
			$DPGroupNALPaths = $DPGroup.arrNALPath
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			foreach ($DPGroupNALPath in $DPGroupNALPaths) {
				$DPResource = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point'" | Where-Object {$_.NALPath -eq $DPGroupNALPath}
				if ($DPResource -ne $null) {
					Write-Verbose "$DPResource"
					$newDistributionPoint.ServerNALPath = $DPResource.NALPath
					Write-Verbose "ServerNALPath = $($newDistributionPoint.ServerNALPath)"
					$newDistributionPoint.SiteCode = $DPResource.SiteCode
					Write-Verbose "SiteCode = $($newDistributionPoint.SiteCode)"
					$newDistributionPoint.Put()
					$newDistributionPoint.Get()
					Write-Host "Assigned Package: $($newDistributionPoint.PackageID) to $($DPResource.ServerName)"
				} else {
					Write-Host "DP not found = $DPGroupNALPath"
				}
			}
		}
		if ($AllDPs) {
			$ListOfResources = Get-SCCMObject -SccmServer $SccmServer -class SMS_SystemResourceList -Filter "RoleName = 'SMS Distribution Point'"
			$DPClass = [WMICLASS]"\\$($SccmServer.Machine)\$($SccmServer.Namespace):SMS_DistributionPoint"
			$newDistributionPoint = $DPClass.createInstance()
			$newDistributionPoint.PackageID = $DPPackageID
			foreach ($resource in $ListOfResources) {
				$newDistributionPoint.ServerNALPath = $Resource.NALPath
				$newDistributionPoint.SiteCode = $Resource.SiteCode
				$newDistributionPoint.Put()
				$newDistributionPoint.Get()
				Write-Verbose "Assigned Package: $($newDistributionPoint.PackageID) $($newDistributionPoint.ServerNALPath)"
			}
		}
	}
}

Function Update-SCCMDriverPkgSourcePath {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Current Path", ValueFromPipeline=$true)][String] $currentPath,
		[Parameter(Mandatory=$true, HelpMessage="New Path", ValueFromPipeline=$true)][String] $newPath
	)

	PROCESS {
		Get-SCCMDriverPackage -sccmserver $SccmServer | Where-Object {$_.PkgSourcePath -ilike "*$($currentPath)*" } | Foreach-Object {
			$newSourcePath = ($_.PkgSourcePath -ireplace [regex]::Escape($currentPath), $newPath)
			Write-Verbose "Changing from '$($_.PkgSourcePath)' to '$($newSourcePath)' on $($_.PackageID)"
			$_.PkgSourcePath = $newSourcePath
			$_.Put() | Out-Null
		}
	}
}

Function Update-SCCMPackageSourcePath {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Current Path", ValueFromPipeline=$true)][String] $currentPath,
		[Parameter(Mandatory=$true, HelpMessage="New Path", ValueFromPipeline=$true)][String] $newPath
	)

	PROCESS {
		Get-SCCMPackage -sccmserver $SccmServer | Where-Object {$_.PkgSourcePath -ilike "*$($currentPath)*" } | Foreach-Object {
			$newSourcePath = ($_.PkgSourcePath -ireplace [regex]::Escape($currentPath), $newPath)
			Write-Verbose "Changing from '$($_.PkgSourcePath)' to '$($newSourcePath)' on $($_.PackageID)"
			$_.PkgSourcePath = $newSourcePath
			$_.Put() | Out-Null
		}
	}
}

Function Update-SCCMDriverSourcePathnotepad {
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory=$true, HelpMessage="SCCM Server")][Alias("Server","SmsServer")][System.Object] $SccmServer,
		[Parameter(Mandatory=$true, HelpMessage="Current Path", ValueFromPipeline=$true)][String] $currentPath,
		[Parameter(Mandatory=$true, HelpMessage="New Path", ValueFromPipeline=$true)][String] $newPath
	)

	PROCESS {
		Get-SCCMDriver -sccmserver $SccmServer | Where-Object {$_.ContentSourcePath -ilike "*$($currentPath)*" } | Foreach-Object {
			$newSourcePath = ($_.ContentSourcePath -ireplace [regex]::Escape($currentPath), $newPath)
			Write-Verbose "Changing from '$($_.ContentSourcePath)' to '$($newSourcePath)' on $($_.PackageID)"
			$_.ContentSourcePath = $newSourcePath
			$_.Put() | Out-Null
		}
	}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# EOF

Examples

# List all available SCCM commands
Get-SCCMCommands

# Create an SCCM-Connection to the local server
$sccm = Connect-SCCMServer -Verbose

# Create a new collection with a querybased collection rule and a direct member
$newCollection = New-SCCMCollection -SccmServer $sccm -name "Some Collection Name" -Verbose
Add-SCCMCollectionRule -Server $sccm -collectionID $newRoot.CollectionId -queryExpression "SELECT * FROM SMS_R_System" -queryRuleName "All Systems" -Verbose
Add-SCCMCollectionRule -Server $sccm -collectionID $newRoot.CollectionId -name "COMPUTER123" -Verbose

# Count files in the inboxes
$sccm | Get-SCCMInboxes

# Get a package
$MyPackage = Get-SCCMPackage -server $sccm -filter "Name = 'Some Package Name'" 

Manufacturer / Model Collections with hierarchy

The last post made a flat structure of collections with “Manufacturer – Model”, in this post the script creates a hierarchy with (almost) the same collections.


The Model-collections queries are limited to the parent Manufacturer-collection.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                                                            Rikard Ronnkvist / snowland.se
#  Usage:
#   Download and install http://www.snowland.se/sccm-posh/
#   Save the file as CreateMM-collections-Hierarchy.ps1
#   PS:>.\CreateMM-collections-Hierarchy.ps1 -rootCollectionName "Name Of Some Collection"
#
#  2010-03-24   Rikard Ronnkvist    First snowland.se release
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PARAM (
	[string] $rootCollectionName = $(throw "rootCollectionName required."),
	[string] $hostName = (Get-Content env:computername),
	[switch] $Verbose,
	[Switch] $WhatIf
)

if ($verbose.IsPresent) {
	$VerbosePreference = 'Continue'
} Else {
	$VerbosePreference = 'SilentlyContinue'
}

Import-Module SCCM\SCCM-Functions -Force

Write-Verbose "Connect to SCCM-server $($hostName)"
$sccm = Connect-SCCMServer -HostName $hostName

Write-Host "Get root collection: ""$($rootCollectionName)"""
$rootCollection = Get-SCCMCollection -filter "Name='$($rootCollectionName)'" -sccmserver $sccm
if (!$rootCollection) {
	throw "Cant find ""$($rootCollectionName)"""
}
Write-Host "Found collection: $($rootCollection.CollectionID)"


Function checkAndCreate ($CollectionName, $ParentCollectionID, $wql, $limit = $null) {
	Write-Host "Checking ""$($CollectionName)""" -ForegroundColor Cyan
	$newCollection = Get-SCCMCollection -filter "Name='$($CollectionName)'" -sccmserver $sccm
	
	if (!$newCollection) {
		if (!$WhatIf.IsPresent) {
			Write-Host "Creating collection: ""$($CollectionName)"""
			$newCollection = New-SCCMCollection -name "$($CollectionName)" -SccmServer $sccm -parentCollectionID $ParentCollectionID -refreshDays 1 -Verbose
		} else {
			Write-Host "What if: Creating collection: ""$($CollectionName)""" -ForegroundColor Red
		}

		if (!$WhatIf.IsPresent) {
			Write-Verbose "Adding rule with WQL: $wql"
			Add-SCCMCollectionRule -queryExpression $wql -Server $sccm -collectionID $newCollection.CollectionId -queryRuleName $CollectionName -limitToCollectionId $limit
		} else {
			Write-Host "What if: Adding collection rule to new collection with wql: $($wql)" -ForegroundColor Red
		}
	} else {
		Write-Host "Found collection ""$($CollectionName)"""
	}
	
	return $newCollection
}

Write-Host "Lookup Manufacturer and Model"
$Manufacturer = Get-wmiobject -query "SELECT DISTINCT Manufacturer FROM SMS_G_System_COMPUTER_SYSTEM" -computername $Sccm.Machine -namespace $Sccm.Namespace | Sort-Object Manufacturer, Model
$Manufacturer | ForEach-Object {
	$wql = "SELECT * FROM SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_COMPUTER_SYSTEM.Manufacturer = '$($_.Manufacturer)'"
	$ManufacturerCollection = checkAndCreate -collectionName $_.Manufacturer -ParentCollectionID $rootCollection.CollectionId -wql $wql -limit $null

	$Model = Get-wmiobject -query "SELECT DISTINCT Model FROM SMS_G_System_COMPUTER_SYSTEM WHERE Manufacturer = '$($ManufacturerCollection.Name)'" -computername $Sccm.Machine -namespace $Sccm.Namespace | Sort-Object Manufacturer, Model
	$Model | ForEach-Object {
		$wql = "SELECT * FROM SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_COMPUTER_SYSTEM.Model = '$($_.Model)'"
		$ModelCollection = checkAndCreate -collectionName $_.Model -ParentCollectionID $ManufacturerCollection.CollectionId -wql $wql -limit $ManufacturerCollection.CollectionId
	}
}

Manufacturer / Model Collections

You have probably created one or two collections that points to a specific Manufacturer and/or Model.

Well, this script will look in to your SCCM-database and create that kind of collections for you.

First you need my SCCM Module for PowerShell
Then I created a collection named “000 – Manufacturer – Model”
Copy and paste the code below to a file, save it as CreateMM-collections.ps1
Run with at least one param, -rootCollectionName
Example: .\CreateMM-collections.ps1 -rootCollectionName “000 – Manufacturer – Model”

The script support the -WhatIf and -Verbose parameters… might be good to have when testing.

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#                                                                                                                            Rikard Ronnkvist / snowland.se
#  Usage:
#   Download and install http://www.snowland.se/sccm-posh/
#   Save the file as CreateMM-collections.ps1
#   PS:>.\CreateMM-collections.ps1 -rootCollectionName "Name Of Some Collection"
#
#  2010-03-23   Rikard Ronnkvist    First snowland.se release
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PARAM (
	[string] $rootCollectionName = $(throw "rootCollectionName required."),
	[string] $hostName = (Get-Content env:computername),
	[switch] $Verbose,
	[Switch] $WhatIf
)

if ($verbose.IsPresent) {
	$VerbosePreference = 'Continue'
} Else {
	$VerbosePreference = 'SilentlyContinue'
}

Import-Module SCCM\SCCM-Functions -Force

Write-Verbose "Connect to SCCM-server $($hostName)"
$sccm = Connect-SCCMServer -HostName $hostName

Write-Host "Get root collection: ""$($rootCollectionName)"""
$rootCollection = Get-SCCMCollection -filter "Name='$($rootCollectionName)'" -sccmserver $sccm
if (!$rootCollection) {
	throw "Cant find ""$($rootCollectionName)"""
}
Write-Host "Found collection: $($rootCollection.CollectionID)"

Write-Host "Lookup Manufacturer and Model"
$ManufacturerModel = Get-wmiobject -query "SELECT DISTINCT Manufacturer, Model FROM SMS_G_System_COMPUTER_SYSTEM" -computername $Sccm.Machine -namespace $Sccm.Namespace | Sort-Object Manufacturer, Model
$ManufacturerModel | ForEach-Object {
	$mmCollectionName = "$($_.Manufacturer) - $($_.Model)"
	Write-Host "Checking ""$($mmCollectionName)""" -ForegroundColor Cyan
	
	$mmCollection = Get-SCCMCollection -filter "Name='$($mmCollectionName)'" -sccmserver $sccm
	
	if (!$mmCollection) {
		if (!$WhatIf.IsPresent) {
			Write-Host "Creating collection: ""$($mmCollectionName)"""
			$newMmCollection = New-SCCMCollection -name "$($mmCollectionName)" -SccmServer $sccm -parentCollectionID $rootCollection.CollectionID -refreshDays 1
		} else {
			Write-Host "What if: Creating collection: ""$($mmCollectionName)""" -ForegroundColor Red
		}

		$wql = "SELECT * FROM SMS_R_System inner join SMS_G_System_COMPUTER_SYSTEM on SMS_G_System_COMPUTER_SYSTEM.ResourceId = SMS_R_System.ResourceId where SMS_G_System_COMPUTER_SYSTEM.Manufacturer = '$($_.Manufacturer)'  AND SMS_G_System_COMPUTER_SYSTEM.Model = '$($_.Model)'"
		if (!$WhatIf.IsPresent) {
			Write-Verbose "Adding rule with WQL: $wql"
			Add-SCCMCollectionRule -queryExpression $wql -Server $sccm -collectionID $newMmCollection.CollectionId -queryRuleName $mmCollectionName
		} else {
			Write-Host "What if: Adding collection rule to new collection with wql: $($wql)" -ForegroundColor Red
		}
	} else {
		Write-Host "Found collection"
	}	
}