internal/functions/Merge-AssignmentParametersEx.ps1

function Merge-AssignmentParametersEx {
    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-DeepCloneAsOrderedHashtable $BaseAssignment.parameters
    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) {
                    foreach ($parameterName in $addedParameters.Keys) {
                        if (!$parameters.ContainsKey($parameterName)) {
                            $parameterValue = $addedParameters.$parameterName
                            $parameters[$parameterName] = $parameterValue
                        }
                    }
                }
            }
        }
    }
    #endregion parameters column

    #region effects column = mutual exclusion handled
    $overridesByEffect = @{}
    $nonComplianceMessages = $BaseAssignment.nonComplianceMessages
    $hasErrors = $false
    $rowNumber = 1
    foreach ($row in $csvParameterArray) {
        ++$rowNumber
        $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

                $requestedEffect = $row[$effectColumn]
                $planedEffect = $requestedEffect
                $isProcessed = $EffectProcessedForPolicy.ContainsKey($flatPolicyEntryKey)
                $perPolicySet = $policySetList.$PolicySetId
                $effectParameterName = $perPolicySet.effectParameterName
                $effectAllowedValues = $perPolicySet.effectAllowedValues
                $effectAllowedOverrides = $perPolicySet.effectAllowedOverrides
                $effectDefault = $perPolicySet.effectDefault
                $policyDefinitionReferenceId = $perPolicySet.policyDefinitionReferenceId
                if ($isProcessed) {
                    #region the second and subsequent time this Policy is processed, the effect must be adjusted to audit
                    $planedEffect = switch ($requestedEffect) {
                        "Append" {
                            "Audit"
                            break
                        }
                        "Modify" {
                            "Audit"
                            break
                        }
                        "Deny" {
                            "Audit"
                            break
                        }
                        "DeployIfNotExists" {
                            "AuditIfNotExists"
                            break
                        }
                        "DenyAction" {
                            "Disabled"
                            break
                        }
                        default {
                            $_
                        }
                    }
                    #endregion the second and subsequent time this Policy is processed, the effect must be adjusted to audit
                }
                else {
                    $EffectProcessedForPolicy[$flatPolicyEntryKey] = $true
                }

                if ($planedEffect -ne $effectDefault) {

                    #region effect parameters including overrides
                    $useOverrides = $false
                    $confirmedEffect = $null
                    if ($perPolicySet.isEffectParameterized) {
                        # test parameter
                        $useOverrides = $false
                        $confirmedEffect = Confirm-EffectIsAllowed -Effect $planedEffect -AllowedEffects $effectAllowedValues
                        if ($null -eq $confirmedEffect) {
                            # fallback 1: test override
                            $useOverrides = $true
                            $confirmedEffect = Confirm-EffectIsAllowed -Effect $planedEffect -AllowedEffects $effectAllowedOverrides
                            if ($null -eq $confirmedEffect -and $requestedEffect -ne $planedEffect) {
                                # fallback 2: if this is the second processed Policy Set, try parameter with original requested effect
                                $useOverrides = $false
                                $confirmedEffect = Confirm-EffectIsAllowed -Effect $requestedEffect -AllowedEffects $effectAllowedValues
                                if ($null -eq $confirmedEffect) {
                                    # fallback 3: try overrides with the original requested effect
                                    $useOverrides = $true
                                    $confirmedEffect = Confirm-EffectIsAllowed -Effect $requestedEffect -AllowedEffects $effectAllowedOverrides
                                }
                            }
                        }
                    }
                    else {
                        # the effect is not parameterized
                        $useOverrides = $true
                        $confirmedEffect = Confirm-EffectIsAllowed -Effect $planedEffect -AllowedEffects $effectAllowedOverrides
                        if ($null -eq $confirmedEffect) {
                            # fallback: try overrides with the original requested effect
                            $confirmedEffect = Confirm-EffectIsAllowed -Effect $requestedEffect -AllowedEffects $effectAllowedOverrides
                        }
                    }

                    if ($null -eq $confirmedEffect) {
                        # the effect is not an allowed value
                        Write-Error " Node $($NodeName): CSV parameterFile '$parameterFileName' row $rowNumber for Policy name '$name': the effect ($effect) must be an allowed value." -ErrorAction Continue
                        $hasErrors = $true
                        continue
                    }
                    elseif ($confirmedEffect -ne $effectDefault) {
                        if ($useOverrides) {
                            # collate the overrides by effect
                            $byEffectList = $null
                            if ($overridesByEffect.ContainsKey($confirmedEffect)) {
                                $byEffectList = $overridesByEffect[$confirmedEffect]
                            }
                            else {
                                $byEffectList = [System.Collections.ArrayList]::new()
                                $overridesByEffect[$confirmedEffect] = $byEffectList
                            }
                            $null = $byEffectList.Add($policyDefinitionReferenceId)
                        }
                        else {
                            # set the effect parameter
                            $parameters[$effectParameterName] = $confirmedEffect
                        }
                    }
                    #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 effects 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
}