private/createOrSetGPO.ps1

function CreateOrSetGPO {
    [CmdletBinding(SupportsShouldProcess=$true,DefaultParameterSetName='Default')]
    Param
    (
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [ValidateScript({[bool](get-rbacOrg -org $_ -includeGlobal)})]
        [ArgumentCompleter( {(get-rbacOrg -includeGlobal).Org})]
        [String]$Org,
        
        [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'SpecificComponent')]
        [ValidateScript({ $(get-rbacComponent).component.contains($_) })]
        [ArgumentCompleter( {(get-rbacComponent).Component})]
        [String]$Component,

        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Hashtable]$GPOTemplate
    )
    Begin{
        $Domain = get-ADDomain
        $DomainDNSRoot= $Domain.DNSRoot
        $DomainGPOPath="\\$DomainDNSRoot\sysvol\$DomainDNSRoot\Policies"
        $shouldProcess = @{
            Confirm = [bool]($ConfirmPreference -eq "low")
            Whatif = [bool]($WhatIfPreference.IsPresent)
            verbose = [bool]($verbosePreference -eq "continue")
        }
        $GPOHeader_SecEdit_INF=@'
[Unicode]
Unicode=yes
[Version]
signature="$CHICAGO$"
Revision=1
'@

        $GPOHeader_GPT_INI_HEADER=@'
[General]
Version=1
displayName=New Group Policy Object
'@

    }
    PROCESS {
        if ($component) {
            $element = get-rbacComponent -org $org -component $Component -detailed
        } else {
            $element = get-rbacOrg -org $org -includeGlobal -detailed
        }
        if (-not $element) {
            throw "Invalid RBAC Element (maybe wrong org for component?)"
        }
        if ($org -eq $OrganizationConfig.GlobalOUName) {
            $element.distinguishedName = "OU=$($OrgsOUStruct.Name),$($OrgsOUStruct.Path)"
        }
        $GPOName = "{0}-{1}" -f $GPOTemplate.Metadata.NamePrefix, $Element.objectMidName
        write-Verbose "Working on GPO: $GPOName"
        
        $GPOObject = if ($PSCmdlet.ShouldProcess($GPOName, "Create / get GPO")) {    
            try {
                new-gpo -name $GPOName -erroraction stop @shouldProcess
                $preExisting = $false
                Write-Host "Created GPO: $GPOName"
            } catch {
                write-warning "GPO already existed: $GPOName"
                $preExisting = $true
                get-gpo $GPOName
            }
        } else {
            get-gpo $GPOName
        }
        $GPOBaseFilePath = "{0}\{{{1}}}" -f $DomainGPOPath, $GPOObject.ID.GUID

        #region set GPLink
        if ($PSCmdlet.ShouldProcess($GPOName, "Create or Set GPLink")) {
            try {
                new-gplink -name $GPOName -target $Element.DistinguishedName -erroraction stop @shouldProcess| out-null
                
            } catch {
                write-Verbose "$($GPONname) GPLink already exists."
            }
            $GPLinkParams = @{
                target = $Element.distinguishedname
                Order = $GPOTemplate.Metadata.LinkOrder
                LinkEnabled = "Yes"
                Enforced = "No"
            }
            $GPOObject | set-gplink @GPLinkParams  | out-null
            Write-host ("Set GPLink: {0,-32} : #{1,-1} ; Enforced: {2,-5} ; Enabled: {3,-5} ; Path: {4}" -f $GPOObject.displayName, $GPLinkParams.Order, $GPLinkParams.Enforced, $GPLinkParams.LinkEnabled, $GPLinkParams.target)
        }
        #endregion

        #region Set permissions on GPO
        $GPPermissions = @{}
        foreach ($GPPermissionLevel in $GPOTemplate.metadata.gppermissions.getEnumerator()) {
            $entityList = resolveEntityReferences -rightsPrefix "Right-$($element.objectMidName)" -rightsAndPrincipals $GPPermissionLevel.value
            $GPPermissions.$($GPPermissionLevel.key) = $EntityList
        }
        write-host "Setting permissions for GPO..."
        foreach ($PermissionLevel in $GPPermissions.GetEnumerator()) {
            foreach ($entity in $PermissionLevel.value) {
                if ($PSCmdlet.ShouldProcess($GPOName, ("Set permissions: {0,-10}; on entityType: {1,-10}; entity: {2}" -f  $permissionLevel.key, $entity.objectClass, $entity.name))) {
                    try {
                        $Params = @{
                            name = $GPOName
                            TargetName = $entity.name
                            TargetType = $entity.objectClass
                            Permissionlevel = $permissionLevel.key
                            Replace = $true
                        }
                    set-GPPermission @Params -ErrorAction stop | out-null
                    } Catch {
                        $_ | format-list * -force
                        Write-warning "Error setting permissions for $GroupName on $GPOName"
                        throw $_
                    }
                }
            }
        }
        #endregion

        if (-not $preExisting -or $GPOTemplate.Metadata.AlwaysRebuild) {
            $GPCExtensionList = "[{827D319E-6EAC-11D2-A4EA-00C04F79F83A}{803E14A0-B4FB-11D0-A0D0-00A0C90F574B}]"
            #region SecEdit.inf
            $SecEditPath ="{0}\Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf" -f $GPOBaseFilePath
            $SecEditContents = try {
                $GPOHeader_SecEdit_INF
                if ($GPOTemplate.SecEdit) {
                    foreach ($Section in $GPOTemplate.secedit.getEnumerator()){
                        $SectionString = "[{0}]" -f $section.key
                        $sectionString
                        try {
                            foreach ($setting in $Section.value.getEnumerator()) {
                                write-verbose "Setting Secedit \ $($section.key)"
                                $entityList = resolveEntityReferences -rightsPrefix "Right-$($element.objectMidName)" -rightsAndPrincipals $setting.value
                                $NamesList = ($entityList | where-object {$null -ne $_.name -and $null -eq $_.GPOSIDRef} ).name -join ","
                                $SIDList = ($entityList | where-object {$null -ne $_.GPOSIDRef} ).GPOSIDRef -join ","
                                $EntityString = (@($NamesList, $SIDList) | where-object {$_ -ne $null -and $_ -ne ""}) -join ","
                                "{0} = {1}" -f $setting.key, $entityString
                            }
                        }  catch [System.Management.Automation.RuntimeException] {
                            write-warning "Missing settings or bad format in GPO template (Section: secedit \ $($section.key))..."
                            $_ | format-list * -force
                        }
                    }
                }
            } catch [System.Management.Automation.RuntimeException] {
                write-warning "Missing settings or bad format in GPO template under SECEDIT..."
                $_ | format-list * -force
            }
            if ($PSCmdlet.ShouldProcess($SecEditPath, ("Writing out SecEdit.inf"))) {
                new-item $SecEditPath -force | out-null
                $SecEditContents | out-file -append $SecEditPath -Encoding unicode
            } else {
                $secEditContents
            }
            #endRegion

            #region RegPol
            if ($GPOTemplate.RegPol) {
                $GPCExtensionList = "[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F72-3407-48AE-BA88-E8213C6761F1}]" + $GPCExtensionList
                $RegPolPath ="{0}\Machine\Registry.pol" -f $GPOBaseFilePath
                $PolicyDefs = foreach ($policyItem in $GPOTemplate.RegPol) {
                    $Value = if ($PolicyItem.ValueCollection) {
                        $entityList = resolveEntityReferences -rightsPrefix "Right-$($element.objectMidName)" -rightsAndPrincipals $PolicyItem.ValueCollection
                        # Special Handling
                        switch ($policyItem.ValueName) {
                            "ADPasswordEncryptionPrincipal" { $EntityList[0].NetBIOS }
                            default { ($($entityList.name + $entityList.SID.Value) | where-object {$_ -ne $null}) -join "," }
                        }
                    } else {
                        $policyItem.valueData
                    }
                    $Policy = @{
                        keyName = $policyItem.keyName
                        valueName = $policyItem.valueName
                        ValueType = $Policyitem.valueType
                        ValueData = $value
                    }
                    write-host ("Setting policy {2,-10}- {0}\{1} = {3}" -f $policy.keyName, $Policy.valueName, $policy.valueType, $policy.ValueData)
                    New-GPRegistryPolicy @policy

                }
                Create-GPRegistryPolicyFile -path $RegPolPath
                append-RegistryPolicies -registryPolicies $PolicyDefs -path $RegPolPath
            }
            # endregion
            # region GPPrefRegistryValues
            if ($GPOTemplate.GPPrefRegistryValues) {
                $GPCExtensionList = $GPCExtensionList + "[{B087BE9D-ED37-454F-AF9C-04291E351182}{BEE07A6A-EC9F-4659-B8C9-0B1937907C83}]"
                foreach ($RegistryPref in $GPOTemplate.GPPrefRegistryValues) {
                    set-GPPrefRegistryValue -GUID $GPOObject.ID @RegistryPref -verbose
                }
            }
            # endregion

            if ($PSCmdlet.ShouldProcess($GPOObject.Path,"Set GPCMachineExtensions on GPO and increment version")) {
                try {
                    $oldVersion = (get-adobject -identity $GPOObject.Path -properties versionNumber).versionNumber
                    $newVersion = [int]$oldVersion + 1
                } catch {
                    $newVersion = 1
                }
                set-adobject -identity $GPOObject.Path -replace @{gPCMachineExtensionNames = $GPCExtensionList; versionNumber = $newVersion} | out-null
                $GPT_Ini_Contents=@"
[General]
Version=$NewVersion
displayName=$GPOName
"@

                # Apparently encoding unicode is bad news for gpt.ini
                $GPT_Ini_Contents | out-file $GPOBaseFilePath\gpt.ini -Force
            }

        }
    }
    End {

    }
}