DSCResources/cCMCollectionRule/cCMCollectionRule.psm1
###################################################################################### # The Get-TargetResource cmdlet. # This function will get the collection if it exists and return all information ###################################################################################### function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $RuleName, [parameter(Mandatory = $true)] [System.String] $ParentCollection, [parameter(Mandatory = $true)] [PSCredential] $SCCMAdministratorCredential, [ValidateSet("1","2")] [System.String] $ParentCollectionType = "2", [ValidateSet("Direct","Exclude","Include","Query")] [System.String] $QueryType = "Query" ) #Login ($oldToken, $context, $newToken) = ImpersonateAs -cred $SCCMAdministratorCredential #Load Module if missing then set the location for execution if(!(Get-Module ConfigurationManager)) { Try { Import-Module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1') } Catch { Throw "Cannot load the SCCM Module, please ensure the SCCM Admin tools are installed and try again" } } $ComputerInfo = Get-WmiObject Win32_ComputerSystem $ComputerFQDN = $ComputerInfo.Name + '.' + $ComputerInfo.Domain $CM12ProviderLocation = Get-WmiObject -Query "Select * From SMS_ProviderLocation where ProviderForLocalSite = True" -Namespace "root\sms" -computername $ComputerFQDN $Site = $CM12ProviderLocation.SiteCode if(!((Get-PSDrive) -like $Site)) { throw "Problems discovering a valid Site. Please Investigate." } $OriginalLocation = Get-Location Set-Location ${Site}: #Grab the ParentCollection if it exists switch ($ParentCollectionType) { 1 {$CMCollection = Get-CMUserCollection -Name $ParentCollection} 2 {$CMCollection = Get-CMDeviceCollection -Name $ParentCollection} } #Search the Collection for any rule matching the RuleName If($ParentCollectionType -eq "1" -and $CMCollection) { switch ($QueryType) { Direct {$QueryExpressionReturn = (Get-CMUserCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceName $RuleName).RuleName} Exclude{$QueryExpressionReturn = (Get-CMUserCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName).ExcludeCollectionID} Include{$QueryExpressionReturn = (Get-CMUserCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName).IncludeCollectionID} Query {$QueryExpressionReturn = (Get-CMUserCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName).QueryExpression} } } Elseif($ParentCollectionType -eq "2" -and $CMCollection) { switch ($QueryType) { Direct {$QueryExpressionReturn = (Get-CMDeviceCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceName $RuleName).RuleName} Exclude{$QueryExpressionReturn = (Get-CMDeviceCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName).ExcludeCollectionID} Include{$QueryExpressionReturn = (Get-CMDeviceCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName).IncludeCollectionID} Query {$QueryExpressionReturn = (Get-CMDeviceCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName).QueryExpression} } } $returnValue = @{ RuleName = $RuleName ParentCollection = if($CMCollection){$ParentCollection}else{''} ParentCollectionType = if($ParentCollectionType -eq "1"){'User'}else{'Device'} QueryExpression = $QueryExpressionReturn QueryType = $QueryType Ensure = if($QueryExpressionReturn){'Present'}else{'Absent'} } #Logout Set-Location $OriginalLocation if ($context) { $context.Undo() $context.Dispose() CloseUserToken($newToken) } $returnValue } ###################################################################################### # The Set-TargetResource cmdlet. # This function will pass the "apply" switch back to the validate function ###################################################################################### function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $RuleName, [parameter(Mandatory = $true)] [System.String] $ParentCollection, [parameter(Mandatory = $true)] [PSCredential] $SCCMAdministratorCredential, [ValidateSet("1","2")] [System.String] $ParentCollectionType, [ValidateSet("Direct","Exclude","Include","Query")] [System.String] $QueryType, [System.String] $QueryExpression, [ValidateSet("Present","Absent")] [System.String] $Ensure ) ValidateProperties @PSBoundParameters -Apply } ###################################################################################### # The Test-TargetResource cmdlet. # This function will only return a $true $false on compliance ###################################################################################### function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $RuleName, [parameter(Mandatory = $true)] [System.String] $ParentCollection, [parameter(Mandatory = $true)] [PSCredential] $SCCMAdministratorCredential, [ValidateSet("1","2")] [System.String] $ParentCollectionType, [ValidateSet("Direct","Exclude","Include","Query")] [System.String] $QueryType, [System.String] $QueryExpression, [ValidateSet("Present","Absent")] [System.String] $Ensure ) ValidateProperties @PSBoundParameters } ###################################################################################### # The ValidateProperties cmdlet. # This function accepts an -apply flag and "does the work" ###################################################################################### function ValidateProperties { param ( [parameter(Mandatory = $true)] [System.String] $RuleName, [parameter(Mandatory = $true)] [System.String] $ParentCollection, [parameter(Mandatory = $true)] [PSCredential] $SCCMAdministratorCredential, [ValidateSet("1","2")] [System.String] $ParentCollectionType = "2", [ValidateSet("Direct","Exclude","Include","Query")] [System.String] $QueryType = "Query", [System.String] $QueryExpression, [ValidateSet("Present","Absent")] [System.String] $Ensure = "Present", [switch] $Apply ) #Preset The Return varibale for a test [boolean]$TestedOK = $true #Login ($oldToken, $context, $newToken) = ImpersonateAs -cred $SCCMAdministratorCredential #Load Module if missing then set the location for execution if(!(Get-Module ConfigurationManager)) { Try { Import-Module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1') } Catch { Throw "Cannot load the SCCM Module, please ensure the SCCM Admin tools are installed and try again" } } $ComputerInfo = Get-WmiObject Win32_ComputerSystem $ComputerFQDN = $ComputerInfo.Name + '.' + $ComputerInfo.Domain $CM12ProviderLocation = Get-WmiObject -Query "Select * From SMS_ProviderLocation where ProviderForLocalSite = True" -Namespace "root\sms" -computername $ComputerFQDN $Site = $CM12ProviderLocation.SiteCode if(!((Get-PSDrive) -like $Site)) { throw "Problems discovering a valid Site. Please Investigate." } $OriginalLocation = Get-Location Set-Location ${Site}: #Grab the ParentCollection if it exists switch ($ParentCollectionType) { 1 {$CMCollection = Get-CMUserCollection -Name $ParentCollection} 2 {$CMCollection = Get-CMDeviceCollection -Name $ParentCollection} } if(!($CMCollection)) { Throw "The mandatory parent collection $ParentCollection cannot be found. Please Correct Entry." } #Search the Collection for any rule matching the RuleName If($ParentCollectionType -eq "1") { switch ($QueryType) { Direct {$CMQuery = Get-CMUserCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceName $RuleName} Exclude{$CMQuery = Get-CMUserCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName} Include{$CMQuery = Get-CMUserCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName} Query {$CMQuery = Get-CMUserCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName} } } Elseif($ParentCollectionType -eq "2") { switch ($QueryType) { Direct {$CMQuery = Get-CMDeviceCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceName $RuleName} Exclude{$CMQuery = Get-CMDeviceCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName} Include{$CMQuery = Get-CMDeviceCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName} Query {$CMQuery = Get-CMDeviceCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName} } } #If $Ensure is set to 'Absent', take action to report or delete the query then quit if($Ensure -eq 'Absent') { if ($CMQuery -and !($Apply)){ [boolean]$TestedOK = $false } elseif($CMQuery -and $Apply -and ($ParentCollectionType -eq "1")){ switch ($QueryType) { Direct {Remove-CMUserCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceName $RuleName -force} Exclude{Remove-CMUserCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName -force} Include{Remove-CMUserCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName -force} Query {Remove-CMUserCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName -force} } } elseif($CMQuery -and $Apply -and ($ParentCollectionType -eq "2")){ switch ($QueryType) { Direct {Remove-CMDeviceCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceName $RuleName -force} Exclude{Remove-CMDeviceCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName -force} Include{Remove-CMDeviceCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName -force} Query {Remove-CMDeviceCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName -force} } } } else{ #Translate $QueryType Specfic Variables needed to create Collections if($QueryType -eq "Direct") { switch ($ParentCollectionType) { 1 {$QueryResourceID = (Get-CMUser -Name $RuleName).ResourceID} 2 {$QueryResourceID = (Get-CMDevice -Name $RuleName).ResourceID} } } #Create the new rule if it is missing if(!($CMQuery)) { if (!($Apply)) { [boolean]$TestedOK = $false } elseif($Apply -and ($ParentCollectionType -eq "1")) { switch ($QueryType) { Direct {Add-CMUserCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceID $QueryResourceID} Exclude{Add-CMUserCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName} Include{Add-CMUserCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName} Query {Add-CMUserCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName -QueryExpression $QueryExpression} } } elseif($Apply -and ($ParentCollectionType -eq "2")) { switch ($QueryType) { Direct {Add-CMDeviceCollectionDirectMembershipRule -CollectionName $CMCollection.Name -ResourceID $QueryResourceID} Exclude{Add-CMDeviceCollectionExcludeMembershipRule -CollectionName $CMCollection.Name -ExcludeCollectionName $RuleName} Include{Add-CMDeviceCollectionIncludeMembershipRule -CollectionName $CMCollection.Name -IncludeCollectionName $RuleName} Query {Add-CMDeviceCollectionQueryMembershipRule -CollectionName $CMCollection.Name -RuleName $RuleName -QueryExpression $QueryExpression} } } } } #Logout Set-Location $OriginalLocation if ($context) { $context.Undo() $context.Dispose() CloseUserToken($newToken) } #Return The Test results if $apply is not set if(!($Apply)) { return $TestedOK } } ###################################################################################### # The below functions are used for user impersonation # There are 3 functions in total ###################################################################################### function Get-ImpersonatetLib { if ($script:ImpersonateLib) { return $script:ImpersonateLib } $sig = @' [DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("kernel32.dll")] public static extern Boolean CloseHandle(IntPtr hObject); '@ $script:ImpersonateLib = Add-Type -PassThru -Namespace 'Lib.Impersonation' -Name ImpersonationLib -MemberDefinition $sig return $script:ImpersonateLib } function ImpersonateAs([PSCredential] $cred) { [IntPtr] $userToken = [Security.Principal.WindowsIdentity]::GetCurrent().Token $userToken $ImpersonateLib = Get-ImpersonatetLib $bLogin = $ImpersonateLib::LogonUser($cred.GetNetworkCredential().UserName, $cred.GetNetworkCredential().Domain, $cred.GetNetworkCredential().Password, 9, 0, [ref]$userToken) if ($bLogin) { $Identity = New-Object Security.Principal.WindowsIdentity $userToken $context = $Identity.Impersonate() } else { throw "Can't Logon as User $cred.GetNetworkCredential().UserName." } $context, $userToken } function CloseUserToken([IntPtr] $token) { $ImpersonateLib = Get-ImpersonatetLib $bLogin = $ImpersonateLib::CloseHandle($token) if (!$bLogin) { throw "Can't close token" } } Export-ModuleMember -Function *-TargetResource |