Public/Set-SemiPrivilegedUser.ps1

function Set-SemiPrivilegedUser {
    <#
        .SYNOPSIS
            Creates a new Semi-Privileged user based on the AD Delegation Model.

        .DESCRIPTION
            This function creates a new Semi-Privileged user based on the Active Directory (AD) Delegation Model.
            It checks if the provided standard user exists, and if so, it creates a
            new Semi-Privileged user with the specified account type.

        .PARAMETER SamAccountName
            Identity of the user getting the new Admin Account (Semi-Privileged user).
            [String] Valid and existing user account name in Active Directory.

        .PARAMETER AccountType
            Must specify the account type. Valid values are T0, T1, or T2.
            [String] Enforces using ValidateSet to restrict values to T0, T1, or T2.

        .PARAMETER AdminUsersDN
            Distinguished Name of the container where the Admin Accounts are located.
            [String] Valid DN in Active Directory.

        .PARAMETER Password
            Secure String containing the password of the user. In case user does not exist, it
            will be created and this password will be used. If user already exist the password will be unchanged.

        .EXAMPLE
            $Splat = @{
                SamAccountName = 'davade'
                AccountType = 'T0'
                AdminUsersDN = 'OU=Users,OU=Admin,DC=EguibarIT,DC=local'
                Password = ConvertTo-SecureString -String 'P@ssword 123456' -AsPlainText -Force
            }
            Set-SemiPrivilegedUser @Splat

        .OUTPUTS
            [Microsoft.ActiveDirectory.Management.ADAccount]
            The function will return the Semi-Privileged user either if newly created or already existing.

        .EXAMPLE
            New-SemiPrivilegedUser -SamAccountName "davade" -AccountType "T0" -AdminUsersDN "OU=Admins,DC=domain,DC=com" -Password (ConvertTo-SecureString -String 'P@ssword 123456' -AsPlainText -Force)

    #>


    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    [OutputType([Microsoft.ActiveDirectory.Management.ADAccount])]

    param (

        [Parameter( Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Identity of the user getting the new Admin Account (Semi-Privileged user).',
            Position = 0)]
        [Alias('Name', 'ID', 'Identity')]
        [ValidateNotNullOrEmpty()]
        $SamAccountName,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Must specify the account type. Valid values are T0 or T1 or T2',
            Position = 1)]
        [ValidateSet('T0', 'T1', 'T2')]
        [string]
        $AccountType,

        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromRemainingArguments = $true,
            HelpMessage = 'Distinguished Name of the container where the Admin Accounts are located.',
            Position = 2)]
        [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,
            HelpMessage = 'Secure password for the Semi-Privileged user.',
            Position = 3)]
        [System.Security.SecureString]
        $Password
    )

    Begin {

        $newSamAccountName = '{0}_{1}' -f $SamAccountName, $AccountType.ToUpper()

        try {
            $stdUser = Get-ADUser -Identity $SamAccountName -Properties *
        } catch {
            Write-Error -Message ('Standard user {0} not found.' -f $SamAccountName)
            throw
        }

        # Check if Surename exists, else use SamAccountName
        if ($null -ne $stdUser.Surname) {
            $Surename = $stdUser.Surname.ToUpper()
        } else {
            $Surename = $stdUser.samAccountName
        } #end If-Else

        # Check if GivenName exists, else use $null
        if ($null -ne $stdUser.GivenName) {
            $GivenName = (Get-Culture).TextInfo.ToTitleCase($stdUser.GivenName.ToLower())

            If ($Surename -eq $GivenName) {
                # Built DisplayName
                $name = ('{0} ({1})' -f
                    $GivenName,
                    $PsBoundParameters['AccountType']
                )
            } else {
                # Built DisplayName
                $name = ('{0}, {1} ({2})' -f
                    $Surename,
                    $GivenName,
                    $PsBoundParameters['AccountType']
                )
            }
        } else {
            $GivenName = $null

            # No GivenName. Omit that on the name
            $name = ('{0} ({1})' -f
                $Surename.ToUpper(),
                $PsBoundParameters['AccountType']
            )
        } #end If-Else


        # HashTable with all params.
        $userParams = @{
            SamAccountName        = $newSamAccountName
            UserPrincipalName     = '{0}_{1}@{2}' -f $SamAccountName, $AccountType, $env:USERDNSDOMAIN
            Name                  = $name
            DisplayName           = $name
            Surname               = $Surename
            GivenName             = $GivenName
            Description           = '{0} Admin account' -f $AccountType
            Path                  = $AdminUsersDN
            Enabled               = $true
            TrustedForDelegation  = $false
            AccountNotDelegated   = $true
            ChangePasswordAtLogon = $false
            PasswordNeverExpires  = $false
            AccountPassword       = $Password
            EmployeeNumber        = $stdUser.SID.Value.ToString()
            OtherAttributes       = @{
                'employeeType'                  = $AccountType.ToUpper();
                'msNpAllowDialin'               = $false;
                'msDS-SupportedEncryptionTypes' = '24';
            }
            PassThru              = $true
            Verbose               = $PSBoundParameters['Verbose']
        }

        # Copy additional attributes from standard user
        $attributesToCopy = @(
            'Company', 'Country', 'Department', 'Division', 'EmailAddress', 'EmployeeId',
            'MobilePhone', 'Office', 'OfficePhone', 'Organization', 'OtherName',
            'POBox', 'PostalCode', 'State', 'StreetAddress', 'Title'
        )

        # Add all attributes to copy
        foreach ($attr in $attributesToCopy) {
            if ($stdUser.$attr) {
                $userParams[$attr] = $stdUser.$attr
            } #end If
        } #end Foreach

    } #end Begin

    Process {

        try {
            $existingUser = Get-ADUser -Identity $newSamAccountName -ErrorAction SilentlyContinue
        } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
            $existingUser = $null
        } Catch {
            Write-Error -Message 'Something went wrong when trying to check if Semi-Privileged user exists or not'
        }

        try {
            if ($existingUser) {

                # Semi-Privileged User exist. Modify it!
                if ($PSCmdlet.ShouldProcess($newSamAccountName, 'Update existing Semi-Privileged user')) {

                    Write-Verbose -Message ('
                        [PROCESS]
                            The Semi-Privileged user {0} already exists.
                            Modifying the account.'
 -f
                        $newSamAccountName
                    )

                    # As we are using Splat var for create and update,
                    # Path works on new user, but not existing. We remove Path here
                    # Name works on new user, but not existing. We remove Name here
                    # AccountPassword works on new user, but not existing. We remove AccountPassword here
                    $userParams.Remove('Path')
                    $userParams.Remove('Name')
                    $userParams.Remove('AccountPassword')
                    $userParams.Remove('OtherAttributes')

                    # OtherAttributes is equivalent to Replace. Adding Replace here
                    $userParams.Add('Replace', @{
                            'employeeType'                  = $AccountType.ToUpper();
                            'msNpAllowDialin'               = $false;
                            'msDS-SupportedEncryptionTypes' = '24';
                        }
                    )

                    $ReturnUser = Set-ADUser -Identity $newSamAccountName @userParams

                } #end If

            } else {

                # Semi-Privileged User does not exist. Create it!
                if ($PSCmdlet.ShouldProcess($newSamAccountName, 'Creating new Semi-Privileged user')) {

                    $ReturnUser = New-ADUser @userParams

                    Write-Verbose -Message ('
                        [PROCESS]
                            Created new Semi-Privileged admin account.
                            New Admin Account {0} of type {1} was created correctly.'
 -f
                        $newSamAccountName,
                        $PsBoundParameters['AccountType']
                    )

                } #end If
            } #end If-Else

        } catch {
            Write-Error -Message ('Error creating/updating semi-privileged user {0}: {1}' -f $newSamAccountName, $_)
            throw
        } #end Try-Catch

    } #end Process

    End {
        $txt = ($Variables.FooterHousekeeping -f $MyInvocation.InvocationName,
            'setting/creating Semi-Privileged account.'
        )
        Write-Verbose -Message $txt

        return $ReturnUser
    } #end End
} #end Function