Public/Set-PrivilegedUsersHousekeeping.ps1

function Set-PrivilegedUsersHousekeeping {
    <#
        .SYNOPSIS
            Organizes user accounts into corresponding admin tier groups and optionally disables non-standard users.

        .DESCRIPTION
            This function scans all user accounts in a specified OU and assigns them to the respective
            administrative tier groups based on their naming conventions. Users not adhering to the standard naming
            conventions can optionally be disabled.

        .PARAMETER AdminUsersDN
            Specifies the Distinguished Name of the OU where admin user accounts are stored.

        .PARAMETER DisableNonStandardUsers
            If this switch is provided, the function will disable user accounts that do not follow the standard naming conventions.

        .EXAMPLE
            Set-PrivilegedUsersHousekeeping -AdminUsersDN "OU=Users,OU=Admin,DC=EguibarIT,DC=local" -DisableNonStandardUsers
            This example will classify users in the specified OU and disable non-standard users.

        .EXAMPLE
            Set-PrivilegedUsersHousekeeping -AdminUsersDN 'OU=Users,OU=Admin,DC=EguibarIT,DC=local' -Tier0Group 'SG_Tier0Admins' -Tier1Group 'SG_Tier1Admins' -Tier2Group 'SG_Tier2Admins' -ExcludeList @('TheGood', 'TheUgly') -DisableNonStandardUsers -Verbose

        .EXAMPLE
            Set-PrivilegedUsersHousekeeping -AdminUsersDN "OU=Users,OU=Admin,DC=EguibarIT,DC=local"

        .NOTES
            Used Functions:
                Name | Module
                ---------------------------------------|--------------------------
                Get-ADUser         | ActiveDirectory
                Get-ADGroupMember         | ActiveDirectory
                Add-ADGroupMember         | ActiveDirectory
                Disable-ADAccount         | ActiveDirectory
                Import-Module | Microsoft.PowerShell.Core
                Write-Verbose | Microsoft.PowerShell.Utility
                Write-Progress | Microsoft.PowerShell.Utility
                Get-FunctionToDisplay | EguibarIT.DelegationPS & EguibarIT.HousekeepingPS
                Test-IsValidDN | EguibarIT.DelegationPS & EguibarIT.HousekeepingPS
                Get-AdObjectType | EguibarIT.DelegationPS & EguibarIT.HousekeepingPS

        .NOTES
            Version: 1.0
            DateModified: 20/Jul/2017
            LasModifiedBy: Vicente Rodriguez Eguibar
                vicente@eguibar.com
                Eguibar Information Technology S.L.
                http://www.eguibarit.com
    #>

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

    Param (

        #Param1
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Admin User Account OU Distinguished Name.',
            Position = 0)]
        [ValidateScript({ Test-IsValidDN -ObjectDN $_ }, ErrorMessage = 'DistinguishedName provided is not valid! Please Check.')]
        [Alias('DN', 'DistinguishedName', 'LDAPPath')]
        [String]
        $AdminUsersDN,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Group containing all Tier0 Semi-Privileged/Privileged users.',
            Position = 1)]
        $Tier0Group,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Group containing all Tier1 Semi-Privileged/Privileged users.',
            Position = 2)]
        $Tier1Group,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Group containing all Tier2 Semi-Privileged/Privileged users.',
            Position = 3)]
        $Tier2Group,

        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'User list to be excluded from this process.',
            Position = 4)]
        [System.Collections.Generic.List[string]]
        $ExcludeList,

        #Param2
        [Parameter(Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'If present, will disable all Non-Standard users.',
            Position = 5)]
        [switch]
        $DisableNonStandardUsers

    )
    Begin {
        $txt = ($Variables.HeaderHousekeeping -f
            (Get-Date).ToShortDateString(),
            $MyInvocation.Mycommand,
            (Get-FunctionDisplay -HashTable $PsBoundParameters -Verbose:$False)
        )
        Write-Verbose -Message $txt

        # Verify the Active Directory module is loaded
        Import-MyModule ActiveDirectory

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

        # parameters variable for splatting CMDlets
        [hashtable]$Splat = [hashtable]::New([StringComparer]::OrdinalIgnoreCase)

        [int]$i = 0

        # If parameter is parsed, initialize variable to be used by default objects
        If (-Not $PSBoundParameters.ContainsKey('ExcludeList')) {
            $ExcludeList = [System.Collections.Generic.List[String]]::New()
        } #end If

        $wellKnownUserSids = @{
            'S-1-5-21-*-500' = 'Administrator'
            'S-1-5-21-*-502' = 'krbtgt'
        }

        foreach ($sid in $wellKnownUserSids.Keys) {
            # For these SIDs, we always need to use the wildcard approach
            $users = Get-ADUser -Filter * | Where-Object -FilterScript { $_.SID -like $sid }

            foreach ($item in $users) {
                If ($item.SamAccountName -notin $ExcludeList) {
                    $ExcludeList.Add($item.SamAccountName) | Out-Null
                }
            } # end foreach

        } #end Foreach


        # Fetch all user accounts in the given OU
        try {
            $Splat = @{
                Filter      = '*'
                Properties  = 'EmployeeType'
                SearchBase  = $PsBoundParameters['AdminUsersDN']
                ErrorAction = 'Stop'
            }
            $AllPrivUsers = Get-ADUser @Splat
        } catch {
            Write-Error -Message ('Failed to retrieve users: {0}' -f $_)
            return
        } #end Try-Catch

        Write-Verbose -Message ('
            Found {0} semi privileged accounts (_T0, _T1, _T2)
            in {1}'
 -f
            $AllPrivUsers.Count, $PsBoundParameters['AdminUsersDN']
        )

        # Initialize and Get each tier group
        $tierGroups = @{
            T0 = Get-AdObjectType -Identity $PsBoundParameters['Tier0Group']

            T1 = if ($Tier1Group) {
                Get-AdObjectType -Identity $PsBoundParameters['Tier1Group']
            }

            T2 = if ($Tier2Group) {
                Get-AdObjectType -Identity $PsBoundParameters['Tier2Group']
            }
        }

        # Define group per each tier to hold members
        $tierMembers = @{
            T0 = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
            T1 = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
            T2 = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
        } # end tierMembers


        # Populate existing members of tier groups
        foreach ($tier in $tierGroups.Keys) {
            if ($tierGroups[$tier]) {
                Get-ADGroupMember -Identity $tierGroups[$tier] | ForEach-Object {
                    $tierMembers[$tier].Add($_.SamAccountName)
                }
            } #end If
        } #end Foreach

    } #end Begin

    Process {

        # Iterate all found users
        Foreach ($user in $AllPrivUsers) {
            $i ++

            # Display the progress bar
            $parameters = @{
                Activity        = 'Checking Privileged Users'
                Status          = ('Working on item No. {0} from {1}' -f $i, $AllPrivUsers.Count)
                PercentComplete = ($i / $AllPrivUsers.Count * 100)
            }
            Write-Progress @parameters

            # Check Exclude list
            if ($user.SamAccountName -in $ExcludeList) {
                continue
            }

            # Check if EmployeeType is defined. Otherwise use last 3 characters of SamAccountName
            $tier = if ($user.EmployeeType -in @('T0', 'T1', 'T2')) {
                $user.EmployeeType
            } else {
                $user.SamAccountName -replace '.*(_T[0-2])$', '$1' -replace '_', ''
            } #end If-Else

            # Check compliance on the user. Disable if needed.
            if ($tier -notin @('T0', 'T1', 'T2')) {

                Write-Warning -Message ('
                    User {0}
                    has an invalid tier: {1}'
 -f
                    $user.SamAccountName, $tier
                )
                if ($DisableNonStandardUsers -and $PSCmdlet.ShouldProcess($user.SamAccountName, 'Disable non-standard user')) {

                    Disable-ADAccount -Identity $user
                    Write-Verbose -Message ('Account {0} was disabled due to compliance.' -f $user.SamAccountName)

                } #end If
                continue
            } #end If-Else

            # Add Semi-Privileged users to the corresponding group
            if (-not $tierMembers[$tier].Contains($user.SamAccountName)) {

                #Get current group
                $groupName = $tierGroups[$tier].Name

                if ($PSCmdlet.ShouldProcess($user.SamAccountName, "Add to $groupName")) {

                    # Add user to the group
                    Add-ADGroupMember -Identity $tierGroups[$tier] -Members $user

                    Write-Verbose -Message ('{0} - {1} added to {2}' -f $tier, $user.SamAccountName, $groupName)

                    $tierMembers[$tier].Add($user.SamAccountName)

                } # end if
            } # end if

        } #end ForEach
    } #end Process

    End {
        $summary = $tierMembers.GetEnumerator() | ForEach-Object {
            ' {0} Members: {1}' -f $_.Key, $_.Value.Count
        } # end ForEach-Object
        Write-Verbose -Message ('Summary:{0}{1}' -f $Constants.NL, ($summary -join $Constants.NL))


        $txt = ($Variables.FooterHousekeeping -f $MyInvocation.InvocationName,
            'setting semi-privileged and/or Privileged users housekeeping.'
        )
        Write-Verbose -Message $txt
    } #end End
} #end Function