Test Active Directory User Accounts for a Default Password with PowerShell

How do you control password resets in your environment? I've worked for numerous companies where their forgotten password reset process was all over the board. Hopefully you have a process in place that allows you to sleep at night. Even with the best policies and procedures in place, what happens when someone on your help desk staff resets a users password to some default password and forgets to set the account so the password has to be changed at next logon? Is the user still using that default password weeks later?

I decided to write a PowerShell script to test user accounts for just that exact scenario.

  1#Requires -Version 3.0 -Modules ActiveDirectory
  2function Test-MrADUserPassword {
  3
  4<#
  5.SYNOPSIS
  6    Test-MrADUserPassword is a function for testing an Active Directory user account for a specific password.
  7
  8.DESCRIPTION
  9    Test-MrADUserPassword is an advanced function for testing one or more Active Directory user accounts for a
 10    specific password.
 11
 12.PARAMETER UserName
 13    The username for the Active Directory user account.
 14
 15.PARAMETER Password
 16    The password to test for.
 17
 18.PARAMETER ComputerName
 19    A server or computer name that has PowerShell remoting enabled.
 20
 21.PARAMETER InputObject
 22    Accepts the output of Get-ADUser.
 23
 24.EXAMPLE
 25     Test-MrADUserPassword -UserName alan0 -Password Password1 -ComputerName Server01
 26
 27.EXAMPLE
 28     'alan0'. 'andrew1', 'frank2' | Test-MrADUserPassword -Password Password1 -ComputerName Server01
 29
 30.EXAMPLE
 31     Get-ADUser -Filter * -SearchBase 'OU=AdventureWorks Users,OU=Users,OU=Test,DC=mikefrobbins,DC=com' |
 32     Test-MrPassword -Password Password1 -ComputerName Server01
 33
 34.INPUTS
 35    String, Microsoft.ActiveDirectory.Management.ADUser
 36
 37.OUTPUTS
 38    PSCustomObject
 39
 40.NOTES
 41    Author:  Mike F Robbins
 42    Website: http://mikefrobbins.com
 43    Twitter: @mikefrobbins
 44#>
 45
 46    [CmdletBinding(DefaultParameterSetName='Parameter Set UserName')]
 47    param (
 48        [Parameter(Mandatory,
 49                   ValueFromPipeline,
 50                   ValueFromPipelineByPropertyName,
 51                   ParameterSetName='Parameter Set UserName')]
 52        [Alias('SamAccountName')]
 53        [string[]]$UserName,
 54
 55        [Parameter(Mandatory)]
 56        [string]$Password,
 57
 58        [Parameter(Mandatory)]
 59        [string]$ComputerName,
 60
 61        [Parameter(ValueFromPipeline,
 62                   ParameterSetName='Parameter Set InputObject')]
 63        [Microsoft.ActiveDirectory.Management.ADUser]$InputObject
 64
 65    )
 66
 67    BEGIN {
 68        $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
 69
 70        $Params = @{
 71            ComputerName = $ComputerName
 72            ScriptBlock = {Get-Random | Out-Null}
 73            ErrorAction = 'SilentlyContinue'
 74            ErrorVariable  = 'Results'
 75        }
 76    }
 77
 78    PROCESS {
 79        if ($PSBoundParameters.UserName) {
 80            Write-Verbose -Message 'Input received via the "UserName" parameter set.'
 81            $Users = $UserName
 82        }
 83        elseif ($PSBoundParameters.InputObject) {
 84            Write-Verbose -Message 'Input received via the "InputObject" parameter set.'
 85            $Users = $InputObject
 86        }
 87
 88        foreach ($User in $Users) {
 89
 90            if (-not($Users.SamAccountName)) {
 91                Write-Verbose -Message "Querying Active Directory for UserName $($User)"
 92                $User = Get-ADUser -Identity $User
 93            }
 94
 95            $Params.Credential = (New-Object System.Management.Automation.PSCredential ($($User.UserPrincipalName), $Pass))
 96
 97            Invoke-Command @Params
 98
 99            [pscustomobject]@{
100                UserName = $User.SamAccountName
101                PasswordCorrect =
102                    switch ($Results.FullyQualifiedErrorId -replace ',.*$') {
103                        LogonFailure {$false; break}
104                        AccessDenied {$true; break}
105                        default {$true}
106                    }
107            }
108
109        }
110
111    }
112
113}

Test one or more Active Directory user accounts for a password of "Password1":

1Test-MrADUserPassword -UserName alan0, david1 -Password Password1 -ComputerName web01

test-password1a.png

Same test except using pipeline input of strings for the usernames:

1'alan0', 'david1' | Test-MrADUserPassword -Password Password1 -ComputerName web01

test-password2a.png

Test all of the user accounts in a specific OU (Organizational Unit) in Active Directory:

1Get-ADUser -Filter * -SearchBase 'OU=AdventureWorks Users,OU=Users,OU=Test,DC=mikefrobbins,DC=com' |
2Test-MrPassword -Password Password1 -ComputerName web01 |
3Sort-Object -Property PasswordCorrect

test-password3a.png

Same as the previous example except only return the accounts where the password matched.

1Get-ADUser -Filter * -SearchBase 'OU=AdventureWorks Users,OU=Users,OU=Test,DC=mikefrobbins,DC=com' |
2Test-MrPassword -Password Password1 -ComputerName web01 |
3Where-Object PasswordCorrect -eq $true

test-password4a.png

Be sure to test this and to get permission from someone in your chain of command before running it in a production environment. Be careful when using this function because it does count as a failed login for the user account if the password doesn't match. It will show up on your audit login failures report if you're performing any type of auditing for login failures. You could also end up locking out the user account if you run this enough times to meet the account lockout threshold set in your domain or in the fine grained password policies if they're enabled in your environment.

The function shown in this blog article can be downloaded from my ActiveDirectory repository on GitHub.


Update:

While at the PowerShell + DevOps Global Summit this week, I was discussing this function with a group of attendees and I discovered that there's a better way to accomplish this task. I'll post a follow-up blog article next week.

µ