Changer le mot de passe de n’importe quel compte local sans être administrateur (à condition d’en connaitre le mot de passe actuel)

par | Nov 21, 2025 | PowerShell, Script, Sécurité | 0 commentaires

Si vous avez déjà essayé de modifier le mot de passe d’un compte local Windows via la ligne de commande (cmd ou PowerShell) sans être administrateur de la machine, vous vous êtes probablement heurté à un mur : si la boite de dialogue Ctrl+Alt+Suppr > Modifier un mot de passe permet bien de modifier le mot de passe de n’importe quel compte, les commandes disponibles nativement (net user ou Set-LocalUser) ne permettent elles que de réinitialiser celui d’un autre utilisateur que soi-même; ce qui nécessite évidemment des permissions élevées (Administrateur) sur la machine.

Les cas d’usage ne sont pas courants, mais on peut par exemple rencontrer le cas où un utilisateur simple d’un poste de travail dispose d’un second compte à privilèges sur sa machine qu’il utilise pour effectuer certaines tâches avec des permissions plus importantes via une élévation ponctuelle (RunAs). Les bonnes pratiques dictent que ce compte dispose d’un mot de passe à complexité élevée et à durée de vie faible, ce qui rend son renouvellement peu pratique s’il n’est pas possible d’utiliser de copier/coller, soit exactement la situation rencontrée dans la boite de dialogue Modifier un mot de passe.

Heureusement il est bel et bien possible de modifier ce mot de passe via Powershell à l’aide de la méthode native ChangePassword() de la classe System.DirectoryServices.AccountManagement.UserPrincipal, dont je vous présente ci-après une implémentation sous forme d’une fonction Set-LocalUserPassword facile à utiliser.

Exemple 1 : Changer le mot de passe pour l’utilisateur local « Bob », sans préciser son ancien ni son nouveau mot de passe dans la commande. La fonction se chargera de vous les demander interactivement.

Set-LocalUserPassword -Identity "Bob"

Exemple 2 : Changer votre propre mot de passe, sans préciser son ancien ni son nouveau mot de passe dans la commande. Dans ce cas pas la peine d’indiquer non-plus votre nom d’utilisateur, la fonction se chargera de tout vous demander interactivement.

Set-LocalUserPassword

Exemple 3 : L’ancien et le nouveau mot de passe peuvent aussi être fournis sous forme de SecureString dans la commande à l’aide des paramètres -OldPassword et -NewPassword.

$OldPassword = "P@ssword1" | ConvertTo-SecureString -AsPlainText -Force
$NewPassword = "P@ssword2" | ConvertTo-SecureString -AsPlainText -Force
Set-LocalUserPassword -Identity "Jane" -OldPassword $OldPassword -NewPassword $NewPassword

Le script complet est dispo sous form de gist Github : Changes the password of any local user account using its current password for verification without requiring administrator permissions

Ou directement ci-dessous :

Function Set-LocalUserPassword
{
    <#
.SYNOPSIS
    Changes the password of a local user account using the current password for verification.

.DESCRIPTION
    This function utilizes the System.DirectoryServices.AccountManagement .NET namespace to change a local user's password.
    
    Unlike the standard 'Set-LocalUser' cmdlet or 'net user' command, this function utilizes the 'ChangePassword' method. 
    This allows standard (non-administrator) users to change the password of any local account, provided they know the current password in the same way as with Set-ADAccountPassword for Active Directory Accounts.

.PARAMETER Identity
    The SAMAccountName of the local user to modify. 
    If omitted, the function will prompt for the username. 
    If this prompt is left empty, it defaults to the currently logged-in user ($env:USERNAME).

.PARAMETER OldPassword
    The current valid password for the account, passed as a SecureString.
    If omitted, the function will prompt the user to enter it securely via the host UI.

.PARAMETER NewPassword
    The desired new password for the account, passed as a SecureString.
    If omitted, the function will prompt the user to enter it securely via the host UI.

.EXAMPLE
    Set-LocalUserPassword -Identity "Bob"

    Description
    -----------
    Attempts to change the password for local user "Bob". The function will interactively prompt for the Old and New passwords.

.EXAMPLE
    Set-LocalUserPassword

    Description
    -----------
    Prompts for the target username. If the user presses Enter without typing a name, it targets the current user. 
    Then prompts for the Old and New passwords.

.INPUTS
    System.String

.OUTPUTS
    None

.NOTES
    Requirements: .NET Framework 3.5 or later (System.DirectoryServices.AccountManagement)
#>
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $false, Position = 0)]
        [String]$Identity,

        [Parameter(Mandatory = $false)]
        [securestring]$OldPassword,

        [Parameter(Mandatory = $false)]
        [securestring]$NewPassword
    )

    Add-Type -AssemblyName System.DirectoryServices.AccountManagement

    try
    {
        if ([string]::IsNullOrWhiteSpace($Identity))
        {
            $Identity = Read-Host -Prompt "Enter local username (Leave empty for current user)"
            if ([string]::IsNullOrWhiteSpace($Identity))
            { 
                $Identity = $env:USERNAME 
            }
        }

        Write-Verbose "Connecting to Local Machine Context..."
        $PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new("Machine")

        Write-Verbose "Looking up user: $Identity"
        $User = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($PrincipalContext, $Identity)

        if ($null -eq $User)
        {
            throw "User '$Identity' could not be found on this computer."
        }

        if (-not $OldPassword)
        {
            $OldPassword = Read-Host -Prompt "Enter OLD password for $Identity" -AsSecureString
        }
        if (-not $NewPassword)
        {
            $NewPassword = Read-Host -Prompt "Enter NEW password for $Identity" -AsSecureString
        }

        # Convert SecureString to PlainText as this is what ChangePassword() method requires
        $OldPassPlain = [System.Net.NetworkCredential]::new("", $OldPassword).Password
        $NewPassPlain = [System.Net.NetworkCredential]::new("", $NewPassword).Password

        $User.ChangePassword($OldPassPlain, $NewPassPlain)
        
        Write-Host "Password successfully changed for user: $Identity" -ForegroundColor Green

    }
    catch
    {
        Write-Error $_.Exception.Message
        throw
    }
    finally
    {
        # Clean up unmanaged COM resources and plain text secret variables
        if ($null -ne $User) { $User.Dispose() }
        if ($null -ne $PrincipalContext) { $PrincipalContext.Dispose() }
        
        $OldPassPlain = $null
        $NewPassPlain = $null
    }
}

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *