Audit Weak Local Passwords in Windows using PowerShell

Audit Weak Local Passwords in Windows using PowerShell

Issue: Devices not joined to Active Directory may not have Group Policies or other settings applied to enforce password complexity. For example, they may be managed by Okta, Datto RMM, and other tools but have yet to be joined to AzureAD. In this case, auditing for weak passwords on local accounts can be challenging.

Solution: Custom Bad Password.ps1 + passwordlist.txt in the same directory will produce output with the lousy password if there’s a match on the local host. It’s also configured to test for blank passwords, which would immediately drop the user at the desktop:

(Datto RMM with custom Post-Conditions)

Note: A custom rule I had in my Firewall blocking inbound TCP/445 broke the script by displaying this error:  Exception calling “Validate Credentials” with “2” arguement(s): The network path was not found. (Script location).

Unfortunately, I haven’t included a password list right now. I’d recommend starting with the classic ‘password’ ‘letmein’ ‘123456…’ and others versus loading an entire dictionary, though a large list doesn’t appear to slow the process down by much, so it’s extensible.

Script:

Function Test-UserCredential {
Param($username, $password)
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ct = [System.DirectoryServices.AccountManagement.ContextType]::Machine, $env:computername
$pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ct
$Result = $pc.ValidateCredentials($username, $password).ToString()
$Result
}

Function Get-PasswordList
{
Param(
[parameter(Mandatory=$false)]
[String]$Path

)
if($PSBoundParameters.ContainsKey('Path'))
{
$txtFileLocation = $Path

}
else
{
$Path = Join-Path $(Split-Path -Parent $PSCommandPath) -ChildPath "passwordlist.txt"
$txtFileLocation = $Path
}
$reader = [System.IO.File]::ReadLines($txtFileLocation)
$reader

}
$found = 0
$users = (Get-LocalUser | where enabled -eq $true).name
$passwordlist = Get-PasswordList #this change makes it easier to extend via file input or adding more entries to the list
foreach ($user in $users){
foreach($password in $passwordlist)
{
$result = Test-UserCredential -username $user -password $password -eq $true

if ($result -eq $true -and $password -eq "")
{
Write-Host "$user was found to have the password: blank.";$found += 1

}
elseif ($result -eq $true)
{
Write-Host "$user was found to have the password: $password.";$found += 1
}

}
}

if ($found -eq 0){write-host "No user accounts with weak passwords."}
if ($found -eq 1){write-Host "$found account found with weak password."}
if ($found -gt 1){Write-Host "$found accounts found with weak passwords."}

Leave a Reply

Your email address will not be published. Required fields are marked *