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!
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.
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.
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.