Public/Authentication/Test-LocalPasswordComplexity.ps1
|
function Test-LocalPasswordComplexity { <# .SYNOPSIS Tests a password against the local password policy for complexity requirements. .DESCRIPTION Validates whether a given password meets the local system's password policy requirements, including minimum length and character complexity. The function checks for the presence of lowercase letters, uppercase letters, digits, and special characters. Returns detailed information about compliance and which requirements are met. .PARAMETER Password The password to test, provided as a SecureString for security. Accepts pipeline input. .PARAMETER RequiredCategories The number of character categories (lowercase, uppercase, digit, special) required for complexity compliance. Valid range is 1-4. Default is 3. Only enforced if the local password complexity policy is enabled. .EXAMPLE $securePassword = ConvertTo-SecureString 'MyP@ssw0rd!' -AsPlainText -Force Test-LocalPasswordComplexity -Password $securePassword Tests if the password 'MyP@ssw0rd!' meets the local password policy requirements. .EXAMPLE ConvertTo-SecureString 'weakpass' -AsPlainText -Force | Test-LocalPasswordComplexity Tests a weak password using pipeline input and returns compliance details. .EXAMPLE $securePassword = ConvertTo-SecureString 'Abc123!@#' -AsPlainText -Force Test-LocalPasswordComplexity -Password $securePassword -RequiredCategories 4 Tests if the password meets all 4 character category requirements. .OUTPUTS PSCustomObject with the following properties: - IsCompliant: Overall compliance status (bool) - Scope: Always 'Local' for this function - MinPasswordLength: Minimum length required by policy - ComplexityEnabled: Whether complexity is enabled in policy (bool) - RequiredCategories: Number of categories required - CategoryCount: Actual number of categories present in password - Length: Actual password length - LengthOk: Whether length requirement is met (bool) - ComplexityOk: Whether complexity requirement is met (bool) .NOTES The function uses Unicode character classes for robust pattern matching: - \p{Ll}: Lowercase letters - \p{Lu}: Uppercase letters - \p{Nd}: Decimal digits - [^\p{L}\p{Nd}]: Any character that is not a letter or digit (special characters) #> [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)] [SecureString] $Password, [ValidateRange(1,4)] [int] $RequiredCategories = 3 ) # Retrieve the current local password policy settings $policy = Get-LocalPasswordPolicy # Convert SecureString to plain text for analysis # Note: This is necessary for validation but we clear it in the finally block $plain = (New-Object PSCredential 'x', $Password).GetNetworkCredential().Password try { # Check if password meets minimum length requirement # If no minimum length is set in policy, consider it always valid $lenOk = if ($policy.MinimumPasswordLength -ne $null) { $plain.Length -ge $policy.MinimumPasswordLength } else { $true } # Check for presence of each character category using Unicode character classes # \p{Ll} = Unicode lowercase letters $hasLower = $plain -cmatch '\p{Ll}' # \p{Lu} = Unicode uppercase letters $hasUpper = $plain -cmatch '\p{Lu}' # \p{Nd} = Unicode decimal digits (0-9) $hasDigit = $plain -cmatch '\p{Nd}' # [^\p{L}\p{Nd}] = Any character that is NOT a letter or digit (special characters) $hasSpecial = $plain -cmatch '[^\p{L}\p{Nd}]' # Count how many character categories are present in the password $categoryCount = @($hasLower,$hasUpper,$hasDigit,$hasSpecial | Where-Object { $_ }).Count # Check if complexity requirement is met # If complexity is enabled in policy, verify the password has enough categories # If complexity is not enabled, automatically pass this check $complexityOk = if ($policy.PasswordComplexity) { $categoryCount -ge $RequiredCategories } else { $true } # Return detailed compliance information [pscustomobject]@{ IsCompliant = $lenOk -and $complexityOk Scope = 'Local' MinPasswordLength = $policy.MinimumPasswordLength ComplexityEnabled = $policy.PasswordComplexity RequiredCategories = if ($policy.PasswordComplexity) { $RequiredCategories } else { 0 } CategoryCount = $categoryCount Length = $plain.Length LengthOk = $lenOk ComplexityOk = $complexityOk } } finally { # Security: Clear the plain text password from memory $plain = $null } } |