Thursday, April 10, 2025

function Get-PasswordLastSet

 function Get-PasswordLastSet {

<#

.SYNOPSIS

    Retrieves the date and time a user's password was last set.


.DESCRIPTION

    This function queries Active Directory (if available) or the local Security Account Manager (SAM)

    to determine the last time a specified user's password was changed.


.PARAMETER UserName

    The username of the account to query.


.EXAMPLE

    Get-PasswordLastSet -UserName "john.doe"


    Displays the last password set date and time for the user "john.doe".


.EXAMPLE

    Get-PasswordLastSet -UserName "administrator"


    Displays the last password set date and time for the local Administrator account.

#>

    [CmdletBinding()]

    param(

        [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]

        [Alias("SamAccountName")]

        [string]$UserName

    )


    process {

        try {

            # Attempt to query Active Directory

            $user = Get-ADUser -Identity $UserName -Properties pwdLastSet -ErrorAction Stop

            if ($user.pwdLastSet -gt 0) {

                $lastSet = [DateTime]::FromFileTime($user.pwdLastSet)

                Write-Output "Password for user '$($user.SamAccountName)' was last set on: $($lastSet)"

            } else {

                Write-Warning "Password for user '$($user.SamAccountName)' has never been set or the value is unavailable in Active Directory."

            }

        }

        catch {

            # If Active Directory is not available or the user is not found there,

            # attempt to query the local SAM

            try {

                $user = Get-LocalUser -Name $UserName -ErrorAction Stop

                $sid = (Get-WmiObject -Class Win32_UserAccount -Filter "Name='$($user.Name)'").SID

                $securityDescriptor = Get-Acl -Path "Registry::HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\$($sid)" -ErrorAction Stop

                $passwordLastSetRaw = ($securityDescriptor.Sacl | Where-Object {$_.SecurityIdentifier -like "S-1-5-*" -and $_.ObjectAceType -eq "System Mandatory Label"}).ObjectSpecificAce.Ace.SubAuthority[0]

                if ($passwordLastSetRaw -gt 0) {

                    $epochStart = [datetime]"01/01/1601"

                    $timeSpan = [TimeSpan]::FromTicks($passwordLastSetRaw * 100)

                    $lastSet = $epochStart + $timeSpan

                    Write-Output "Password for local user '$($user.Name)' was last set on: $($lastSet)"

                } else {

                    Write-Warning "Could not determine the last password set time for local user '$($user.Name)'."

                }

            }

            catch {

                Write-Error "User '$($UserName)' not found on the local machine."

            }

        }

    }

}


# Example usage:

# To find the last password set time for a specific user in Active Directory:

# Get-PasswordLastSet -UserName "domain\username"


# To find the last password set time for a local user:

# Get-PasswordLastSet -UserName "localusername"


# You can also pipe usernames to the function:

# "user1", "user2", "anotheruser" | Get-PasswordLastSet

No comments:

Post a Comment

PAM maturity