Managing user passwords is one of the most common tasks for Windows administrators. PowerShell provides a powerful and scriptable way to reset Active Directory passwords, unlock accounts, and automate password management at scale.

This guide covers everything from basic password resets to advanced automation with CSV imports and scheduled tasks.

Prerequisites

Before you can manage Active Directory with PowerShell, ensure you have:

  • RSAT tools installed: Remote Server Administration Tools for Windows
  • Active Directory module: The Active Directory PowerShell module
  • Appropriate permissions: Delegate rights to reset passwords on target OUs

Install RSAT and AD Module

# Windows 10/11 - Install RSAT via Optional Features
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0

# Or via PowerShell Gallery (older method)
Install-Module -Name ActiveDirectory -Force

# Verify the module is available
Get-Module -ListAvailable ActiveDirectory

Connect to Active Directory

# Import the module
Import-Module ActiveDirectory

# Verify connection
Get-ADDomainController -Discover

Basic Password Reset

The simplest way to reset a password is using Set-ADAccountPassword:

# Reset password for a single user
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "NewP@ssw0rd123!" -Force)

# The -Reset switch clears the old password requirement
# The user must change password at next logon by default

Key Parameters Explained

Parameter Description
-Identity Username, DN, SID, or GUID of the account
-Reset Allows reset without knowing the old password
-NewPassword SecureString containing the new password
-OldPassword Required without -Reset (user's current password)

Safer Password Handling

Avoid hardcoding passwords in scripts. Use one of these methods instead:

# Method 1: Prompt for password
$password = Read-Host -AsSecureString "Enter new password"
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword $password

# Method 2: Generate random password
$randomPassword = (-join ((65..90) + (97..122) + (48..57) | Get-Random -Count 16 | ForEach-Object {[char]$_})) + "!@#"
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText $randomPassword -Force)

# Method 3: Use Get-Credential
$credential = Get-Credential -UserName "jsmith" -Message "Enter new password for user"
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword $credential.Password

Reset Password and Force Change at Logon

By default, after a password reset, the user must change their password at next logon. You can control this behavior:

# Reset password AND force change at next logon
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "TempP@ss123!" -Force)
Set-ADUser -Identity "jsmith" -ChangePasswordAtLogon $true

# Reset password but DO NOT force change
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "KnownP@ss456!" -Force)
Set-ADUser -Identity "jsmith" -ChangePasswordAtLogon $false

Unlock Locked Accounts

Often password resets are needed because accounts get locked. Here's how to unlock:

# Check if account is locked
Get-ADUser -Identity "jsmith" -Properties LockedOut, lockoutTime

# Unlock the account
Unlock-ADAccount -Identity "jsmith"

# Combined: Reset password and unlock account
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "NewP@ss789!" -Force)
Unlock-ADAccount -Identity "jsmith"

Find All Locked Accounts

# Find all locked accounts in domain
Search-ADAccount -LockedOut | Select-Object Name, SamAccountName, LastLogonDate

# Find locked accounts in specific OU
Search-ADAccount -LockedOut -SearchBase "OU=Users,DC=company,DC=com" | Select-Object Name, SamAccountName

# Unlock all locked accounts (use with caution!)
Search-ADAccount -LockedOut | Unlock-ADAccount

Bulk Password Resets

Reset Multiple Users from CSV

Create a CSV file with user accounts:

# CSV format (users.csv)
# SamAccountName,NewPassword
# jsmith,TempP@ss1!
# mjones,TempP@ss2!
# awilliams,TempP@ss3!

# Import and reset passwords
$users = Import-Csv -Path "C:\Scripts\users.csv"
foreach ($user in $users) {
    $secPassword = ConvertTo-SecureString -AsPlainText $user.NewPassword -Force
    Set-ADAccountPassword -Identity $user.SamAccountName -Reset -NewPassword $secPassword
    Write-Host "Reset password for $($user.SamAccountName)" -ForegroundColor Green
}

Reset Passwords for All Users in an OU

# Get all users in an OU and reset passwords
$users = Get-ADUser -Filter * -SearchBase "OU=Interns,DC=company,DC=com"
$defaultPassword = ConvertTo-SecureString -AsPlainText "Welcome@2026!" -Force

foreach ($user in $users) {
    Set-ADAccountPassword -Identity $user.SamAccountName -Reset -NewPassword $defaultPassword
    Set-ADUser -Identity $user.SamAccountName -ChangePasswordAtLogon $true
    Write-Host "Reset password for $($user.Name)" -ForegroundColor Cyan
}

Reset Expired Passwords for Multiple Users

# Find users with expired passwords
$expiredUsers = Get-ADUser -Filter {PasswordExpired -eq $true} -Properties PasswordExpired, PasswordLastSet

foreach ($user in $expiredUsers) {
    $tempPassword = "Temp" + (Get-Random -Minimum 1000 -Maximum 9999) + "!"
    $secPassword = ConvertTo-SecureString -AsPlainText $tempPassword -Force
    
    Set-ADAccountPassword -Identity $user.SamAccountName -Reset -NewPassword $secPassword
    Unlock-ADAccount -Identity $user.SamAccountName
    
    Write-Host "Reset password for $($user.Name) to: $tempPassword"
}

# Export results to CSV for distribution
$results | Export-Csv -Path "C:\Scripts\password_resets.csv" -NoTypeInformation

Set Password to Never Expire

For service accounts or specific scenarios, you may need to set passwords to never expire:

# Set single user password to never expire
Set-ADUser -Identity "svc_backup" -PasswordNeverExpires $true

# Verify the setting
Get-ADUser -Identity "svc_backup" -Properties PasswordNeverExpires | Select-Object Name, PasswordNeverExpires

# Set password to never expire AND prevent user from changing it (service account pattern)
Set-ADUser -Identity "svc_backup" -PasswordNeverExpires $true -CannotChangePassword $true

# Find all users with passwords set to never expire
Get-ADUser -Filter {PasswordNeverExpires -eq $true} -Properties PasswordNeverExpires | Select-Object Name, SamAccountName

Automated Password Reset Script

Here's a complete production-ready script for password management:

#Requires -Module ActiveDirectory
#Requires -RunAsAdministrator

param(
    [Parameter(Mandatory=$false)]
    [string]$CSVPath,
    
    [Parameter(Mandatory=$false)]
    [string]$OutputPath = "C:\Scripts\PasswordReset_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv",
    
    [Parameter(Mandatory=$false)]
    [switch]$GenerateRandomPasswords,
    
    [Parameter(Mandatory=$false)]
    [int]$PasswordLength = 12
)

function New-RandomPassword {
    param([int]$Length = 12)
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*'
    $password = -join ((1..$Length) | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })
    return $password
}

$results = @()

try {
    if ($CSVPath) {
        $users = Import-Csv -Path $CSVPath
        
        foreach ($user in $users) {
            $password = if ($user.NewPassword) { 
                $user.NewPassword 
            } elseif ($GenerateRandomPasswords) { 
                New-RandomPassword -Length $PasswordLength 
            } else {
                Read-Host "Enter password for $($user.SamAccountName)"
            }
            
            $secPassword = ConvertTo-SecureString -AsPlainText $password -Force
            
            try {
                Set-ADAccountPassword -Identity $user.SamAccountName -Reset -NewPassword $secPassword -ErrorAction Stop
                Unlock-ADAccount -Identity $user.SamAccountName -ErrorAction SilentlyContinue
                
                if ($user.ForceChange -ne 'false') {
                    Set-ADUser -Identity $user.SamAccountName -ChangePasswordAtLogon $true
                }
                
                $results += [PSCustomObject]@{
                    SamAccountName = $user.SamAccountName
                    Status = 'Success'
                    Password = $password
                    Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
                }
            }
            catch {
                $results += [PSCustomObject]@{
                    SamAccountName = $user.SamAccountName
                    Status = "Failed: $($_.Exception.Message)"
                    Password = $password
                    Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
                }
            }
        }
        
        $results | Export-Csv -Path $OutputPath -NoTypeInformation
        Write-Host "Results exported to: $OutputPath" -ForegroundColor Green
    }
}
catch {
    Write-Error "Script failed: $($_.Exception.Message)"
}

Running the Script

# Run with CSV input
.\Reset-ADPasswords.ps1 -CSVPath "C:\Scripts\users.csv"

# Run with random password generation
.\Reset-ADPasswords.ps1 -CSVPath "C:\Scripts\users.csv" -GenerateRandomPasswords -PasswordLength 16

# Schedule as a task (run weekly)
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\Reset-ADPasswords.ps1 -CSVPath C:\Scripts\weekly_resets.csv -GenerateRandomPasswords"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 2am
Register-ScheduledTask -TaskName "Weekly Password Resets" -Action $action -Trigger $trigger -RunLevel Highest

Troubleshooting Common Issues

Access Denied Errors

# Check if you have permissions
whoami /priv | findstr "SeEnableDelegationPrivilege"

# Run PowerShell as Administrator
# Ensure your account has "Reset Password" permission on the target OU
# In ADUC: Right-click OU > Properties > Security > Advanced > Add > Reset Password

Password Policy Violations

# Check domain password policy
Get-ADDefaultDomainPasswordPolicy | Select-Object MinPasswordLength, PasswordComplexityEnabled, MaxPasswordAge

# Check fine-grained password policies (if applicable)
Get-ADUserResultantPasswordPolicy -Identity "jsmith"

# Generate compliant passwords
function New-CompliantPassword {
    $upper = -join ((65..90) | Get-Random -Count 2 | ForEach-Object {[char]$_})
    $lower = -join ((97..122) | Get-Random -Count 4 | ForEach-Object {[char]$_})
    $digits = -join ((48..57) | Get-Random -Count 2 | ForEach-Object {[char]$_})
    $special = -join @(33,35,36,37,38,42) | Get-Random -Count 2 | ForEach-Object {[char]$_}
    return -join ($upper + $lower + $digits + $special | Get-Random -Count 10)
}

Account Lockout After Reset

# User might have cached credentials or existing sessions
# Clear cached credentials:

# Force Kerberos ticket purge
Invoke-Command -ComputerName "workstation01" -ScriptBlock {
    klist purge
}

# Check for locked sessions
Get-ADUser -Identity "jsmith" -Properties badPwdCount, lockoutTime

# Check which DC handled the lockout
Get-ADDomainController -Filter * | ForEach-Object {
    Get-ADUser -Identity "jsmith" -Server $_.Name -Properties badPwdCount -ErrorAction SilentlyContinue
} | Select-Object Name, badPwdCount

Connection Issues

# Specify a domain controller
Set-ADAccountPassword -Identity "jsmith" -Server "dc01.company.com" -Reset -NewPassword $password

# Use specific credentials
$password = Read-Host -AsSecureString "Enter admin password"
$credential = New-Object System.Management.Automation.PSCredential ("company\adminuser", $password)
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword $newPassword -Credential $credential

Audit and Compliance

View Password Reset History

# Get password reset events from Security log (Event ID 4724)
Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4724} -MaxEvents 50 | 
    Select-Object TimeCreated, Message | Format-Table -AutoSize

# Check when passwords were last set
Get-ADUser -Filter * -Properties PasswordLastSet, PasswordNeverExpires | 
    Select-Object Name, SamAccountName, PasswordLastSet, PasswordNeverExpires | 
    Sort-Object PasswordLastSet -Descending | 
    Format-Table -AutoSize

Export Audit Report

# Export password audit report
$report = Get-ADUser -Filter * -Properties PasswordLastSet, PasswordNeverExpires, PasswordExpired | 
    Select-Object Name, SamAccountName, PasswordLastSet, PasswordNeverExpires, PasswordExpired, @{N='DaysSinceLastSet';E={(New-TimeSpan -Start $_.PasswordLastSet -End (Get-Date)).Days}}

$report | Export-Csv -Path "C:\Scripts\PasswordAudit_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

Security Best Practices

  1. Use least privilege: Delegate password reset permissions only to specific OUs
  2. Log all operations: Enable PowerShell transcript logging for audit trails
  3. Avoid hardcoded passwords: Use secure strings, encrypted files, or password managers
  4. Force password changes: Always set ChangePasswordAtLogon for user resets
  5. Use MFA for admin accounts: Protect privileged accounts with additional factors
# Start transcript for audit logging
Start-Transcript -Path "C:\Logs\PasswordReset_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"

# Your password reset commands here
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword $password

# Stop transcript
Stop-Transcript

Next Steps

  • Implement self-service password reset via Microsoft Entra ID
  • Set up password expiration notifications via email
  • Create scheduled reports for password audits
  • Integrate with IT service management tools for automated workflows

PowerShell gives you complete control over Active Directory password management. Automate repetitive tasks while maintaining security and audit compliance.