How can a standard Windows user change their password from the command line?

Solution 1:

Here's some PowerShell code to do what you're looking for with domain accounts:

param (
    [string]$oldPassword = $( Read-Host "Old password"),
    [string]$newPassword = $( Read-Host "New password")
)

$ADSystemInfo = New-Object -ComObject ADSystemInfo
$type = $ADSystemInfo.GetType()
$user = [ADSI] "LDAP://$($type.InvokeMember('UserName', 'GetProperty', $null, $ADSystemInfo, $null))"
$user.ChangePassword( $oldPassword, $newPassword)

The ASDI provider also supports the syntax WinNT://computername/username for the ChangePassword() method. The ADSystemInfo object, however, won't work for machine-local accounts, so just retrofitting the code above with WinNT://... syntax isn't workable.

(Anybody want to suggest an edit w/ code to differentiate between local and domain accounts?)

On a completely different tack, the old NetUserChangePassword API will work with local (and domain, provided you specify the domain name in NetBIOS syntax) accounts, too:

param (
    [string]$oldPassword = $( Read-Host "Old password"),
    [string]$newPassword = $( Read-Host "New password")
)

$MethodDefinition = @'
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public static extern bool NetUserChangePassword(string domainname, string username, string oldPassword, string newPassword);
'@

$NetAPI32 = Add-Type -MemberDefinition $MethodDefinition -Name 'NetAPI32' -Namespace 'Win32' -PassThru

$NetAPI32::NetUserChangePassword('.', $env:username, $oldPassword, $newPassword)

This code assumes you're changing a password on the local machine (".").

Solution 2:

This is actually pretty simple in PowerShell:

([ADSI]'LDAP://CN=User,CN=Users,DC=domain').ChangePassword('currentpassword','newpassword')

Solution 3:

I tried both of the answers above to no avail, for changing the password of a local admin that is not domain-joined. Digging through the comments yielded what I needed though.

For the second part of the currently accepted answer, you want to update the signature to use long instead of bool return value, and these can be troubleshooted over at the system error codes docs. So you end up with:

param (
    [string]$oldPassword = $( Read-Host "Old password"),
    [string]$newPassword = $( Read-Host "New password")
)

$MethodDefinition = @'
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public static extern **long** NetUserChangePassword(string domainname, string username, string oldPassword, string newPassword);
'@

$NetAPI32 = Add-Type -MemberDefinition $MethodDefinition -Name 'NetAPI32' -Namespace 'Win32' -PassThru

$NetAPI32::NetUserChangePassword('.', $env:username, $oldPassword, $newPassword)

However, that did not work for me. The error codes alternated between 86 and 2221, depending on how I set up the parameters. Was about to give up and dug more into the comments, and finally found success in doing:

([ADSI]'WinNT://./USERNAME').ChangePassword("OLDPASS‌​", "NEWPASS")

Absolutely ridiculous that simple CHANGING of a local admin password is so complicated in Powershell. If you store securestrings at all on your system, then updating the password must be done with supplying the old password, or risk losing ability to properly decrypt those secure strings!