ActiveDirectory/Get-ADPasswordPolicy.ps1
|
function Get-ADPasswordPolicy { <# .SYNOPSIS Retrieves and analyzes Active Directory password policies .DESCRIPTION Gets domain default password policy and fine-grained password policies (PSOs) with security analysis and recommendations .PARAMETER Domain Target domain .PARAMETER IncludeFineGrained Include Fine-Grained Password Policies (PSOs) .EXAMPLE Get-ADPasswordPolicy Get-ADPasswordPolicy -IncludeFineGrained -Domain "contoso.com" .OUTPUTS PSCustomObject with password policy information #> [CmdletBinding()] param( [Parameter()] [string]$Domain, [Parameter()] [switch]$IncludeFineGrained ) begin { Write-Host "=== AD PASSWORD POLICY ANALYSIS ===" -ForegroundColor Cyan if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { throw "ActiveDirectory module required" } Import-Module ActiveDirectory -ErrorAction Stop if (-not $Domain) { $Domain = (Get-ADDomain).DNSRoot } Write-Host "Domain: $Domain" -ForegroundColor Yellow $analysis = [PSCustomObject]@{ AnalysisDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Domain = $Domain DefaultPolicy = @{} FineGrainedPolicies = @() SecurityScore = 0 MaxScore = 100 Findings = @() Recommendations = @() } } process { try { # 1. Get Default Domain Password Policy Write-Host "`nAnalyzing Default Password Policy..." -ForegroundColor Cyan $policy = Get-ADDefaultDomainPasswordPolicy -Server $Domain $score = 0 # Complexity (20 points) if ($policy.ComplexityEnabled) { $score += 20 Write-Host " + Complexity Enabled: Yes" -ForegroundColor Green } else { Write-Host " - Complexity Enabled: No" -ForegroundColor Red $analysis.Findings += [PSCustomObject]@{ Severity = 'Critical' Finding = 'Password complexity is disabled' Impact = 'Weak passwords can be set' } } # Min Length (25 points) Write-Host " Min Password Length: $($policy.MinPasswordLength)" -ForegroundColor $( if ($policy.MinPasswordLength -ge 14) { 'Green' } elseif ($policy.MinPasswordLength -ge 12) { 'Yellow' } else { 'Red' } ) if ($policy.MinPasswordLength -ge 14) { $score += 25 } elseif ($policy.MinPasswordLength -ge 12) { $score += 20 $analysis.Findings += [PSCustomObject]@{ Severity = 'Medium' Finding = "Minimum password length is $($policy.MinPasswordLength) (recommended: 14+)" Impact = 'Increased vulnerability to brute force' } } elseif ($policy.MinPasswordLength -ge 8) { $score += 10 $analysis.Findings += [PSCustomObject]@{ Severity = 'High' Finding = "Minimum password length is only $($policy.MinPasswordLength)" Impact = 'Significant vulnerability to brute force' } } else { $analysis.Findings += [PSCustomObject]@{ Severity = 'Critical' Finding = "Minimum password length is critically low ($($policy.MinPasswordLength))" Impact = 'Extremely vulnerable to brute force' } } # Password History (10 points) Write-Host " Password History: $($policy.PasswordHistoryCount)" -ForegroundColor $( if ($policy.PasswordHistoryCount -ge 24) { 'Green' } elseif ($policy.PasswordHistoryCount -ge 12) { 'Yellow' } else { 'Red' } ) if ($policy.PasswordHistoryCount -ge 24) { $score += 10 } elseif ($policy.PasswordHistoryCount -ge 12) { $score += 7 $analysis.Findings += [PSCustomObject]@{ Severity = 'Low' Finding = "Password history count is $($policy.PasswordHistoryCount) (recommended: 24)" Impact = 'Users can reuse passwords more frequently' } } else { $score += 3 $analysis.Findings += [PSCustomObject]@{ Severity = 'Medium' Finding = "Password history count is only $($policy.PasswordHistoryCount)" Impact = 'Password reuse is not adequately prevented' } } # Max Password Age (15 points) Write-Host " Max Password Age: $($policy.MaxPasswordAge.Days) days" -ForegroundColor $( if ($policy.MaxPasswordAge.Days -le 90 -and $policy.MaxPasswordAge.Days -gt 0) { 'Green' } elseif ($policy.MaxPasswordAge.Days -le 180) { 'Yellow' } else { 'Red' } ) if ($policy.MaxPasswordAge.Days -le 90 -and $policy.MaxPasswordAge.Days -gt 0) { $score += 15 } elseif ($policy.MaxPasswordAge.Days -le 180) { $score += 10 } else { $analysis.Findings += [PSCustomObject]@{ Severity = 'Medium' Finding = "Password max age is $($policy.MaxPasswordAge.Days) days" Impact = 'Passwords not rotated frequently enough' } } # Lockout Policy (20 points) if ($policy.LockoutThreshold -gt 0) { Write-Host " Lockout Threshold: $($policy.LockoutThreshold) attempts" -ForegroundColor $( if ($policy.LockoutThreshold -le 5) { 'Green' } else { 'Yellow' } ) if ($policy.LockoutThreshold -le 5) { $score += 15 } else { $score += 10 $analysis.Findings += [PSCustomObject]@{ Severity = 'Low' Finding = "Lockout threshold is $($policy.LockoutThreshold) (recommended: 5 or less)" Impact = 'More attempts allowed for password guessing' } } Write-Host " Lockout Duration: $($policy.LockoutDuration.TotalMinutes) minutes" -ForegroundColor Green if ($policy.LockoutDuration.TotalMinutes -ge 15) { $score += 5 } } else { Write-Host " - Lockout Policy: Disabled" -ForegroundColor Red $analysis.Findings += [PSCustomObject]@{ Severity = 'High' Finding = 'Account lockout policy is disabled' Impact = 'No protection against brute force attacks' } } # Reversible Encryption (10 points) if ($policy.ReversibleEncryptionEnabled -eq $false) { $score += 10 Write-Host " + Reversible Encryption: Disabled" -ForegroundColor Green } else { Write-Host " - Reversible Encryption: Enabled" -ForegroundColor Red $analysis.Findings += [PSCustomObject]@{ Severity = 'Critical' Finding = 'Reversible encryption is enabled' Impact = 'Passwords stored in plaintext-equivalent form' } } $analysis.SecurityScore = $score $analysis.DefaultPolicy = [PSCustomObject]@{ ComplexityEnabled = $policy.ComplexityEnabled MinPasswordLength = $policy.MinPasswordLength PasswordHistoryCount = $policy.PasswordHistoryCount MaxPasswordAge = $policy.MaxPasswordAge.Days MinPasswordAge = $policy.MinPasswordAge.Days LockoutThreshold = $policy.LockoutThreshold LockoutDuration = $policy.LockoutDuration.TotalMinutes LockoutObservationWindow = $policy.LockoutObservationWindow.TotalMinutes ReversibleEncryptionEnabled = $policy.ReversibleEncryptionEnabled DistinguishedName = $policy.DistinguishedName } # 2. Get Fine-Grained Password Policies if ($IncludeFineGrained) { Write-Host "`nAnalyzing Fine-Grained Password Policies (PSOs)..." -ForegroundColor Cyan try { $psos = Get-ADFineGrainedPasswordPolicy -Filter * -Server $Domain if ($psos) { Write-Host " Found $($psos.Count) Fine-Grained Password Policies" -ForegroundColor Yellow foreach ($pso in $psos) { $appliesTo = @(Get-ADFineGrainedPasswordPolicySubject -Identity $pso -Server $Domain) $psoInfo = [PSCustomObject]@{ Name = $pso.Name Precedence = $pso.Precedence ComplexityEnabled = $pso.ComplexityEnabled MinPasswordLength = $pso.MinPasswordLength PasswordHistoryCount = $pso.PasswordHistoryCount MaxPasswordAge = $pso.MaxPasswordAge.Days LockoutThreshold = $pso.LockoutThreshold AppliesTo = $appliesTo.Count AppliesToObjects = if ($appliesTo.Count -gt 0) { $appliesTo.Name -join ', ' } else { 'None' } } $analysis.FineGrainedPolicies += $psoInfo Write-Host "`n PSO: $($pso.Name)" -ForegroundColor White Write-Host " Precedence: $($pso.Precedence)" -ForegroundColor Gray Write-Host " Min Length: $($pso.MinPasswordLength)" -ForegroundColor Gray Write-Host " Applies To: $($appliesTo.Count) objects" -ForegroundColor Gray } } else { Write-Host " No Fine-Grained Password Policies configured" -ForegroundColor Gray } } catch { Write-Warning "Could not retrieve Fine-Grained Password Policies: $_" } } # Generate recommendations if ($policy.MinPasswordLength -lt 14) { $analysis.Recommendations += "Increase minimum password length to 14+ characters" } if (-not $policy.ComplexityEnabled) { $analysis.Recommendations += "Enable password complexity requirements immediately" } if ($policy.LockoutThreshold -eq 0) { $analysis.Recommendations += "Enable account lockout policy (5 attempts recommended)" } if ($policy.PasswordHistoryCount -lt 24) { $analysis.Recommendations += "Increase password history to 24 remembered passwords" } if ($policy.ReversibleEncryptionEnabled) { $analysis.Recommendations += "Disable reversible encryption immediately" } $analysis.Recommendations += "Consider implementing Fine-Grained Password Policies for privileged accounts" $analysis.Recommendations += "Regular password policy audits (quarterly)" } catch { Write-Error "Error analyzing password policies: $_" throw } } end { Write-Host "`n=== ANALYSIS COMPLETE ===" -ForegroundColor Green Write-Host "`nPassword Policy Security Score: $($analysis.SecurityScore)/100" -ForegroundColor $( if ($analysis.SecurityScore -ge 80) { 'Green' } elseif ($analysis.SecurityScore -ge 60) { 'Yellow' } else { 'Red' } ) if ($analysis.Findings.Count -gt 0) { Write-Host "`nFindings: $($analysis.Findings.Count)" -ForegroundColor Yellow $analysis.Findings | Group-Object Severity | ForEach-Object { Write-Host " $($_.Name): $($_.Count)" -ForegroundColor $( switch ($_.Name) { 'Critical' { 'Red' } 'High' { 'Red' } 'Medium' { 'Yellow' } default { 'White' } } ) } } if ($analysis.Recommendations.Count -gt 0) { Write-Host "`nRecommendations:" -ForegroundColor Cyan $analysis.Recommendations | ForEach-Object { Write-Host " ! $_" -ForegroundColor Yellow } } return $analysis } } |