How to Reset Active Directory Passwords with PowerShell
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
- Use least privilege: Delegate password reset permissions only to specific OUs
- Log all operations: Enable PowerShell transcript logging for audit trails
- Avoid hardcoded passwords: Use secure strings, encrypted files, or password managers
- Force password changes: Always set ChangePasswordAtLogon for user resets
- 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.