PowerShell

How to change your own expired password when you can’t login to RDP

I must admit that it was a bit embarrassing to see my Administrator password expired when I tried to log in as Domain Admin to Domain Controller. I got this little message saying

This user account's password has expired. The password must change in order to logon. Please update the password or contact your system administrator or technical support.

Everything would be relatively OK (and admittedly less embarrassing) if I weren't the system administrator and if I wouldn't tell guys working in Service Desk and similar technical positions as myself (you know Domain Admins who remember their passwords) to remember to change their passwords on Client domain before they expire. And now I am supposed to go to them and tell them to change my password because I forgot it myself.  Well, that's not gonna happen!

Change password via RDP when NLA is disabled

If you've not enabled NLA (Network Level Authentication) on your servers/computers that you're trying to log in via RDP, there's one little trick you can do if it doesn't let you in instantly. Open up Remote Desktop Connection and instead of pressing connect use Save As, and save your connection file to a safe place.

Open up a saved RDP file which should look more or less like this:

Add this line to the end of the file

enablecredsspsupport:i:0

Now when you try to login with the saved session file, it should let you in. However, in my case that didn't work. Surely enough I always enable NLA. Bummer.

Change password using PowerShell

Fortunately, in my case, PowerShell is my friend. While it does not exactly change your expired password via RDP that you were looking for it allows you to change the expired password before you have to log in to RDP and in turn saves you from having an embarrassing moment.

function Set-PasswordRemotely {
    [CmdletBinding(DefaultParameterSetName = 'Secure')]
    param(
        [Parameter(ParameterSetName = 'Secure', Mandatory)][string] $UserName,
        [Parameter(ParameterSetName = 'Secure', Mandatory)][securestring] $OldPassword,
        [Parameter(ParameterSetName = 'Secure', Mandatory)][securestring] $NewPassword,
        [Parameter(ParameterSetName = 'Secure')][alias('DC', 'Server', 'ComputerName')][string] $DomainController
    )
    Begin {
        $DllImport = @'
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public static extern bool NetUserChangePassword(string domain, string username, string oldpassword, string newpassword);
'@
        $NetApi32 = Add-Type -MemberDefinition $DllImport -Name 'NetApi32' -Namespace 'Win32' -PassThru

        if (-not $DomainController) {
            if ($env:computername -eq $env:userdomain) {
                # not joined to domain, lets prompt for DC
                $DomainController = Read-Host -Prompt 'Domain Controller DNS name or IP Address'
            } else {
                $Domain = $Env:USERDNSDOMAIN
                $Context = [System.DirectoryServices.ActiveDirectory.DirectoryContext]::new([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain, $Domain)
                $DomainController = ([System.DirectoryServices.ActiveDirectory.DomainController]::FindOne($Context)).Name
            }
        }
    }
    Process {
        if ($DomainController -and $OldPassword -and $NewPassword -and $UserName) {
            $OldPasswordPlain = [System.Net.NetworkCredential]::new([string]::Empty, $OldPassword).Password
            $NewPasswordPlain = [System.Net.NetworkCredential]::new([string]::Empty, $NewPassword).Password

            $result = $NetApi32::NetUserChangePassword($DomainController, $UserName, $OldPasswordPlain, $NewPasswordPlain)
            if ($result) {
                Write-Host -Object "Set-PasswordRemotely - Password change for account $UserName failed on $DomainController. Please try again." -ForegroundColor Red
            } else {
                Write-Host -Object "Set-PasswordRemotely - Password change for account $UserName succeeded on $DomainController." -ForegroundColor Cyan
            }
        } else {
            Write-Warning "Set-PasswordRemotely - Password change for account failed. All parameters are required. "
        }
    }
}

This little function does magic trick of changing password remotely even if you don't have a domain-joined computer (like me). Usage is straightforward

Set-PasswordRemotely

You will be asked a series of 3 questions that you need to fill in, and your password will be changed (or not if any errors will occur in the meantime). You can also provide parameters directly not to get any prompts. If you're on a Domain joined computer, you can skip the DomainController parameter, and it will be autodetected based on the currently logged-in user. If you're planning to change passwords for different domains, please make sure to provide the Domain Controller name or IP address. Otherwise, a password change will fail.

The method above is actually based on NetUserChangePassword function. It requires TCP port 445 open (SMB) to Domain Controller. While you may be thinking that there is a simple PowerShell way to do it such as this (as suggested on Reddit)

#Edit domain, username, oldpassword, newpassword
([adsi]'WinNT://domain/username,user').ChangePassword('oldpassword','newpassword')

You should aware that it will only work on non-expired passwords. LDAP will verify password prior to change.

Quick usage with Install-Module for easy deployment

So all you need to do is save this function for later and simply use it. Alternatively, this function is added as part of my PowerShell (I have it all) Module called PSSharedGoods where you can simply do

# force switch downloads newest version including downloading any dependencies it may have
Install-Module PSSharedGoods -Force 

Set-PasswordRemotely

PSSharedGoods module actually has lots of different, sometimes weird functions that I use over and over in my modules. Feel free to explore on GitHub.

This post was last modified on December 16, 2020 11:33

Przemyslaw Klys

System Architect with over 14 years of experience in the IT field. Skilled, among others, in Active Directory, Microsoft Exchange and Office 365. Profoundly interested in PowerShell. Software geek.

Share
Published by
Przemyslaw Klys

Recent Posts

Active Directory Replication Summary to your Email or Microsoft Teams

Active Directory replication is a critical process that ensures the consistent and up-to-date state of…

2 weeks ago

Syncing Global Address List (GAL) to personal contacts and between Office 365 tenants with PowerShell

Hey there! Today, I wanted to introduce you to one of the small but excellent…

5 months ago

Active Directory Health Check using Microsoft Entra Connect Health Service

Active Directory (AD) is crucial in managing identities and resources within an organization. Ensuring its…

7 months ago

Seamless HTML Report Creation: Harness the Power of Markdown with PSWriteHTML PowerShell Module

In today's digital age, the ability to create compelling and informative HTML reports and documents…

8 months ago

How to Efficiently Remove Comments from Your PowerShell Script

As part of my daily development, I create lots of code that I subsequently comment…

8 months ago

Unlocking PowerShell Magic: Different Approach to Creating ‘Empty’ PSCustomObjects

Today I saw an article from Christian Ritter, "PowerShell: Creating an "empty" PSCustomObject" on X…

9 months ago