Public/Set-PrivilegedComputerHousekeeping.ps1

Function Set-PrivilegedComputerHousekeeping {
    <#
        .SYNOPSIS
            Manages privileged and semi-privileged computers (PAWs and Infrastructure Servers) by updating their group memberships.

        .DESCRIPTION
            This function identifies privileged (PAWs) and infrastructure servers from a specified Organizational Unit (OU) in Active Directory
            and ensures their correct group memberships. It assigns computers running server operating systems to the infrastructure servers group
            and other machines to the PAW group. This operation helps to automate the housekeeping of privileged computers, ensuring they are
            consistently and correctly managed according to their roles.

        .PARAMETER SearchRootDN
            Specifies the distinguished name (DN) of the OU where the function will search for computers. Only computers under this
            search base will be processed.

        .PARAMETER InfraGroup
            Specifies the distinguished name or group identifier for the group that contains all Infrastructure Servers.
            Computers with server operating systems will be added to this group if found.

        .PARAMETER PawGroup
            Specifies the distinguished name or group identifier for the group that contains all PAW (Privileged Access Workstation) machines.
            Non-server machines will be added to this group if found.

        .EXAMPLE
            Set-PrivilegedComputerHousekeeping -SearchRootDN "OU=Admin,DC=EguibarIT,DC=local" -InfraGroup 'SL_InfrastructureServers' -PawGroup 'SL_PAWs'

            Description:
            This example runs the housekeeping process for computers within the "OU=Admin,DC=EguibarIT,DC=local" organizational unit.
            It adds server computers to the 'SL_InfrastructureServers' group and PAWs to the 'SL_PAWs' group based on their operating system.

        .EXAMPLE
            Set-PrivilegedComputerHousekeeping -SearchRootDN "OU=Servers,DC=EguibarIT,DC=local" -InfraGroup 'Infra_Servers_Group' -PawGroup 'PAW_Group' -WhatIf

            Description:
            This example shows what the function would do (without actually performing the changes) if it were to run on the "OU=Servers" organizational
            unit, adding servers to the 'Infra_Servers_Group' and PAWs to the 'PAW_Group'. The `-WhatIf` parameter simulates the execution.

        .INPUTS
            None.
            The function does not accept input objects from the pipeline.

        .OUTPUTS
            None.
            This function does not return any objects. It uses verbose messages for output and updates Active Directory objects.


        .NOTES
            Used Functions:
                Name | Module
                ---------------------------------------|--------------------------
                Get-ADComputer         | ActiveDirectory
                Remove-ADGroupMember         | ActiveDirectory
                Add-ADGroupMember         | 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

        .LINK
            https://www.delegationmodel.com/

    #>


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

    param(

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

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Identity of the group of all Infrastructure Servers.',
            Position = 1)]
        [ValidateNotNullOrEmpty()]
        [Alias('InfrastructureServers', 'AllServers', 'ServersGroupID')]
        $InfraGroup,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Identity of the group of all PAWs.',
            Position = 2)]
        [ValidateNotNullOrEmpty()]
        [Alias('Paws', 'AllPaws', 'PawGroupID')]
        $PawGroup

    )

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

        Import-MyModule ActiveDirectory

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

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

        [int]$i = 0

        $stats = @{
            NewServer = 0
            NewPAW    = 0
        }

        # Lists for computers
        $AllPrivComputers = [System.Collections.Generic.List[Object]]::new()

        # Get Infrastructure Servers group
        $InfraGroup = Get-AdObjectType -Identity $PsBoundParameters['InfraGroup']
        if (-not $InfraGroup) {
            Throw "Infrastructure Servers group ($InfraGroup) not found."
        } #end If

        $PawGroup = Get-AdObjectType -Identity $PsBoundParameters['PawGroup']
        if (-not $PawGroup) {
            Throw "PAW group ($PawGroup) not found."
        } #end If

    } #end Begin

    Process {

        Write-Verbose -Message 'Getting the list of ALL T0 servers and PAW computers.'
        $Props = @(
            'OperatingSystem',
            'SamAccountName',
            'DistinguishedName'
        )

        $Splat = @{
            Filter     = '*'
            Properties = $Props
            SearchBase = $PsBoundParameters['SearchRootDN']
        }
        $AllPrivComputers = Get-ADComputer @Splat | Select-Object -Property $Props

        $TotalObjectsFound = $AllPrivComputers.Count
        if ($TotalObjectsFound -eq 0) {
            Write-Verbose -Message ('No computers found in the search root: {0}.' -f $SearchRootDN)
            return
        } #end If

        # Iterate all found items
        Foreach ($item in $AllPrivComputers) {
            $i ++

            $error.Clear()

            # Display the progress bar
            $parameters = @{
                Activity        = 'Checking computers within Admin Area'
                Status          = "Working on item No. $i from $TotalObjectsFound"
                PercentComplete = ($i / $TotalObjectsFound * 100)
            }
            Write-Progress @parameters

            # exclude all computers within Housekeeping
            if ($item.DistinguishedName -notlike '*Housekeeping*') {

                $targetGroup = if ($item.OperatingSystem -like '*Server*') {
                    $infraGroup
                    $stats.NewServer++
                } else {
                    $pawGroup
                    $stats.NewPAW++
                } #end If-Else

                if ($PSCmdlet.ShouldProcess($item.SamAccountName, "Add to $($targetGroup.Name)")) {

                    Add-ADGroupMember -Identity $targetGroup -Members $item -ErrorAction Stop

                    Write-Verbose -Message ('
                        Added {0}
                        to {1}'
 -f
                        $item.SamAccountName, $targetGroup.Name
                    )

                } #end If
            } #end If

        } #end Foreach

    } #end Process

    End {
        $Constants.NL
        Write-Verbose -Message 'Any semi-privileged and/or Privileged computer will be patched and managed by Tier0 services'
        $Constants.NL
        Write-Verbose -Message ('Servers found...: {0}' -f $stats.NewServer.Count)
        Write-Verbose -Message ('PAWs found......: {0}' -f $stats.NewPAW.Count)
        $Constants.NL

        $txt = ($Variables.FooterHousekeeping -f $MyInvocation.InvocationName,
            'setting Infrastructure Servers / PAWs housekeeping.'
        )
        Write-Verbose -Message $txt
    } #end End
}