Public/Start-AdCleanOU.ps1

# Clean OU from default BuiltIn groups
function Start-AdCleanOU {
    <#
        .SYNOPSIS
            Cleans default OU permissions by removing built-in groups.
 
        .DESCRIPTION
            Removes default permissions from specified OU, including:
            - Account Operators built-in group
            - Print Operators built-in group
            - Pre-Windows 2000 Compatible Access group
            - Optionally removes Authenticated Users
            - Optionally removes unresolvable SIDs
 
            Implements comprehensive error handling and logging for each operation.
 
        .PARAMETER LDAPPath
            [String] Distinguished name of the OU to clean.
            Must be a valid LDAP path in the current domain.
 
        .PARAMETER RemoveAuthenticatedUsers
            [Switch] Remove Authenticated Users group.
            CAUTION: May affect GPO application.
 
        .PARAMETER RemoveUnknownSIDs
            [Switch] Remove unresolvable SIDs from ACL.
            Helps clean up orphaned permissions.
 
        .EXAMPLE
            Start-AdCleanOU -LDAPPath "OU=IT,DC=EguibarIT,DC=local"
 
            Removes built-in groups from IT OU.
 
        .EXAMPLE
            $params = @{
                LDAPPath = "OU=Admin,DC=EguibarIT,DC=local"
                RemoveAuthenticatedUsers = $true
                RemoveUnknownSIDs = $true
            }
            Start-AdCleanOU @params -Verbose
 
            Removes all default groups and unknown SIDs with verbose logging.
 
        .OUTPUTS
            [void]
 
        .NOTES
            Used Functions:
                Name ║ Module
                ═══════════════════════════════════════╬════════════════════════
                Set-AdAclCreateDeleteUser ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteComputer ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteGroup ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeleteContact ║ EguibarIT.DelegationPS
                Set-CreateDeleteInetOrgPerson ║ EguibarIT.DelegationPS
                Set-AdAclCreateDeletePrintQueue ║ EguibarIT.DelegationPS
                Remove-PreWin2000 ║ EguibarIT.DelegationPS
                Remove-PreWin2000FromOU ║ EguibarIT.DelegationPS
                Remove-AccountOperator ║ EguibarIT.DelegationPS
                Remove-PrintOperator ║ EguibarIT.DelegationPS
                Remove-AuthUser ║ EguibarIT.DelegationPS
                Remove-UnknownSID ║ EguibarIT.DelegationPS
                Get-CurrentErrorToDisplay ║ EguibarIT
                Get-FunctionDisplay ║ EguibarIT
                Get-ADGroup ║ ActiveDirectory
        .NOTES
            Version: 1.3
            DateModified: 31/Mar/2024
            LasModifiedBy: Vicente Rodriguez Eguibar
                vicente@eguibar.com
                Eguibar IT
                http://www.eguibarit.com
 
        .LINK
            https://github.com/vreguibar/EguibarIT
        .LINK
            https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/implementing-least-privilege-administrative-models
 
    #>


    [CmdletBinding(
        SupportsShouldProcess = $true,
        ConfirmImpact = 'High'
    )]
    [OutputType([void])]

    param (
        #PARAM1 Distinguished name of the OU to be cleaned
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = 'Distinguished name of the OU to be cleaned.',
            Position = 0)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript(
            { Test-IsValidDN -ObjectDN $_ },
            ErrorMessage = 'DistinguishedName provided is not valid! Please Check.'
        )]
        [Alias('DN', 'DistinguishedName')]
        [String]
        $LDAPpath,

        #PARAM2 Remove Authenticated Users
        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = 'Remove Authenticated Users.',
            Position = 1)]
        [switch]
        $RemoveAuthenticatedUsers,

        #PARAM3 Remove Unknown SIDs
        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = 'Remove Unknown SIDs.',
            Position = 2)]
        [switch]
        $RemoveUnknownSIDs,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false,
            HelpMessage = 'If present, the function will not ask for confirmation when performing actions.',
            Position = 3)]
        [Switch]
        $Force
    )

    begin {
        Set-StrictMode -Version Latest

        # Initialize logging
        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.DelegationPS' -Verbose:$false

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

        [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase)

        # Get Account Operators group
        try {

            $AccountOperators = Get-ADGroup -Filter { SID -like 'S-1-5-32-548' }

            $Splat = @{
                Group      = $AccountOperators
                LDAPPath   = $PSBoundParameters['LDAPpath']
                RemoveRule = $true
            }

        } catch {

            Write-Error -Message ('Failed to get Account Operators group: {0}' -f $_.Exception.Message)
            throw

        } #end try-catch
    } #end Begin

    process {

        if ($PSCmdlet.ShouldProcess($LDAPpath, 'Clean OU permissions')) {

            # For operations that need additional confirmation
            if ($Force -or $PSCmdlet.ShouldContinue(
                    "This will remove all built-in groups from OU '$LDAPpath', which may affect permissions. Continue?",
                    'Confirm Permission Changes')) {

                # Remove the Account Operators group from ACL to Create/Delete Users
                try {
                    Set-AdAclCreateDeleteUser @Splat
                } catch {
                    Write-Error -Message 'Error when delegating user Create/Delete cleanup permission'
                } #end Try-Catch


                # Remove the Account Operators group from ACL to Create/Delete Computers
                try {
                    Set-AdAclCreateDeleteComputer @Splat
                } catch {
                    Write-Error -Message 'Error when delegating computer cleanup permission'
                } #end Try-Catch


                # Remove the Account Operators group from ACL to Create/Delete Groups
                try {
                    Set-AdAclCreateDeleteGroup @Splat
                } catch {
                    Write-Error -Message 'Error when delegating group cleanup permission'
                } #end Try-Catch


                # Remove the Account Operators group from ACL to Create/Delete Contacts
                try {
                    Set-AdAclCreateDeleteContact @Splat
                } catch {
                    Write-Error -Message 'Error when delegating contact cleanup permission'
                } #end Try-Catch


                # Remove the Account Operators group from ACL to Create/Delete inetOrgPerson
                try {
                    Set-CreateDeleteInetOrgPerson @Splat
                } catch {
                    Write-Error -Message 'Error when delegating InetOrg cleanup permission'
                } #end Try-Catch


                # Remove the Print Operators group from ACL to Create/Delete PrintQueues
                try {
                    Set-AdAclCreateDeletePrintQueue @Splat
                } catch {
                    Write-Error -Message 'Error when delegating PrintQueue Create/Delete cleanup permission'
                } #end Try-Catch


                # Remove Pre-Windows 2000 Compatible Access group from Admin-User
                try {
                    Remove-PreWin2000 -LDAPPath $PSBoundParameters['LDAPPath']
                } catch {
                    Write-Error -Message 'Error when delegating Pre-Win2000 cleanup permission'
                } #end Try-Catch


                # Remove Pre-Windows 2000 Access group from OU
                try {
                    Remove-PreWin2000FromOU -LDAPPath $PSBoundParameters['LDAPPath']
                } catch {
                    Write-Error -Message 'Error when delegating Pre-Win2000 cleanup from OU permission'
                } #end Try-Catch


                # Remove ACCOUNT OPERATORS 2000 Access group from OU
                try {
                    Remove-AccountOperator -LDAPPath $PSBoundParameters['LDAPPath']
                } catch {
                    Write-Error -Message 'Error when delegating AccountOperators cleanup permission'
                } #end Try-Catch


                # Remove PRINT OPERATORS 2000 Access group from OU
                try {
                    Remove-PrintOperator -LDAPPath $PSBoundParameters['LDAPPath']
                } catch {
                    Write-Error -Message 'Error when delegating PrintOperators cleanup permission'
                } #end Try-Catch


                If ($PsBoundParameters['RemoveAuthenticatedUsers']) {
                    # Remove AUTHENTICATED USERS group from OU
                    try {
                        Remove-AuthUser -LDAPPath $PSBoundParameters['LDAPPath']
                    } catch {
                        Write-Error -Message 'Error when delegating Authenticated Users cleanup permission'
                    } #end Try-Catch

                    Write-VerboseDebug -Message 'Removing Authenticated Users'
                }  #end If

                If ($PsBoundParameters['$RemoveUnknownSIDs']) {
                    # Remove Un-Resolvable SID from a given object
                    try {
                        Remove-UnknownSID -LDAPPath $PSBoundParameters['LDAPPath'] -RemoveSID
                    } catch {
                        Write-Error -Message 'Error when removing Unknown SIDs'
                    } #end Try-Catch

                    Write-Debug -Message 'Remove Un-Resolvable / Unknown SIDs'
                } #end If
            } #end if ShouldContinue
        } #end If

    } #end Process

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

            $txt = ($Variables.Footer -f $MyInvocation.InvocationName,
                'removing Builtin groups.'
            )
            Write-Verbose -Message $txt
        } #end If
    } #end End

} #end Function Start-ADCleanOU