internal/functions/Merge-AssignmentParametersEx.ps1

function Merge-AssignmentParametersEx {
    # Recursive Function
    param(
        $NodeName,
        $PolicySetId,
        [hashtable] $BaseAssignment,
        [hashtable] $ParameterInstructions,
        [hashtable] $FlatPolicyList,
        [hashtable] $CombinedPolicyDetails,
        [hashtable] $EffectProcessedForPolicy
    )

    $csvParameterArray = $ParameterInstructions.csvParameterArray
    $effectColumn = $ParameterInstructions.effectColumn
    $parametersColumn = $ParameterInstructions.parametersColumn
    $nonComplianceMessageColumn = $ParameterInstructions.nonComplianceMessageColumn

    #region parameters column

    $parameters = Get-DeepClone $BaseAssignment.parameters -AsHashTable
    foreach ($row in $csvParameterArray) {
        if ($row.flatPolicyEntryKey) {
            $parametersColumnCell = $row[$parametersColumn]
            if ($null -ne $parametersColumnCell -and $parametersColumnCell -ne "") {
                $addedParameters = ConvertFrom-Json $parametersColumnCell -Depth 100 -AsHashTable
                if ($null -ne $addedParameters -and $addedParameters.psbase.Count -gt 0) {
                    foreach ($parameterName in $addedParameters.Keys) {
                        $rawParameterValue = $addedParameters.$parameterName
                        $parameterValue = Get-DeepClone $rawParameterValue -AsHashTable
                        $parameters[$parameterName] = $parameterValue
                    }
                }
            }
        }
    }

    #endregion parameters column

    #region parameters column = mutual exclusion handled

    $overridesByEffect = @{}
    $nonComplianceMessages = $BaseAssignment.nonComplianceMessages
    $hasErrors = $false
    foreach ($row in $csvParameterArray) {
        $flatPolicyEntryKey = $row.flatPolicyEntryKey
        if ($flatPolicyEntryKey) {
            $name = $row.name
            $flatPolicyEntry = $FlatPolicyList.$flatPolicyEntryKey
            if ($null -eq $name -or $name -eq "" -or $null -eq $flatPolicyEntry -or $null -eq $flatPolicyEntry.policySetList -or $null -eq $row.policyId) {
                continue
            }
            $policySetList = $flatPolicyEntry.policySetList
            if ($policySetList.ContainsKey($PolicySetId)) {
                # Policy in this for loop iteration is referenced in the Policy Set currently being processed

                #region effect parameters including overrides
                $perPolicySet = $policySetList.$PolicySetId
                $effectParameterName = $perPolicySet.effectParameterName
                $effect = $row[$effectColumn]
                $setEffectAllowedValues = $perPolicySet.effectAllowedValues
                $effectAllowedOverrides = $flatPolicyEntry.effectAllowedOverrides
                $effectDefault = $perPolicySet.effectDefault
                $desiredEffect = $effect.ToLower()
                $useOverrides = $false
                $policyDefinitionReferenceId = $perPolicySet.policyDefinitionReferenceId
                $isProcessed = $EffectProcessedForPolicy.ContainsKey($flatPolicyEntryKey)
                $modifiedEffect = $desiredEffect
                if ($isProcessed) {
                    # the second and subsequent time this Policy is processed, the effect must be adjusted to audit
                    if ($desiredEffect -eq $EffectProcessedForPolicy.$flatPolicyEntryKey) {
                        # Adjust desiredEffect
                        $modifiedEffect = switch ($desiredEffect) {
                            append {
                                "Audit"
                            }
                            modify {
                                "Audit"
                            }
                            deny {
                                "Audit"
                            }
                            deployIfNotExists {
                                "AuditIfNotExists"
                            }
                            manual {
                                "Manual"
                            }
                            Default {
                                $_
                            }
                        }
                    }
                }
                else {
                    # first encounter of this Policy, use desired value (previously set) and enter in list of processed Policies
                    $null = $EffectProcessedForPolicy.Add($flatPolicyEntryKey, $desiredEffect)
                }

                $isAllowed = $false
                if ($perPolicySet.isEffectParameterized) {
                    if ($desiredEffect -ne $modifiedEffect) {
                        # check if the modified effect is an allowed parameter value or an allowed override value
                        if ($setEffectAllowedValues -contains $modifiedEffect) {
                            # the modified effect is an allowed parameter value
                            $isAllowed = $true
                            $desiredEffect = $modifiedEffect
                        }
                        elseif ($effectAllowedOverrides -contains $modifiedEffect) {
                            # the modified effect is an allowed override value
                            $desiredEffect = $modifiedEffect
                            $isAllowed = $true
                            $useOverrides = $true
                        }
                    }
                    if (!$isAllowed) {
                        # check if the original desired effect is an allowed parameter value or an allowed override value
                        if ($setEffectAllowedValues -contains $desiredEffect) {
                            # the original desired effect is an allowed parameter value
                            $isAllowed = $true
                        }
                        elseif ($effectAllowedOverrides -contains $desiredEffect) {
                            # the original desired effect is an allowed override value
                            $isAllowed = $true
                            $useOverrides = $true
                        }
                    }
                }
                else {
                    # the effect is not parameterized
                    if ($desiredEffect -ne $modifiedEffect) {
                        # check if the modified effect is an allowed override value
                        if ($effectAllowedOverrides -contains $modifiedEffect) {
                            # the modified effect is an allowed override value
                            $desiredEffect = $modifiedEffect
                            $isAllowed = $true
                            $useOverrides = $true
                        }
                    }
                    if (!$isAllowed) {
                        # check if the original desired effect is an allowed override value
                        if ($effectAllowedOverrides -contains $desiredEffect) {
                            # the original desired effect is an allowed override value
                            $isAllowed = $true
                            $useOverrides = $true
                        }
                    }
                }

                if (!$isAllowed) {
                    # the effect is not an allowed value
                    Write-Error " Node $($NodeName): CSV parameterFile '$parameterFileName' row for Policy name '$name': the effect ($effect) must be an allowed value."
                    $hasErrors = $true
                    continue
                }
                else {
                    if ($desiredEffect -ne $effectDefault) {
                        # the effect is not the default value
                        if ($useOverrides) {
                            # find the correct case for the allowed override value
                            foreach ($effectAllowedOverride in $effectAllowedOverrides) {
                                if ($effectAllowedOverride -eq $desiredEffect) {
                                    $desiredEffect = $effectAllowedOverride # fixes potentially wrong case, or keeps the original case
                                    break
                                }
                            }
                            # collate the overrides by effect
                            $byEffectList = $null
                            if ($overridesByEffect.ContainsKey($desiredEffect)) {
                                $byEffectList = $overridesByEffect[$desiredEffect]
                            }
                            else {
                                $byEffectList = [System.Collections.ArrayList]::new()
                                $overridesByEffect[$desiredEffect] = $byEffectList
                            }
                            $null = $byEffectList.Add($policyDefinitionReferenceId)
                        }
                        else {
                            # find the correct case for the allowed parameter value
                            foreach ($setEffectAllowedValue in $setEffectAllowedValues) {
                                if ($setEffectAllowedValue -eq $desiredEffect) {
                                    $desiredEffect = $setEffectAllowedValue # fixes potentially wrong case, or keeps the original case
                                    break
                                }
                            }
                            # set the effect parameter
                            $parameters[$effectParameterName] = $desiredEffect
                        }
                    }
                }
                #endregion effect parameters including overrides

                #region nonComplianceMessages
                if ($null -ne $nonComplianceMessageColumn) {
                    $nonComplianceMessage = $row[$nonComplianceMessageColumn]
                    if ($nonComplianceMessage -ne "") {
                        $null = $nonComplianceMessages.Add(
                            @{
                                message                     = $nonComplianceMessage
                                policyDefinitionReferenceId = $policyDefinitionReferenceId
                            }
                        )
                    }
                }
                #endregion nonComplianceMessages
            }
        }
    }

    #endregion parameters column = mutual exclusion handled

    #region optimize overrides

    $effectsCount = $overridesByEffect.psbase.Count
    if ($effectsCount -gt 0) {
        $finalOverrides = [System.Collections.ArrayList]::new()
        foreach ($effectValue in $overridesByEffect.Keys) {
            [System.Collections.ArrayList] $policyDefinitionReferenceIds = $overridesByEffect[$effectValue]
            $idsCount = $policyDefinitionReferenceIds.Count
            $startIndex = 0
            while ($idsCount -gt 0) {
                $ids = $null
                if ($idsCount -gt 50) {
                    # each override can have up to 50 selectors
                    $ids = ($policyDefinitionReferenceIds.GetRange($startIndex, 50)).ToArray()
                    $startIndex += 50
                    $idsCount -= 50
                }
                else {
                    $ids = ($policyDefinitionReferenceIds.GetRange($startIndex, $idsCount)).ToArray()
                    $idsCount = 0
                }
                $override = @{
                    kind      = "policyEffect"
                    value     = $effectValue
                    selectors = @(
                        @{
                            kind = "policyDefinitionReferenceId"
                            in   = $ids
                        }
                    )
                }
                $null = $finalOverrides.Add($override)
            }
        }
        if ($finalOverrides.Count -gt 10) {
            Write-Error " Node $($NodeName): CSV parameterFile '$parameterFileName' causes too many overrides ($($finalOverrides.Count)) for Policies without parameterized effect." -ErrorAction Continue
            $hasErrors = $true
        }
        else {
            $BaseAssignment.overrides = $finalOverrides.ToArray()
        }
    }
    #endregion optimize overrides

    $BaseAssignment.parameters = $parameters

    return $hasErrors
}