DscResources/MimSyncFilterRule/MimSyncFilterRule.psm1
data DscParameterToXmlNodeMap { ConvertFrom-StringData @' CDObjectType = //stay-disconnector/filter-set[@cd-object-type='{0}'] ImportFilter = 'import-filter' Type = 'type' FilterAlternative = 'filter-alternative' '@ } function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $ManagementAgentName, [parameter(Mandatory = $true)] [System.String] $CDObjectType ) ### Check the schema cache and update if necessary Write-MimSyncConfigCache -Verbose $svrexportPath = Get-MimSyncConfigCache Write-Verbose "Getting sync configuration files from '$svrexportPath'" ### Get the MIM object XML from the server configuration files Write-Verbose "Finding filter rule with a CD object type of '$CDObjectType' on management agent '$ManagementAgentName'..." $fimSyncObject = Select-Xml -Path (Join-Path $svrexportPath *.xml) -XPath "//ma-data[name='$ManagementAgentName']/stay-disconnector/filter-set[@cd-object-type='$CDObjectType']" $FilterAlternative = @($fimSyncObject.Node.SelectNodes('filter-alternative') | ConvertMimSyncFilterAlternative-ToCimInstance) Write-Output @{ ManagementAgentName = $ManagementAgentName CDObjectType = $CDObjectType FilterAlternative = $FilterAlternative ImportFilter = $fimSyncObject.Node.'import-filter' -as [Boolean] Type = $fimSyncObject.Node.type } } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $ManagementAgentName, [parameter(Mandatory = $true)] [System.String] $CDObjectType, [Boolean] $ImportFilter, [String] $Type, [Microsoft.Management.Infrastructure.CimInstance[]] $FilterAlternative, [ValidateSet("Present","Absent")] [System.String] $Ensure ) Write-Warning "DSC resources for the Synchronization Service are not able to update the Synchronization configuration." } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $ManagementAgentName, [parameter(Mandatory = $true)] [System.String] $CDObjectType, [Boolean] $ImportFilter, [String] $Type, [Microsoft.Management.Infrastructure.CimInstance[]] $FilterAlternative, [ValidateSet("Present","Absent")] [System.String] $Ensure ) ### Check the schema cache and update if necessary Write-MimSyncConfigCache -Verbose ### Get the MIM object XML from the server configuration files Write-Verbose "Finding filter rule with a CD object type of '$CDObjectType' on management agent '$ManagementAgentName'..." $xPathFilter = "//ma-data[name='$ManagementAgentName']/stay-disconnector/filter-set[@cd-object-type='$CDObjectType']" Write-Verbose " Using XPath: $xPathFilter" $fimSyncObject = Select-Xml -Path (Join-Path (Get-MimSyncConfigCache) *.xml) -XPath $xPathFilter $objectsAreTheSame = $true if ($Ensure -eq 'Present') { if ($fimSyncObject -eq $null) { Write-Verbose "Filter Rule not found: $Name." $objectsAreTheSame = $false } else { Write-Verbose "Filter Rule found, diffing the properties: $($fimSyncObject.Path)" foreach ($dscResourceProperty in Get-DscResource -Name MimSyncFilterRule | Select-Object -ExpandProperty Properties) { if ($dscResourceProperty.Name -in 'Ensure','DependsOn','PsDscRunAsCredential','ManagementAgentName','CDObjectType') { Write-Verbose " Skipping system-owned attribute: $($dscResourceProperty.Name)" continue } if ($dscResourceProperty.Name -eq 'FilterAlternative') { if ($Type -eq 'scripted') { Write-Verbose " Skipping property $($dscResourceProperty.Name) because this is a scripted filter rule (they have no conditions)" continue } Write-Verbose " Comparing property $($dscResourceProperty.Name) using XPath: $($DscParameterToXmlNodeMap.($dscResourceProperty.Name))" $valuesFromDSC = @($FilterAlternative) $valuesFromMIM = @($fimSyncObject.Node.SelectNodes('filter-alternative') | ConvertMimSyncFilterAlternative-ToCimInstance) Write-Verbose " From DSC: $($valuesFromDSC.count)" Write-Verbose " From MIM: $($valuesFromMIM.count)" if ($valuesFromDSC.count -ne $valuesFromMIM.count) { Write-Warning " The number of filters is different, therefore the filter rule is not the same." $objectsAreTheSame = $false } else { ### Compare each FilterAlternative for ($i = 0; $i -lt $valuesFromDSC.count; $i++) { Write-Verbose " Comparing Filter $i" $filterConditionCompareResults = Compare-Object -ReferenceObject $valuesFromDSC[$i].FilterCondition -DifferenceObject $valuesFromMIM[$i].FilterCondition -Property CDAttribute,Operator,Value if ($filterConditionCompareResults) { Write-Warning " 'Filter $i is not the same." $objectsAreTheSame = $false Write-Verbose " From DSC: $(($filterConditionCompareResults | Where SideIndicator -eq '<=' | ft -AutoSize | out-string))" Write-Verbose " From FIM: $(($filterConditionCompareResults | Where SideIndicator -eq '=>' | ft -AutoSize | out-string))" } } } } else { Write-Verbose " Comparing property '$($dscResourceProperty.Name)' using XPath: $($DscParameterToXmlNodeMap.($dscResourceProperty.Name))" if ($dscResourceProperty.Name -eq 'ImportFilter') { $fimValue = $fimSyncObject.Node.'import-filter' } elseif ($dscResourceProperty.Name -eq 'Type') { $fimValue = $fimSyncObject.Node.type } else { $fimValue = $fimSyncObject.Node.SelectSingleNode($DscParameterToXmlNodeMap.($dscResourceProperty.Name)).InnerText } if ($dscResourceProperty.PropertyType -eq '[bool]') { $fimValue = [Convert]::ToBoolean([int]$fimValue) #HACK - not loving this } Write-Verbose " From DSC: $($PSBoundParameters[$dscResourceProperty.Name])" Write-Verbose " From MIM: $fimValue" if ((-not $PSBoundParameters.ContainsKey($dscResourceProperty.Name)) -and [String]::IsNullOrEmpty($fimValue)) { #Empty on both sides, do nothing } elseif ($PSBoundParameters[$dscResourceProperty.Name] -ne $fimValue) { Write-Warning " '$($dscResourceProperty.Name)' property is not the same." $objectsAreTheSame = $false } } } $objectsAreTheSame = $objectsAreTheSame } } elseif($Ensure -eq 'Absent') { if ($fimSyncObject -ne $null) { Write-Warning "Join Rule found ($Name) but is supposed to be Absent. DESTROY!!!" $objectsAreTheSame = $false } else { $objectsAreTheSame = $true } } else { Write-Error "Expected the 'Ensure' parameter to be 'Present' or 'Absent'" } Write-Verbose "Returning: $objectsAreTheSame" return $objectsAreTheSame } function ConvertMimSyncFilterAlternative-ToCimInstance { <# .Synopsis Converts the MIM Sync XML to a CIM Instance .DESCRIPTION MIM Sync uses XML to represent the configuration objects DSC uses CIM instances to work with custom MOF classes It is necessary for the DSC resource to create CIM instances from the MIM Sync XML .EXAMPLE Get-MimSyncServerXml -Path (Get-MimSyncConfigCache) -Force $fimSyncObject = Select-Xml -Path (Join-Path (Get-MimSyncConfigCache) *.xml) -XPath "//ma-data[name='CORP AD']/stay-disconnector/filter-set[@cd-object-type='computer']" $fimSyncObject.Node.'join-criterion'[3] | ConvertMimSyncJoinCriterion-ToCimInstance .EXAMPLE [xml]@' <filter-set import-filter="1" cd-object-type="computer" type="declared"> <filter-alternative id="{D3FAE5BC-E685-413C-9D4A-3D5C108EC135}"> <condition cd-attribute="sAMAccountName" operator="substring-start"> <value>$Duplicate</value> </condition> </filter-alternative> <filter-alternative id="{CD0801C0-6145-4DD1-BCE3-E2FEA8E3D554}"> <condition cd-attribute="cn" operator="equality"> <value>foo</value> </condition> <condition cd-attribute="employeeID" operator="inequality"> <value>oo7</value> </condition> <condition cd-attribute="extensionAttribute11" operator="present"> <value></value> </condition> </filter-alternative> </filter-set> '@ | Select-Object -ExpandProperty 'filter-set' | ConvertMimSyncFilterAlternative-ToCimInstance .INPUTS XML of the RunSteps from the RunProfile .OUTPUTS a CIM Instance for the RunStep .COMPONENT The component this cmdlet belongs to #> [CmdletBinding()] [OutputType([Microsoft.Management.Infrastructure.CimInstance])] Param ( # Join Criterion to Convert [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)] $FilterAlternative ) Process { $FilterConditions = @() foreach($filterCondition in $FilterAlternative.condition) { $FilterConditions += New-CimInstance -ClassName MimSyncFilterCondition -ClientOnly -Namespace root/microsoft/windows/desiredstateconfiguration -Property @{ CDAttribute = $filterCondition.'cd-attribute' -as [String] Operator = $filterCondition.operator -as [String] Value = $filterCondition.value -as [String] } } $cimInstance = New-CimInstance -ClassName MimSyncFilterAlternative -ClientOnly -Namespace root/microsoft/windows/desiredstateconfiguration -Property @{ ID = $FilterAlternative.id -as [String] FilterCondition = $FilterConditions -as [CimInstance[]] } Write-Output -InputObject $cimInstance } } Export-ModuleMember -Function *-TargetResource |