Public/New-Tier0Delegation.ps1

function New-Tier0Delegation {

    <#
        .SYNOPSIS
            Delegates rights and permissions to the Tier0 Admin area.

        .DESCRIPTION
            This function applies delegation permissions for administrative groups within the Tier0
            administrative area, following a tiered administration model and principle of least privilege.
            It configures access control lists (ACLs) for various security functions including:
            - User Management (UM - Semi-Privileged User Management)
            - Group Management (GM - Semi-Privileged Group Management)
            - Privileged User Management (PUM)
            - Privileged Group Management (PGM)
            - Server Admin Groups Management (SAGM)
            - Privileged Infrastructure Services Management (PISM)
            - Privileged Access Workstation Management (PAWM)
            - Domain Controller Management (DCManagement)
            - Privileged Service Account Management (PSAM)
            - GPO Administration
            - Directory Replication
            - Infrastructure Administration
            - FSMO Role Transfer
            - AD Administration

            This function is critical for implementing proper security boundaries in a tiered
            administrative model.

        .PARAMETER ConfigXMLFile
            [System.IO.FileInfo] Full path to the XML configuration file.
            Contains all naming conventions, OU structure, and security settings.
            Must be a valid XML file with required schema elements.
            Default: C:\PsScripts\Config.xml

        .PARAMETER DMScripts
            [String] Path to all the scripts and files needed by this function.
            Should contain a SecTmpl subfolder.
            Default: C:\PsScripts\

        .EXAMPLE
            New-Tier0Delegation -ConfigXMLFile C:\PsScripts\Config.xml

            Delegates rights and permissions to the Tier0 Admin area using the default configuration file.

        .EXAMPLE
            $Splat = @{
                ConfigXMLFile = 'C:\CustomPath\Config.xml'
                DMScripts = 'D:\Scripts\'
                Verbose = $true
            }
            New-Tier0Delegation @Splat

            Delegates rights and permissions to the Tier0 Admin area with custom paths and verbose output.

        .INPUTS
            [System.IO.FileInfo]
            You can pipe the path to the XML configuration file to this function.

        .OUTPUTS
            [System.String]
            Returns completion status message.

        .NOTES
            Used Functions:
                Name ║ Module/Namespace
                ═══════════════════════════════════════════╬══════════════════════════════
                Set-StrictMode ║ Microsoft.PowerShell.Core
                Import-MyModule ║ EguibarIT
                Get-FunctionDisplay ║ EguibarIT
                Get-Content ║ Microsoft.PowerShell.Management
                Get-AdObjectType ║ EguibarIT
                Set-AdAclDelegateUserAdmin ║ EguibarIT.DelegationPS
                Set-AdAclDelegateGalAdmin ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteGroup ║ EguibarIT.DelegationPS
                Set-AdAclChangeGroup ║ EguibarIT.DelegationPS
                Set-AdAclDelegateComputerAdmin ║ EguibarIT.DelegationPS
                Add-GroupToSCManager ║ EguibarIT.DelegationPS
                Add-ServiceAcl ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteGMSA ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteMSA ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteUser ║ EguibarIT.DelegationPS
                Set-AdAclResetUserPassword ║ EguibarIT.DelegationPS
                Set-AdAclChangeUserPassword ║ EguibarIT.DelegationPS
                Set-AdAclUserGroupMembership ║ EguibarIT.DelegationPS
                Set-AdAclUserAccountRestriction ║ EguibarIT.DelegationPS
                Set-AdAclUserLogonInfo ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteGPO ║ EguibarIT.DelegationPS
                Set-AdAclLinkGPO ║ EguibarIT.DelegationPS
                Set-AdAclGPoption ║ EguibarIT.DelegationPS
                Set-AdDirectoryReplication ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteOU ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteSubnet ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteSite ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteSiteLink ║ EguibarIT.DelegationPS
                Set-AdAclFMSOtransfer ║ EguibarIT.DelegationPS
                Set-DeleteOnlyComputer ║ EguibarIT.DelegationPS
                Set-AdAclChangeSubnet ║ EguibarIT.DelegationPS
                Set-AdAclChangeSite ║ EguibarIT.DelegationPS
                Set-AdAclChangeSiteLink ║ EguibarIT.DelegationPS
                Write-Verbose ║ Microsoft.PowerShell.Utility
                Write-Error ║ Microsoft.PowerShell.Utility
                Get-Service ║ Microsoft.PowerShell.Management

        .NOTES
            Version: 1.0
            DateModified: 30/Apr/2025
            LastModifiedBy: Vicente Rodriguez Eguibar
                        vicente@eguibar.com
                        Eguibar IT
                        http://www.eguibarit.com

        .LINK
            https://github.com/vreguibar/EguibarIT

        .COMPONENT
            Active Directory

        .ROLE
            Security

        .FUNCTIONALITY
            Tier 0 Delegation
    #>


    [CmdletBinding(
        SupportsShouldProcess = $true,
        ConfirmImpact = 'High'
    )]
    [OutputType([System.String])]

    param (
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $True,
            ValueFromPipelineByPropertyName = $True,
            ValueFromRemainingArguments = $false,
            HelpMessage = 'Full path to the configuration.xml file',
            Position = 0)]
        [ValidateScript({
                if (-Not ($_ | Test-Path -PathType Leaf) ) {
                    throw ('File not found: {0}' -f $_)
                }
                if ($_.Extension -ne '.xml') {
                    throw ('File must be XML: {0}' -f $_)
                }
                try {
                    [xml]$xml = Get-Content -Path $_ -ErrorAction Stop
                    # Verify required XML elements are present
                    if ($null -eq $xml.n.Admin -or
                        $null -eq $xml.n.Admin.OUs) {
                        throw 'XML file is missing required elements (Admin or OUs section)'
                    }
                    return $true
                } catch {
                    throw ('Invalid XML file: {0}' -f $_.Exception.Message)
                }
            })]
        [PSDefaultValue(Help = 'Default Value is "C:\PsScripts\Config.xml"',
            Value = 'C:\PsScripts\Config.xml'
        )]
        [Alias('Config', 'XML', 'ConfigXml')]
        [System.IO.FileInfo]
        $ConfigXMLFile,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $false,
            HelpMessage = 'Path to all the scripts and files needed by this function',
            Position = 1)]
        [PSDefaultValue(
            Help = 'Default Value is "C:\PsScripts\"',
            Value = 'C:\PsScripts\'
        )]
        [Alias('ScriptPath')]
        [string]
        $DMScripts = 'C:\PsScripts\',

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false,
            ValueFromRemainingArguments = $false,
            HelpMessage = 'Start transcript logging to DMScripts path with function name',
            Position = 2)]
        [Alias('Transcript', 'Log')]
        [switch]
        $EnableTranscript

    )

    Begin {
        Set-StrictMode -Version Latest

        If (-not $PSBoundParameters.ContainsKey('ConfigXMLFile')) {
            $PSBoundParameters['ConfigXMLFile'] = 'C:\PsScripts\Config.xml'
        } #end If

        If (-not $PSBoundParameters.ContainsKey('DMScripts')) {
            $PSBoundParameters['DMScripts'] = 'C:\PsScripts\'
        } #end If

        # If EnableTranscript is specified, start a transcript
        if ($EnableTranscript) {
            # Ensure DMScripts directory exists
            if (-not (Test-Path -Path $DMScripts -PathType Container)) {
                try {
                    New-Item -Path $DMScripts -ItemType Directory -Force | Out-Null
                    Write-Verbose -Message ('Created transcript directory: {0}' -f $DMScripts)
                } catch {
                    Write-Warning -Message ('Failed to create transcript directory: {0}' -f $_.Exception.Message)
                } #end try-catch
            } #end if

            # Create transcript filename using function name and current date/time
            $TranscriptFile = Join-Path -Path $DMScripts -ChildPath ('{0}_{1}.LOG' -f $MyInvocation.MyCommand.Name, (Get-Date -Format 'yyyyMMdd_HHmmss'))

            try {
                Start-Transcript -Path $TranscriptFile -Force -ErrorAction Stop
                Write-Verbose -Message ('Transcript started: {0}' -f $TranscriptFile)
            } catch {
                Write-Warning -Message ('Failed to start transcript: {0}' -f $_.Exception.Message)
            } #end try-catch
        } #end if

        # Display function header if variables exist
        if ($null -ne $Variables -and
            $null -ne $Variables.Header) {

            $txt = ($Variables.Header -f
                (Get-Date).ToString('dd/MMM/yyyy'),
                $MyInvocation.Mycommand,
                (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False)
            )
            Write-Verbose -Message $txt
        } #end If

        ##############################
        # Module imports

        Import-MyModule -Name 'ActiveDirectory' -Verbose:$false
        Import-MyModule -Name 'EguibarIT' -Verbose:$false
        Import-MyModule -Name 'EguibarIT.DelegationPS' -Verbose:$false

        ##############################
        # Variables Definition

        # parameters variable for splatting CMDlets
        [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase)
        #[System.Collections.ArrayList]$ArrayList = [System.Collections.ArrayList]::new()
        [System.Collections.Generic.List[object]]$ArrayList = [System.Collections.Generic.List[object]]::New()

        # Load the XML configuration file
        try {
            [xml]$confXML = [xml](Get-Content -Path $PSBoundParameters['ConfigXMLFile'] -ErrorAction Stop)
            Write-Verbose -Message ('Successfully loaded configuration from {0}' -f $PSBoundParameters['ConfigXMLFile'])
        } catch {
            Write-Error -Message ('Error reading XML file: {0}' -f $_.Exception.Message)
            throw
        } #end Try-Catch

        # Naming conventions hashtable
        $NC = @{'sl' = $confXML.n.NC.LocalDomainGroupPreffix
            'sg'     = $confXML.n.NC.GlobalGroupPreffix
            'su'     = $confXML.n.NC.UniversalGroupPreffix
            'Delim'  = $confXML.n.NC.Delimiter
            'T0'     = $confXML.n.NC.AdminAccSufix0
            'T1'     = $confXML.n.NC.AdminAccSufix1
            'T2'     = $confXML.n.NC.AdminAccSufix2
        }
        # For example :
        # ('{0}{1}{2}{1}{3}' -f $NC['sg'], $NC['Delim'], $confXML.n.Admin.lg.PAWM.name, $NC['T0'])
        # Returns: SG_PAWM_T0

        #region Local groups Variables
        $SL_UM = Get-SafeVariable -Name 'SL_UM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.UM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_GM = Get-SafeVariable -Name 'SL_GM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.GM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_PUM = Get-SafeVariable -Name 'SL_PUM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PUM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_PGM = Get-SafeVariable -Name 'SL_PGM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PGM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_SAGM = Get-SafeVariable -Name 'SL_SAGM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.SAGM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_PISM = Get-SafeVariable -Name 'SL_PISM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PISM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_PAWM = Get-SafeVariable -Name 'SL_PAWM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PAWM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_DcManagement = Get-SafeVariable -Name 'SL_DcManagement' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.DcManagement.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_PSAM = Get-SafeVariable -Name 'SL_PSAM' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.PSAM.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_GpoAdminRight = Get-SafeVariable -Name 'SL_GpoAdminRight' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.GpoAdminRight.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_DirReplRight = Get-SafeVariable -Name 'SL_DirReplRight' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.DirReplRight.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_InfraRight = Get-SafeVariable -Name 'SL_InfraRight' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.InfraRight.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_TransferFSMOright = Get-SafeVariable -Name 'SL_TransferFSMOright' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.TransferFSMOright.Name)
            Get-AdObjectType -Identity $groupName
        }

        $SL_AdRight = Get-SafeVariable -Name 'SL_AdRight' -CreateIfNotExist {
            $groupName = ('{0}{1}{2}' -f $NC['sl'], $NC['Delim'], $confXML.n.Admin.LG.AdRight.Name)
            Get-AdObjectType -Identity $groupName
        }
        #endregion Local groups Variables

        $AllLocalGroupVariables = @(
            $SL_UM,
            $SL_GM,
            $SL_PUM,
            $SL_PGM,
            $SL_SAGM,
            $SL_PISM,
            $SL_PAWM,
            $SL_DcManagement,
            $SL_PSAM,
            $SL_GpoAdminRight,
            $SL_DirReplRight,
            $SL_InfraRight,
            $SL_TransferFSMOright,
            $SL_AdRight
        )
        foreach ($Item in $AllLocalGroupVariables) {
            if ($null -ne $Item) {
                [void]$ArrayList.Add($Item)
            } else {
                Write-Error -Message ('Group not found: {0}' -f $Item)
            } #end If GroupName
        } #end ForEach

        # Build OU paths using string format for consistency
        [string]$ItAdminOuDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItAdminOU.name, $Variables.AdDn)
        [string]$ItAdminAccountsOuDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItAdminAccountsOU.name, $ItAdminOuDn)
        [string]$ItAdminGroupsOuDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItAdminGroupsOU.name, $ItAdminOuDn)
        [string]$ItPrivGroupsOuDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItPrivGroupsOU.name, $ItAdminOuDn)
        [string]$ItRightsOuDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItRightsOU.name, $ItAdminOuDn)
        [string]$ItAdminSrvGroupsOUDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItAdminSrvGroupsOU.name, $ItAdminOuDn)

        [string]$ItInfraT0OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItInfraT0OU.name, $ConfXML.n.Admin.OUs.ItInfraOU.name, $ItAdminOuDn)
        [string]$ItInfraT1OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItInfraT1OU.name, $ConfXML.n.Admin.OUs.ItInfraOU.name, $ItAdminOuDn)
        [string]$ItInfraT2OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItInfraT2OU.name, $ConfXML.n.Admin.OUs.ItInfraOU.name, $ItAdminOuDn)
        [string]$ItInfraStagingOuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItInfraStagingOU.name, $ConfXML.n.Admin.OUs.ItInfraOU.name, $ItAdminOuDn)

        [string]$ItPawT0OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItPawT0OU.name, $ConfXML.n.Admin.OUs.ItPawOU.name, $ItAdminOuDn)
        [string]$ItPawT1OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItPawT1OU.name, $ConfXML.n.Admin.OUs.ItPawOU.name, $ItAdminOuDn)
        [string]$ItPawT2OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItPawT2OU.name, $ConfXML.n.Admin.OUs.ItPawOU.name, $ItAdminOuDn)
        [string]$ItPawStagingOuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItPawStagingOU.name, $ConfXML.n.Admin.OUs.ItPawOU.name, $ItAdminOuDn)

        [string]$DCsOuDn = ('OU=Domain Controllers,{0}' -f $Variables.AdDn)
        [string]$ItQuarantinePcOuDn = ('OU={0},{1}' -f $ConfXML.n.Admin.OUs.ItNewComputersOU.name, $Variables.AdDn)

        [string]$ItSAT0OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItSAT0OU.name, $ConfXML.n.Admin.OUs.ItServiceAccountsOU.name, $ItAdminOuDn)
        [string]$ItSAT1OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItSAT1OU.name, $ConfXML.n.Admin.OUs.ItServiceAccountsOU.name, $ItAdminOuDn)
        [string]$ItSAT2OuDn = ('OU={0},OU={1},{2}' -f $ConfXML.n.Admin.OUs.ItSAT2OU.name, $ConfXML.n.Admin.OUs.ItServiceAccountsOU.name, $ItAdminOuDn)

        Write-Verbose -Message 'Starting the Tier0 delegation process...'
    } #end Begin

    Process {

        if ($PSCmdlet.ShouldProcess('Active Directory Security', 'Delegate Rights and Permissions to Tier0 Admin area')) {

            # Define progress variables
            [int]$CurrentStep = 0
            [int]$TotalSteps = 15 # Total number of major delegation tasks
            [string]$ProgressActivity = 'Delegating permissions to Tier0 Admin area'
            [string]$CurrentOperation = ''

            # Computer objects within this area MUST have read access, otherwise GPO will not apply

            # UM - Semi-Privileged User Management
            $CurrentStep++
            $CurrentOperation = 'Configuring User Management (UM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            Set-AdAclDelegateUserAdmin -Group $SL_UM -LDAPpath $ItAdminAccountsOuDn
            Set-AdAclDelegateGalAdmin -Group $SL_UM -LDAPpath $ItAdminAccountsOuDn



            # GM - Semi-Privileged Group Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Group Management (GM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            Set-AdAclCreateDeleteGroup -Group $SL_GM -LDAPpath $ItAdminGroupsOuDn
            Set-AdAclChangeGroup -Group $SL_GM -LDAPpath $ItAdminGroupsOuDn



            # PUM - Privileged User Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Privileged User Management (PUM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            Set-AdAclDelegateUserAdmin -Group $SL_PUM -LDAPpath $ItAdminAccountsOuDn
            Set-AdAclDelegateGalAdmin -Group $SL_PUM -LDAPpath $ItAdminAccountsOuDn



            # PGM - Privileged Group Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Privileged Group Management (PGM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Create/Delete Groups
            Set-AdAclCreateDeleteGroup -Group $SL_PGM -LDAPpath $ItPrivGroupsOUDn
            Set-AdAclCreateDeleteGroup -Group $SL_PGM -LDAPpath $ItRightsOuDn
            # Change Group Properties
            Set-AdAclChangeGroup -Group $SL_PGM -LDAPpath $ItPrivGroupsOUDn
            Set-AdAclChangeGroup -Group $SL_PGM -LDAPpath $ItRightsOuDn




            # Local Admin groups management
            $CurrentStep++
            $CurrentOperation = 'Configuring Server Admin Groups Management (SAGM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Create/Delete Groups
            Set-AdAclCreateDeleteGroup -Group $SL_SAGM -LDAPpath $ItAdminSrvGroupsOUDn
            # Change Group Properties
            Set-AdAclChangeGroup -Group $SL_SAGM -LDAPpath $ItAdminSrvGroupsOUDn



            # PISM - Privileged Infrastructure Services Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Privileged Infrastructure Services Management (PISM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Create/Delete Computers
            Set-AdAclDelegateComputerAdmin -Group $SL_PISM -LDAPpath $ItInfraT0OuDn
            Set-AdAclDelegateComputerAdmin -Group $SL_PISM -LDAPpath $ItInfraT1OuDn
            Set-AdAclDelegateComputerAdmin -Group $SL_PISM -LDAPpath $ItInfraT2OuDn
            Set-AdAclDelegateComputerAdmin -Group $SL_PISM -LDAPpath $ItInfraStagingOuDn



            # PAWM - Privileged Access Workstation Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Privileged Access Workstation Management (PAWM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            Set-AdAclDelegateComputerAdmin -Group $SL_PAWM -LDAPpath $ItPawT0OuDn
            Set-AdAclDelegateComputerAdmin -Group $SL_PAWM -LDAPpath $ItPawT1OuDn
            Set-AdAclDelegateComputerAdmin -Group $SL_PAWM -LDAPpath $ItPawT2OuDn
            Set-AdAclDelegateComputerAdmin -Group $SL_PAWM -LDAPpath $ItPawStagingOuDn



            # DC_Management - Domain Controllers Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Domain Controller Management (DCM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat
            Set-AdAclDelegateComputerAdmin -Group $SL_DcManagement -LDAPpath $DCsOuDn

            # DC_Management - Service Control Management (Permission to services)
            Add-GroupToSCManager -Group $SL_DcManagement -verbose

            # DC_Management - Service permissions
            $CurrentStep++
            $CurrentOperation = 'Configuring service permissions for DC Management'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Get all services
            $AllServices = Get-Service -ErrorAction SilentlyContinue
            $ServiceCount = $AllServices.Count
            $ServiceIndex = 0

            Foreach ($item in $AllServices) {
                $ServiceIndex++
                # Update nested progress for service permissions
                $NestedProgressSplat = @{
                    Id              = 1
                    Activity        = 'Configuring service permissions'
                    Status          = ('Service {0}/{1}: {2}' -f $ServiceIndex, $ServiceCount, $item.Name)
                    PercentComplete = (($ServiceIndex / $ServiceCount) * 100)
                }
                Write-Progress @NestedProgressSplat

                # ToDo: Error due Access Denied.
                #Add-ServiceAcl -Group $SL_DcManagement -Service $Item.Name -verbose

            } #end Foreach service

            # Complete the nested progress bar
            Write-Progress -Id 1 -Activity 'Configuring service permissions' -Completed


            # PSAM - Privileged Service Account Management
            $CurrentStep++
            $CurrentOperation = 'Configuring Privileged Service Account Management (PSAM) permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Managed Service Accounts "Default Container"
            $Splat = @{
                Group    = $SL_PSAM
                LDAPPath = ('CN=Managed Service Accounts,{0}' -f $Variables.AdDn)
            }
            Set-AdAclCreateDeleteGMSA @Splat
            Set-AdAclCreateDeleteMSA @Splat

            # TIER 0
            $Splat = @{
                Group    = $SL_PSAM
                LDAPPath = $ItSAT0OuDn
            }
            Set-AdAclCreateDeleteGMSA @Splat
            Set-AdAclCreateDeleteMSA @Splat
            Set-AdAclCreateDeleteUser @Splat
            Set-AdAclResetUserPassword @Splat
            Set-AdAclChangeUserPassword @Splat
            Set-AdAclUserGroupMembership @Splat
            Set-AdAclUserAccountRestriction @Splat
            Set-AdAclUserLogonInfo @Splat

            # TIER 1
            $Splat = @{
                Group    = $SL_PSAM
                LDAPPath = $ItSAT1OuDn
            }
            Set-AdAclCreateDeleteGMSA @Splat
            Set-AdAclCreateDeleteMSA @Splat
            Set-AdAclCreateDeleteUser @Splat
            Set-AdAclResetUserPassword @Splat
            Set-AdAclChangeUserPassword @Splat
            Set-AdAclUserGroupMembership @Splat
            Set-AdAclUserAccountRestriction @Splat
            Set-AdAclUserLogonInfo @Splat

            # TIER 2
            $Splat = @{
                Group    = $SL_PSAM
                LDAPPath = $ItSAT2OuDn
            }
            Set-AdAclCreateDeleteGMSA @Splat
            Set-AdAclCreateDeleteMSA @Splat
            Set-AdAclCreateDeleteUser @Splat
            Set-AdAclResetUserPassword @Splat
            Set-AdAclChangeUserPassword @Splat
            Set-AdAclUserGroupMembership @Splat
            Set-AdAclUserAccountRestriction @Splat
            Set-AdAclUserLogonInfo @Splat




            # GPO Admins
            $CurrentStep++
            $CurrentOperation = 'Configuring GPO Admin permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Create/Delete GPOs
            Set-AdAclCreateDeleteGPO -Group $SL_GpoAdminRight -Confirm:$false
            # Link existing GPOs to OUs
            Set-AdAclLinkGPO -Group $SL_GpoAdminRight
            # Change GPO options
            Set-AdAclGPoption -Group $SL_GpoAdminRight


            # Directory Replication Rights
            $CurrentStep++
            $CurrentOperation = 'Configuring Directory Replication Rights'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Delegate Directory Replication Rights
            # ToDo: 'Error while trying to change Directory Replication Rights. Access denied.'
            #Set-AdDirectoryReplication -Group $SL_DirReplRight -Confirm:$false




            # Infrastructure Admins
            $CurrentStep++
            $CurrentOperation = 'Configuring Infrastructure Admin permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Organizational Units at domain level
            Set-AdAclCreateDeleteOU -Group $SL_InfraRight -LDAPpath $Variables.AdDn
            # Organizational Units at Admin area
            Set-AdAclCreateDeleteOU -Group $SL_InfraRight -LDAPpath $ItAdminOuDn
            # Subnet Configuration Container
            # Create/Delete Subnet
            Set-AdAclCreateDeleteSubnet -Group $SL_InfraRight
            # Site Configuration Container
            # Create/Delete Sites
            Set-AdAclCreateDeleteSite -Group $SL_InfraRight
            # Site-Link Configuration Container
            # Create/Delete Site-Link
            Set-AdAclCreateDeleteSiteLink -Group $SL_InfraRight

            # Transfer FSMO roles
            $CurrentStep++
            $CurrentOperation = 'Configuring FSMO Role Transfer permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            $Splat = @{
                Group     = $SL_TransferFSMOright
                FSMOroles = 'Schema', 'Infrastructure', 'DomainNaming', 'RID', 'PDC'
                Confirm   = $false
            }
            Set-AdAclFMSOtransfer @Splat




            # AD Admins
            $CurrentStep++
            $CurrentOperation = 'Configuring AD Admin permissions'
            $ProgressSplat = @{
                Activity        = $ProgressActivity
                Status          = ('{0}/{1} - {2}' -f $CurrentStep, $TotalSteps, $CurrentOperation)
                PercentComplete = (($CurrentStep / $TotalSteps) * 100)
            }
            Write-Progress @ProgressSplat

            # Domain Controllers management
            Set-AdAclDelegateComputerAdmin -Group $SL_AdRight -LDAPpath $DCsOuDn
            # Delete computers from default container
            Set-DeleteOnlyComputer -Group $SL_AdRight -LDAPpath $ItQuarantinePcOuDn
            # Subnet Configuration Container|
            # Change Subnet
            Set-AdAclChangeSubnet -Group $SL_AdRight
            # Site Configuration Container
            # Change Site
            Set-AdAclChangeSite -Group $SL_AdRight
            # Site-Link Configuration Container
            # Change SiteLink
            Set-AdAclChangeSiteLink -Group $SL_AdRight

            # Complete the progress bar
            Write-Progress -Activity $ProgressActivity -Completed

        } #end If ShouldProcess

    } #end Process

    End {
        if ($null -ne $Variables -and
            $null -ne $Variables.Footer) {

            $txt = ($Variables.Footer -f $MyInvocation.InvocationName,
                'Delegate Rights and Permissions to Tier0 Admin area.'
            )
            Write-Verbose -Message $txt
        } #end If

        # Stop transcript if it was started
        if ($EnableTranscript) {
            try {
                Stop-Transcript -ErrorAction Stop
                Write-Verbose -Message 'Transcript stopped successfully'
            } catch {
                Write-Warning -Message ('Failed to stop transcript: {0}' -f $_.Exception.Message)
            } #end Try-Catch
        } #end If
    } #end End
} #end Function New-Tier0Delegation