private/new-OUPermission.ps1

function new-oupermission {
    [CmdletBinding(DefaultParameterSetName = 'Normal')]
    Param
    (

        # The principal that the ACE refers to
        [Parameter(mandatory, parametersetname = "Normal", ValueFromPipelineByPropertyName )]
        [Parameter(mandatory, parametersetname = "Extended", ValueFromPipelineByPropertyName )]
        [ValidateScript( { [System.Security.Principal.NTAccount]::new($_).translate([System.security.Principal.SecurityIdentifier]) })]
        $Principal,

        # The principal that the ACE refers to
        [Parameter(mandatory, parametersetname = "IdentityNormal", ValueFromPipelineByPropertyName )]
        [Parameter(mandatory, parametersetname = "IdentityExtended", ValueFromPipelineByPropertyName )]
        [System.Security.Principal.IdentityReference]
        $Identity,

        # ADRight: Generally CreateChild, DeleteChild, GenericAll, or something involving "ExtendedRight".
        [Parameter(ValueFromPipelineByPropertyName )]
        [System.directoryservices.ActiveDirectoryRights] $ADRight,

        # a specific extended right, which must be a proper AD Schema extendedright
        [Parameter(parametersetname = "IdentityExtended", mandatory, ValueFromPipelineByPropertyName )]
        [Parameter(parametersetname = "Extended", Mandatory, ValueFromPipelineByPropertyName )]
        #[ArgumentCompleter( { (Get-ADObjectGUIDs | where-object { $_.type -eq "Right" }).name })]
        #[ValidateScript( { $myArg = $_; (Get-ADObjectGUIDs | where-object { $_.name -eq $myArg -and $_.type -eq "Right" }) })]
        [String]$ExtendedRight,

        # If ADRight is "writeproperty", this can be the target attribute. If it's createchild, it's the child object type. Must be a valid AD Schema object
        [Parameter(parametersetname = "IdentityNormal", ValueFromPipelineByPropertyName )]
        [Parameter(parametersetname = "Normal", ValueFromPipelineByPropertyName )]
        #[ArgumentCompleter( { (Get-ADObjectGUIDs | where-object { $_.type -eq "Object" }).name })]
        #[ValidateScript( { $myArg = $_; (Get-ADObjectGUIDs | where-object { $_.name -eq $myArg -and $_.type -eq "Object" }) })]
        [String[]]$TargetObject,

        # Also known as InheritedObjectType, shown as "Applies to" in the GUI. This is an object GUID. This must be a valid AD Schema object name or array of objects
        [Parameter(ValueFromPipelineByPropertyName )]
        #[ArgumentCompleter( { (Get-ADObjectGUIDs | where-object { $_.type -eq "Object" }).name })]
        #[ValidateScript( { $myArg = $_; (Get-ADObjectGUIDs | where-object { $_.name -eq $myArg -and $_.type -eq "Object" }) })]
        [String[]]$AppliesTo,

        # Whether the ACE is an allow or deny entry
        [Parameter(ValueFromPipelineByPropertyName )]
        [Validateset("Allow", "Deny")]
        [System.security.AccessControl.AccessControlType] $Action = "Allow",

        # Whether and how the inheritance applies to descendents
        [Parameter(ValueFromPipelineByPropertyName )]
        [System.DirectoryServices.ActiveDirectorySecurityInheritance] $InheritanceType = "All",

        [Parameter()]
        $ObjectGUIDs = $(write-warning "This is slow!"; get-ADObjectGUIDs)
    )

    Begin {
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
        $acesCreated = 0
    }

    Process {

        try {

            if (-not $identity) {
                write-loghandler -level "Debug" -message "Resolving principal to identity" -indentLevel 1
                $PrincipalName = $principal
                $principalSID = [System.Security.Principal.NTAccount]::new($principalName).translate([System.security.Principal.SecurityIdentifier])
                $identity = [System.Security.Principal.IdentityReference] $principalSID
            } else {
                write-loghandler -level "Debug" -message "Resolving identity to principal" -indentLevel 1
                $principalName = $identity.translate([System.Security.Principal.NTAccount]).value.toString()
            }
            write-loghandler -level "Debug" -message "Resolving AppliesTo to IOTs" -indentLevel 1
            try {
                $inheritedObjectTypeList = @(
                    If ($appliesTo) {
                        $AppliesTo | foreach-object {
                            $IOTName = $_
                            @{
                                Name = $IOTName
                                GUID = ($($ObjectGUIds).where({ $_.name -eq $IOTName -and $_.type -eq "Object" })).GUID
                            }
                        }
                    }
                    else {
                        @{
                            Name = "(All / Unspec)"
                            GUID = [GUID]"00000000-0000-0000-0000-000000000000"
                        }
                    }
                )
            } catch {
                Write-LogHandler -level "Warning" -message "Failed to resolve appliesTo ($appliesTo) to an IOT GUID."
                throw $_
            }
            write-loghandler -level "Debug" -message "Resolving ADRights / ExtendedRights"
            If ($ExtendedRight -and -not $ADRight) {
                write-loghandler -level "Debug" -message "Setting ADRight to 'ExtendedRight'" -indentLevel 2
                $ADRight = [System.directoryservices.ActiveDirectoryRights]"ExtendedRight"
            }
            write-loghandler -level "Debug" -message "Resolving ObjectTypes"
            try {
                $ObjectTypeList = $(
                    if ($extendedRight) {
                        write-loghandler -level "Debug" -message "ObjectType as extended right ($extendedRight)" -indentLevel 2
                        @{
                            Name = $extendedRight
                            Type = "ExtendedRight"
                            GUID = $($ObjectGUIDs).where( { $_.name -eq $extendedRight -and $_.type -eq "Right"} ).GUID
                        }
                    }
                    elseif ($targetObject) {
                        write-loghandler -level "Debug" -message "ObjectType as schema class or attribute" -indentLevel 2
                        $targetObject | foreach-object  {
                            $objectName = $_
                            @{
                                Name = $objectName
                                Type = "Schema class or attribute"
                                GUID = $($ObjectGUIDs).where( { $_.name -eq $objectName -and $_.type -eq "object"} ).GUID
                            }
                        }
                        write-loghandler -level "Debug" -message "finished resolving objectType" -indentLevel 2
                    }
                    else {
                        write-loghandler -level "Debug" -message "Setting null (wildcard) objectType / attribute" -indentLevel 2
                        @{
                            Name = "Null"
                            Type = "(Unknown / wildcard)"
                            GUID = [GUID]"00000000-0000-0000-0000-000000000000"
                        }
                    }
                )
            } catch {
                write-loghandler -level "Warning" -message "Failed to resolve an objectType from extendedRight($extendedRight)/targetObject($targetObject)" -indentLevel 1
                throw $_
            }
            write-loghandler -level "Debug" -message "Cycling through IOT and object lists to create single master list" -indentLevel 1
            $ACEParamList = @(
                foreach ($InheritedObjectType in $inheritedObjectTypeList) {
                    foreach ($ObjectType in $ObjectTypeList) {
                        @{
                            PrincipalName = $principalName
                            Identity = $Identity
                            ADRight = $ADRight
                            Action = $Action
                            objectType = $ObjectType['GUID']
                            InheritanceType = $InheritanceType
                            InheritedObjectType = $inheritedObjectType['GUID']
                        }
                        write-loghandler -level "Debug" -target $Principalname -message ("{0,-5} {1,-16} on: {2,-24} IOT: {3,-24} {4}" -f $action, $ADRight, ($ExtendedRight + $objectType['Name']), $inheritedObjectType['Name'], $PrincipalName) -indentLevel 1
                    }
                }
            )

            $ACEParamList | foreach-object -parallel  {
                New-object System.DirectoryServices.ActiveDirectoryAccessRule($_['Identity'], $_['ADRight'], $_['Action'], $_['objectType'], $_['InheritanceType'], $_['inheritedObjectType'])
            }
            $acesCreated +=$ACEParamList.count

        }
        catch {
            $_ | format-list * -force
            write-loghandler -level "warning" -message "WHOOPS"
        }
    }
    End{
        $sw.stop()
        write-loghandler -level "Debug" -message "Created $AcesCreated ACEs in $($sw.ElapsedMilliseconds) ms"
    }
}