Last active
January 19, 2026 19:54
-
-
Save SweetAsNZ/a2850168b24533198c540173b8fd66f7 to your computer and use it in GitHub Desktop.
Gets the effective password policy for a user, including fine-grained password policies if applied. Returns user password status along with policy requirements.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Get-UsersPasswordPolicy { | |
| <# | |
| .SYNOPSIS | |
| Retrieves password policy settings for a user from Active Directory. | |
| .DESCRIPTION | |
| Gets the effective password policy for a user, including fine-grained password policies if applied. | |
| Returns user password status along with policy requirements. | |
| .PARAMETER UserName | |
| The username (SamAccountName) to query. Defaults to the current user. | |
| .EXAMPLE | |
| Get-UsersPasswordPolicy | |
| Gets password policy for the current user. | |
| .EXAMPLE | |
| Get-UsersPasswordPolicy -UserName "jsmith" | |
| Gets password policy for user jsmith. | |
| .NOTES | |
| Author: Tim West | |
| Created: 20/01/2026 | |
| Updated: 20/01/2026 | |
| Status: Production | |
| Version: 1.1.0 | |
| .CHANGELOG | |
| 2026-01-20: Fixed Get-ADUser property error - password policy properties retrieved from Get-ADUserResultantPasswordPolicy or Get-ADDefaultDomainPasswordPolicy | |
| 2026-01-20: Added PasswordPolicyName and AppliedViaGroup fields to show which policy and group grants the password policy | |
| #> | |
| [CmdletBinding()] | |
| param ( | |
| [string]$UserName = $env:USERNAME | |
| ) | |
| # Import the Active Directory module if not already imported | |
| if (-not (Get-Module -Name ActiveDirectory)) { | |
| Import-Module ActiveDirectory | |
| } | |
| # Get the user object from Active Directory with valid user properties only | |
| $user = Get-ADUser -Identity $UserName -Properties "msDS-UserPasswordExpiryTimeComputed", "PasswordLastSet", "PasswordNeverExpires", "AccountExpirationDate", "MemberOf" | |
| if (-not $user) { | |
| Write-Error "User '$UserName' not found in Active Directory." | |
| return | |
| } | |
| # Get the effective password policy for the user (handles fine-grained password policies) | |
| $policy = Get-ADUserResultantPasswordPolicy -Identity $UserName | |
| $policyName = $null | |
| $appliedViaGroup = $null | |
| # If no fine-grained password policy is applied, get the default domain policy | |
| if (-not $policy) { | |
| $policy = Get-ADDefaultDomainPasswordPolicy | |
| $policyName = "Default Domain Policy" | |
| $appliedViaGroup = "N/A (Domain Default)" | |
| } | |
| else { | |
| # Fine-grained password policy is applied | |
| $policyName = $policy.Name | |
| # Get the groups/users this policy applies to | |
| $policyObject = Get-ADFineGrainedPasswordPolicy -Identity $policy.Name -Properties AppliesTo | |
| # Check which groups the user is a member of that grant this policy | |
| $userGroups = $user.MemberOf | |
| $matchingGroups = @() | |
| foreach ($target in $policyObject.AppliesTo) { | |
| # Check if target is directly the user | |
| if ($target -eq $user.DistinguishedName) { | |
| $matchingGroups += "Directly Applied to User" | |
| break | |
| } | |
| # Check if target is a group the user is a member of | |
| if ($userGroups -contains $target) { | |
| $groupName = (Get-ADGroup -Identity $target).Name | |
| $matchingGroups += $groupName | |
| } | |
| } | |
| if ($matchingGroups.Count -gt 0) { | |
| $appliedViaGroup = $matchingGroups -join ", " | |
| } | |
| else { | |
| $appliedViaGroup = "Unknown (policy applies via nested group or direct)" | |
| } | |
| } | |
| # Create a custom object to hold the password policy information | |
| $passwordPolicy = [PSCustomObject]@{ | |
| UserName = $user.SamAccountName | |
| MinPasswordLength = $policy.MinPasswordLength | |
| PasswordExpiryDate = if ($user."msDS-UserPasswordExpiryTimeComputed" -ne 0 -and $user."msDS-UserPasswordExpiryTimeComputed" -ne 9223372036854775807) { [DateTime]::FromFileTime($user."msDS-UserPasswordExpiryTimeComputed") } else { "Never Expires" } | |
| PasswordPolicyName = $policyName | |
| AppliedViaGroup = $appliedViaGroup | |
| PasswordLastSet = $user.PasswordLastSet | |
| PasswordNeverExpires = $user.PasswordNeverExpires | |
| AccountExpirationDate = if ($user.AccountExpirationDate) { $user.AccountExpirationDate } else { "Never Expires" } | |
| PasswordHistoryLength = $policy.PasswordHistoryCount | |
| LockoutThreshold = $policy.LockoutThreshold | |
| LockoutDuration = $policy.LockoutDuration | |
| LockoutObservationWindow = $policy.LockoutObservationWindow | |
| MaxPasswordAge = $policy.MaxPasswordAge | |
| MinPasswordAge = $policy.MinPasswordAge | |
| ComplexityEnabled = $policy.ComplexityEnabled | |
| } | |
| return $passwordPolicy | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment