Using PowerShell to Disable Users in AD

Hi all,
This is my first PowerShell script that I have been trying to code for the past two days.
I have been struggling a bit. I basically wanted to take a user name then Disable it remove it from the OU and Memberships.

First I approach this problem by thinking How I would do it in a GUI then think of it in PowerShell. I did some simple test by doing many one liner command of following:
Get-ADUser -Identity TestDisableUser
$x = Get-ADUser -Identity TestDisableUser
$x # to verify the variable inside and that Name called Enabled has Property as $true before i disable it
Disable-ADAccount -Identity TestDsiableUser

After all these simple test. I decided to make it into a function with if statement and it’s mandatory to enter the User Name that is going to be disabled.

Function du{
Param(
[Parameter(Mandatory=$true)]
[String]$DEnterName
$DisableUserName = Get-Aduser -Identity $DEnterName
)

if($DisableUserName.Enabled -eq $true){
    Write-Output 'This user will be disabled'
    Disable-ADAccount -Identity $DisableUserName
    Move-ADobject -Identity $DisableUserName -Targetpath "OU=FebDeletes,OU=Users,DC=TestAD,DC=local"
    Remove-ADPrincipalGroupMembership -Identity TestUser -MemberOf "test"
    }else{
        Write-Output 'The user was already disabled, nothing was executed!'
        $DisableUserName.Enabled
}

}

I’m struggling where I can define the variable $DisableUserName before it passes through the if loop.

Thanks,

Chi

I supplied a bit more information that was asked for, but as someone that’s new to PowerShell, all of this will be useful in the long run.

  1. Since you’re newer, I wouldn’t consider trying to set the $DisabledUserName variable as part of the Param keyword. In fact, the moment I dropped your function into the ISE, it indicated there was an error (red, squiggly underline). Move it out, and no error.

  2. At minimum, you can define the $DisabledUserName variable before your If statement, as the variable’s value is needed inside this conditional statement. If you get into advanced functions, which this really is since it contains the Param keyword, you’ll discover the Begin{}, Process{}, and End{} block. I often use Begin{} to set variables that can be set at that point in the function.

  3. I’d recommend you rename your function from “du” to use an approved verb, a dash, and a singular noun. Perhaps you should use Disable-User. If you really want to use du, create an alias that you can use to invoke your function just before, or after, you define your function:

Set-Alias -Name du -Value Disable-User
Function Disable-User {
    # Function Contents.
}
  1. Get-ADUser has the potential to fail, and it doesn’t handle this well when you supply a user that’s not in the directory. Use a try-catch.
....
try {
    $DisableUserName = Get-Aduser -Identity $DEnterName
    If (...) {...
    } Else {
    ...} 
} catch {
    # Indicate the user couldn't be found. Suggestion: Use the Write-Warning cmdlet.
}

Oh, and last, commit to reading these help files: Get-Help -Name about_Functions*. You’ll find them in $PSHOME.

Tommy,

I want to thank you for going the extra length in expanding the best practice. I took your advice. I finally got my code working.
Thanks again, I can’t wait to write more code using powershell.

Hi Chi! We are here to learn and to share. Hereby, I would like to add a bit more information to your question.

First of all, like Tommy suggested, use an approved verb. To see the approved verbs, use Get-Verb.
To get you started, I’ve chosen Revoke-ADUser.

Secondly, if you are writing a function, you are actually writing a tool. And a tool should be reusable. For that reason, never put hard-coded values in your functions. In your code you’ve put for example the Organization Name hardcoded in the function. You should always parameterize your functions.

Check this example, how I would start the function:

function Revoke-ADUser {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)][string[]]$Identity,
        [Parameter(Mandatory = $true)][string]$OrganizationalUnit,
        [Parameter(Mandatory = $true)][string]$ActiveDirectoryGroup
    )

Do you notice the CmdletBinding in the code? This gives you all the goodies like verbose, debug and erroractions. This will also allows you to use Write-Verbose in your function. Never use Write-Host; this will only returns a string, and not any usable objects.

Also, the Parameter $Identity can be given more than one Identity name, because of the double square brackets: [string].
This means that you can use the function on more that one Identity at the same time. For the function to be able to process all of the Identities, the code continues like this:

    process {

Then, as Tommy also suggested, use a Try/Catch block, to catch any error messages that Get-ADUser will spit out to you, and this will be the rest of the code:

        Try {
            # Harvesting information about the AD Object.
            if ((Get-ADUser -Identity $Identity).Enabled -eq $true) {

                Write-Verbose -Message "Useraccount $Identity will be disabled."
                
                # Disabling AD Object.
                Disabled-ADAccount -Identity $Identity -Confirm $false
                Write-Verbose -Message "Disabled account $Identity." 

                # Moving AD Object to OU.
                Move-ADObject -Identity $Identity -TargetPath $OrganizationalUnit
                Write-Verbose -Message "Moved AD Object $Identity to $OrganizationalUnit." 
                
                # Removing AD Object from AD Group.
                Remove-ADPrincipalGroupMembership -Identity $Identity -MemberOf $ActiveDirectoryGroup
                Write-Verbose -Message "Removed AD Object $Identity from group $ActiveDirectoryGroup."
            }
            else {
                Write-Warning -Message "The Active Directory User $Identity was already disabled."
            }
        }
        Catch {
            Write-Error -Message $_.Exception.Message -ErrorAction Stop
            return
        }
    }
    end {
    }
}

You can see I use Write-Verbose. If you use the function, you can use -verbose as a parameter to see the verbose messages which are being put in the code.

In the end you can use the function like this:

# For one AD User:
Revoke-ADUser -Identity 'testuser' -OrganizationalUnit 'OU=FebDeletes,OU=Users,DC=TestAD,DC=local' -ActiveDirectoryGroup 'testgroup' -Verbose

# For two AD Users:
Revoke-ADUser -Identity 'testuser','testuser2' -OrganizationalUnit 'OU=FebDeletes,OU=Users,DC=TestAD,DC=local' -ActiveDirectoryGroup 'testgroup' -Verbose

To be complete, the final function looks like this:

function Revoke-ADUser {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)][string[]]$Identity,
        [Parameter(Mandatory = $true)][string]$OrganizationalUnit,
        [Parameter(Mandatory = $true)][string]$ActiveDirectoryGroup
    )

    process {

        Try {
            # Harvesting information about the AD Object.
            if ((Get-ADUser -Identity $Identity).Enabled -eq $true) {

                Write-Verbose -Message "Useraccount $Identity will be disabled."
                
                # Disabling AD Object.
                Disabled-ADAccount -Identity $Identity -Confirm $false
                Write-Verbose -Message "Disabled account $Identity." 

                # Moving AD Object to OU.
                Move-ADObject -Identity $Identity -TargetPath $OrganizationalUnit
                Write-Verbose -Message "Moved AD Object $Identity to $OrganizationalUnit." 
                
                # Removing AD Object from AD Group.
                Remove-ADPrincipalGroupMembership -Identity $Identity -MemberOf $ActiveDirectoryGroup
                Write-Verbose -Message "Removed AD Object $Identity from group $ActiveDirectoryGroup."
            }
            else {
                Write-Warning -Message "The Active Directory User $Identity was already disabled."
            }
        }
        Catch {
            Write-Error -Message $_.Exception.Message -ErrorAction Stop
            return
        }
    }
    end {
    }
}

This code is still quick-n-dirty, but it will get you started I guess.

You’re very welcome, Chi. I’m glad I was able to assist.

Hi Richard,
Thanks for going out of your way to write every extensive and detail tips and best practices.
I will keep all your advice in mind. I guess I should have be more careful on my wordings. You’re absolutely right that I was writing a function instead of a script. I originally was thinking maybe I should test it out as a function first then I’ll converted into a script I will continue experimenting all the different possibilities and ways to write a better code and all the best practices.

No problem Chi. Just try to have fun and keep discovering what PowerShell has to offer. It’s an fantastic product from Microsoft.