powershell max authent policies V2
# ============================================================================
# NetScaler Authentication Policy Analyzer - ENHANCED v2.4
# ============================================================================
# Analyse spécialisée pour les objets AAA - Application Traffic
#
# NOUVEAUTÉS v2.4:
# - Séparation des objets non utilisés en deux catégories claires
# - Section COMMANDES DE SUPPRESSION pour copier-coller facilement
# - Affichage des lignes de configuration comme preuve
# - Meilleure visibilité pour le nettoyage
#
# IMPORTANT: Chain of authentication:
# Actions (define HOW) -> Policies (define WHEN) -> Bindings (define WHERE)
# Example: LDAP_Action -> Auth_Policy -> bound to AAA_vServer
#
# === OBJETS ANALYSÉS (dans l'ordre du flux) ===
# Niveau 1 - Point d'entrée:
# 1. Authentication Profiles → Attachés aux VPN/LB vServers
#
# Niveau 2 - Serveur d'authentification:
# 2. Authentication vServers → Référencés dans les profiles
#
# Niveau 3 - Configuration:
# 3. Authentication Login Schemas → Bindés aux vServers
# 4. Authentication Policies → Bindées aux vServers ou globalement
# 5. Authentication Policy Labels → Utilisés comme nextFactor
#
# Niveau 4 - Actions (endpoints):
# 6. LDAP Actions → Définissent comment authentifier
# 7. OAUTH Actions → Définissent l'auth OAuth
# 8. SAML Actions → Définissent l'auth SAML
# 9. RADIUS Actions → Définissent l'auth RADIUS
# 10. EPA Actions → Définissent les checks EPA
# ============================================================================
# ========== CONFIGURATION ==========
$NS_CONF_PATH = "C:\logs\ns.conf"
$DEBUG_MODE = $false # Set to $true to see detailed calculation info
# ====================================
# ============================================================================
# FONCTIONS PRINCIPALES
# ============================================================================
function Load-NSConf {
param([string]$FilePath)
if (Test-Path $FilePath) {
Write-Host "`n[INFO] Chargement du fichier : $FilePath" -ForegroundColor Cyan
return Get-Content -Path $FilePath -Encoding UTF8
} else {
Write-Host "`n[ERREUR] Le fichier $FilePath est introuvable !" -ForegroundColor Red
exit 1
}
}
# ADC Interface paths
$policyPaths = @{
"authentication vserver" = "Security > AAA - Application Traffic > Authentication Virtual Servers"
"authentication authnprofile" = "Security > AAA - Application Traffic > Authentication Profile"
"authentication loginschema" = "Security > AAA - Application Traffic > Login Schema > Policies"
"authentication loginschemaprofile" = "Security > AAA - Application Traffic > Login Schema > Profiles"
"authentication policy" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Authentication Policies"
"authentication policylabel" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Authentication Policy Labels"
"authentication ldapAction" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Actions > LDAP Actions"
"authentication OAuthAction" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Actions > OAUTH Actions"
"authentication samlAction" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Actions > SAML Actions"
"authentication radiusAction" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Actions > RADIUS Actions"
"authentication epaAction" = "Security > AAA - Application Traffic > Policies > Authentication > Advanced Policies > Actions > Authentication EPA Action"
}
function Find-DefinedObjects {
param(
[string[]]$ConfigLines,
[string]$ObjectType
)
$configString = $ConfigLines -join "`n"
if ($ObjectType -match "Action$") {
$actualType = $ObjectType -replace "authentication ", ""
$pattern = "(?i)add authentication $actualType\s+(`"[^`"]+`"|\S+)"
} else {
$pattern = "(?i)add $ObjectType\s+(`"[^`"]+`"|\S+)"
}
$matches = [regex]::Matches($configString, $pattern)
$objects = @{}
foreach ($match in $matches) {
$objectName = $match.Groups[1].Value.Trim('"')
# Capturer la ligne complète
$linePattern = "(?im)^.*add.*$([regex]::Escape($objectName)).*$"
$lineMatch = [regex]::Match($configString, $linePattern)
$objects[$objectName] = @{
Name = $objectName
Type = $ObjectType
BoundTo = @()
BindingDetails = @()
Line = if ($lineMatch.Success) { $lineMatch.Value } else { "" }
}
}
return $objects
}
function Find-BoundObjects {
param(
[string[]]$ConfigLines,
[string]$ObjectType,
[hashtable]$DefinedObjects
)
$configString = $ConfigLines -join "`n"
$boundObjects = @{}
switch ($ObjectType.ToLower()) {
"authentication policy" {
# Bound to authentication vservers
$directPattern = "(?im)^(bind authentication vserver\s+(\S+).*?-policy\s+(`"([^`"]+)`"|\S+).*)$"
$matches = [regex]::Matches($configString, $directPattern)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$vserver = $match.Groups[2].Value.Trim('"')
$policy = $match.Groups[3].Value.Trim('"')
if ($DefinedObjects.ContainsKey($policy)) {
if (-not $boundObjects.ContainsKey($policy)) {
$boundObjects[$policy] = @()
}
if ($fullLine -match "-priority\s+(\d+)") {
$priority = $Matches[1]
$boundObjects[$policy] += @{
'Description' = "AUTH_VSERVER: $vserver (priority: $priority)"
'Line' = $fullLine
}
} else {
$boundObjects[$policy] += @{
'Description' = "AUTH_VSERVER: $vserver"
'Line' = $fullLine
}
}
}
}
# Bound to policy labels
$labelPattern = "(?im)^(bind authentication policylabel\s+(\S+).*?-policyName\s+(`"([^`"]+)`"|\S+).*)$"
$matches = [regex]::Matches($configString, $labelPattern)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$label = $match.Groups[2].Value.Trim('"')
$policy = $match.Groups[3].Value.Trim('"')
if ($DefinedObjects.ContainsKey($policy)) {
if (-not $boundObjects.ContainsKey($policy)) {
$boundObjects[$policy] = @()
}
if ($fullLine -match "-priority\s+(\d+)") {
$priority = $Matches[1]
$boundObjects[$policy] += @{
'Description' = "POLICY_LABEL: $label (priority: $priority)"
'Line' = $fullLine
}
} else {
$boundObjects[$policy] += @{
'Description' = "POLICY_LABEL: $label"
'Line' = $fullLine
}
}
}
}
# Bound globally
$globalPattern = "(?im)^(bind system global\s+(`"([^`"]+)`"|\S+).*)$"
$matches = [regex]::Matches($configString, $globalPattern)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$policy = $match.Groups[2].Value.Trim('"')
if ($DefinedObjects.ContainsKey($policy)) {
if (-not $boundObjects.ContainsKey($policy)) {
$boundObjects[$policy] = @()
}
$description = "GLOBAL_SYSTEM"
if ($fullLine -match "-priority\s+(\d+)") {
$priority = $Matches[1]
$description += " (priority: $priority)"
}
$boundObjects[$policy] += @{
'Description' = $description
'Line' = $fullLine
}
}
}
}
"authentication policylabel" {
# Policy labels are bound as nextFactor
$pattern = "(?im)^(bind authentication vserver\s+(\S+).*?-nextFactor\s+(\S+).*)$"
$matches = [regex]::Matches($configString, $pattern)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$vserver = $match.Groups[2].Value.Trim('"')
$label = $match.Groups[3].Value.Trim('"')
if ($DefinedObjects.ContainsKey($label)) {
if (-not $boundObjects.ContainsKey($label)) {
$boundObjects[$label] = @()
}
$boundObjects[$label] += @{
'Description' = "AUTH_VSERVER: $vserver (as nextFactor)"
'Line' = $fullLine
}
}
}
}
"authentication authnprofile" {
# Profiles bound to VPN vservers
$pattern = "(?im)^(add vpn vserver\s+(\S+).*?-authnProfile\s+(`"([^`"]+)`"|\S+).*)$"
$matches = [regex]::Matches($configString, $pattern)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$vserver = $match.Groups[2].Value.Trim('"')
$profile = $match.Groups[3].Value.Trim('"')
if ($DefinedObjects.ContainsKey($profile)) {
if (-not $boundObjects.ContainsKey($profile)) {
$boundObjects[$profile] = @()
}
$boundObjects[$profile] += @{
'Description' = "VPN_VSERVER: $vserver"
'Line' = $fullLine
}
}
}
# Profiles bound to LB vservers
$lbPattern = "(?im)^(add lb vserver\s+(\S+).*?-authnProfile\s+(`"([^`"]+)`"|\S+).*)$"
$matches = [regex]::Matches($configString, $lbPattern)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$vserver = $match.Groups[2].Value.Trim('"')
$profile = $match.Groups[3].Value.Trim('"')
if ($DefinedObjects.ContainsKey($profile)) {
if (-not $boundObjects.ContainsKey($profile)) {
$boundObjects[$profile] = @()
}
$boundObjects[$profile] += @{
'Description' = "LB_VSERVER: $vserver"
'Line' = $fullLine
}
}
}
}
"authentication vserver" {
# AAA vservers referenced in authnProfiles
$mapping = @{}
$patternMap = "(?i)add authentication authnProfile\s+(`"([^`"]+)`"|\S+).*?-authnVsName\s+(`"([^`"]+)`"|\S+)"
$matches = [regex]::Matches($configString, $patternMap)
foreach ($match in $matches) {
$profile = $match.Groups[1].Value.Trim('"')
$aaaVserver = $match.Groups[3].Value.Trim('"')
$mapping[$profile] = $aaaVserver
}
# Find where these profiles are used
$patternBound = "(?im)^(add vpn vserver\s+(\S+).*?-authnProfile\s+(`"([^`"]+)`"|\S+).*)$"
$matches = [regex]::Matches($configString, $patternBound)
foreach ($match in $matches) {
$fullLine = $match.Groups[1].Value
$vserver = $match.Groups[2].Value.Trim('"')
$profile = $match.Groups[3].Value.Trim('"')
if ($mapping.ContainsKey($profile)) {
$aaaVserver = $mapping[$profile]
if ($DefinedObjects.ContainsKey($aaaVserver)) {
if (-not $boundObjects.ContainsKey($aaaVserver)) {
$boundObjects[$aaaVserver] = @()
}
$boundObjects[$aaaVserver] += @{
'Description' = "VPN_VSERVER: $vserver (via profile: $profile)"
'Line' = $fullLine
}
}
}
}
}
"authentication loginschema" {
# Method 1: loginschema policies
$policyPattern = "(?i)add authentication loginschemapolicy\s+(`"[^`"]+`"|\S+).*?-action\s+(`"[^`"]+`"|\S+)"
$policyMatches = [regex]::Matches($configString, $policyPattern)
$schemaPolicies = @{}
foreach ($match in $policyMatches) {
$policyName = $match.Groups[1].Value.Trim('"')
$schemaName = $match.Groups[2].Value.Trim('"')
if (-not $schemaPolicies.ContainsKey($schemaName)) {
$schemaPolicies[$schemaName] = @()
}
$schemaPolicies[$schemaName] += $policyName
}
foreach ($schemaName in $schemaPolicies.Keys) {
if ($DefinedObjects.ContainsKey($schemaName)) {
foreach ($policyName in $schemaPolicies[$schemaName]) {
$bindPattern = "(?im)^(bind authentication vserver\s+(\S+).*?-policy\s+$([regex]::Escape($policyName)).*)$"
$bindMatches = [regex]::Matches($configString, $bindPattern)
foreach ($bindMatch in $bindMatches) {
$fullLine = $bindMatch.Groups[1].Value
$vserver = $bindMatch.Groups[2].Value.Trim('"')
if (-not $boundObjects.ContainsKey($schemaName)) {
$boundObjects[$schemaName] = @()
}
$boundObjects[$schemaName] += @{
'Description' = "AUTH_VSERVER: $vserver (via policy: $policyName)"
'Line' = $fullLine
}
}
}
}
}
# Method 2: schemas in policy labels (only if label is actually used)
$labelPattern = "(?is)add authentication policylabel\s+(`"[^`"]+`"|\S+).*?-login[Ss]chema\s+(`"[^`"]+`"|\S+)"
$labelMatches = [regex]::Matches($configString, $labelPattern)
foreach ($match in $labelMatches) {
$labelName = $match.Groups[1].Value.Trim('"')
$schemaName = $match.Groups[2].Value.Trim('"')
if ($DefinedObjects.ContainsKey($schemaName)) {
# Check if label has policies bound
$labelPolicyPattern = "(?is)bind authentication policylabel\s+$([regex]::Escape($labelName)).*?-policyName\s+(`"[^`"]+`"|\S+)"
$labelPolicyMatches = [regex]::Matches($configString, $labelPolicyPattern)
$policiesInLabel = @()
foreach ($policyMatch in $labelPolicyMatches) {
$policyInLabel = $policyMatch.Groups[1].Value.Trim('"')
$policiesInLabel += $policyInLabel
}
if ($policiesInLabel.Count -gt 0) {
# Check if policies are bound to vservers
foreach ($policy in $policiesInLabel) {
$vserverBindPattern = "(?im)^(bind authentication vserver\s+(\S+).*?-policy\s+$([regex]::Escape($policy)).*)$"
$vserverMatches = [regex]::Matches($configString, $vserverBindPattern)
foreach ($vMatch in $vserverMatches) {
$fullLine = $vMatch.Groups[1].Value
$vserver = $vMatch.Groups[2].Value.Trim('"')
if (-not $boundObjects.ContainsKey($schemaName)) {
$boundObjects[$schemaName] = @()
}
$boundObjects[$schemaName] += @{
'Description' = "POLICY_LABEL: $labelName -> POLICY: $policy -> VSERVER: $vserver"
'Line' = $fullLine
}
}
}
}
}
}
# Method 3: nextFactor usage
foreach ($match in $labelMatches) {
$labelName = $match.Groups[1].Value.Trim('"')
$schemaName = $match.Groups[2].Value.Trim('"')
if ($DefinedObjects.ContainsKey($schemaName)) {
$nextFactorPattern = "(?im)^(bind authentication (?:vserver|policylabel)\s+(\S+).*?-nextFactor\s+$([regex]::Escape($labelName)).*)$"
$nextFactorMatches = [regex]::Matches($configString, $nextFactorPattern)
foreach ($nfMatch in $nextFactorMatches) {
$fullLine = $nfMatch.Groups[1].Value
$vserver = $nfMatch.Groups[2].Value.Trim('"')
if (-not $boundObjects.ContainsKey($schemaName)) {
$boundObjects[$schemaName] = @()
}
$binding = @{
'Description' = "POLICY_LABEL: $labelName -> VSERVER: $vserver (as nextFactor)"
'Line' = $fullLine
}
# Éviter les doublons
$exists = $false
foreach ($existing in $boundObjects[$schemaName]) {
if ($existing['Description'] -eq $binding['Description']) {
$exists = $true
break
}
}
if (-not $exists) {
$boundObjects[$schemaName] += $binding
}
}
}
}
}
{ $_ -in @("authentication ldapAction", "authentication OAuthAction",
"authentication samlAction", "authentication radiusAction",
"authentication epaAction") } {
# Actions referenced in policies
$policyPattern = "(?i)add authentication policy\s+(`"[^`"]+`"|\S+).*?-action\s+(`"[^`"]+`"|\S+)"
$matches = [regex]::Matches($configString, $policyPattern)
foreach ($match in $matches) {
$policyName = $match.Groups[1].Value.Trim('"')
$actionName = $match.Groups[2].Value.Trim('"')
if ($DefinedObjects.ContainsKey($actionName)) {
# Get the line for this policy definition
$policyLinePattern = "(?im)^(add authentication policy\s+$([regex]::Escape($policyName)).*?)$"
$policyLineMatch = [regex]::Match($configString, $policyLinePattern)
$policyLine = if ($policyLineMatch.Success) { $policyLineMatch.Groups[1].Value } else { "" }
if (-not $boundObjects.ContainsKey($actionName)) {
$boundObjects[$actionName] = @()
}
# Check if policy is bound
$policyBound = $false
$bindingDetails = @()
# Check vserver bindings
$vserverPattern = "(?im)^(bind authentication vserver\s+(\S+).*?-policy\s+$([regex]::Escape($policyName)).*)$"
$vserverMatches = [regex]::Matches($configString, $vserverPattern)
foreach ($vMatch in $vserverMatches) {
$fullLine = $vMatch.Groups[1].Value
$vserver = $vMatch.Groups[2].Value.Trim('"')
$bindingDetails += @{
'Type' = "vserver"
'Description' = "via AUTH_VSERVER: $vserver"
'Line' = $fullLine
}
$policyBound = $true
}
# Check label bindings
$labelPattern = "(?im)^(bind authentication policylabel\s+(\S+).*?-policyName\s+$([regex]::Escape($policyName)).*)$"
$labelMatches = [regex]::Matches($configString, $labelPattern)
foreach ($lMatch in $labelMatches) {
$fullLine = $lMatch.Groups[1].Value
$label = $lMatch.Groups[2].Value.Trim('"')
$bindingDetails += @{
'Type' = "label"
'Description' = "via POLICY_LABEL: $label"
'Line' = $fullLine
}
$policyBound = $true
}
# Check global bindings
$globalPattern = "(?im)^(bind system global\s+$([regex]::Escape($policyName)).*)$"
if ([regex]::IsMatch($configString, $globalPattern)) {
$globalMatch = [regex]::Match($configString, $globalPattern)
$fullLine = $globalMatch.Groups[1].Value
$bindingDetails += @{
'Type' = "global"
'Description' = "via GLOBAL_SYSTEM"
'Line' = $fullLine
}
$policyBound = $true
}
# Add to bound objects
if ($policyBound) {
foreach ($detail in $bindingDetails) {
$boundObjects[$actionName] += @{
'Description' = "POLICY: $policyName ($($detail['Description']))"
'Line' = $detail['Line']
'PolicyLine' = $policyLine
}
}
}
}
}
}
}
# Update defined objects
foreach ($objName in $boundObjects.Keys) {
if ($DefinedObjects.ContainsKey($objName)) {
$DefinedObjects[$objName].BoundTo = $boundObjects[$objName]
}
}
return $boundObjects
}
# ============================================================================
# AFFICHAGE DES RESULTATS
# ============================================================================
function Show-ObjectsWithSeparation {
param(
[hashtable]$DefinedObjects,
[hashtable]$BoundObjects,
[string]$ObjectType,
[string]$ConfigString
)
# Séparer en catégories
$orphanObjects = @()
$referencedButUnboundObjects = @{}
$boundObjectsList = @()
foreach ($objName in ($DefinedObjects.Keys | Sort-Object)) {
if ($BoundObjects.ContainsKey($objName) -and $BoundObjects[$objName].Count -gt 0) {
# Objet bindé/utilisé
$boundObjectsList += $objName
} else {
# Objet non bindé - déterminer pourquoi
$isReferenced = $false
$references = @()
# Logique spécifique selon le type
switch ($ObjectType.ToLower()) {
"authentication loginschema" {
# Check si dans un label
$labelPattern = "(?is)add authentication policylabel\s+(`"[^`"]+`"|\S+).*?-login[Ss]chema\s+$([regex]::Escape($objName))"
$labelMatches = [regex]::Matches($ConfigString, $labelPattern)
if ($labelMatches.Count -gt 0) {
foreach ($match in $labelMatches) {
$labelName = $match.Groups[1].Value.Trim('"')
$references += "Label: $labelName"
$isReferenced = $true
}
}
}
{ $_ -in @("authentication ldapaction", "authentication oauthaction",
"authentication samlaction", "authentication radiusaction",
"authentication epaaction") } {
# Check si utilisée par une policy
$policyPattern = "(?i)add authentication policy\s+(`"[^`"]+`"|\S+).*?-action\s+$([regex]::Escape($objName))"
$policyMatches = [regex]::Matches($ConfigString, $policyPattern)
if ($policyMatches.Count -gt 0) {
foreach ($match in $policyMatches) {
$policyName = $match.Groups[1].Value.Trim('"')
$references += "Policy: $policyName (not bound)"
$isReferenced = $true
}
}
}
}
if ($isReferenced) {
$referencedButUnboundObjects[$objName] = $references
} else {
$orphanObjects += $objName
}
}
}
# Affichage
$totalUnused = $orphanObjects.Count + $referencedButUnboundObjects.Count
if ($totalUnused -gt 0) {
Write-Host "`n[OBJETS NON UTILISES: $totalUnused]" -ForegroundColor Red
# [1] Objets orphelins
if ($orphanObjects.Count -gt 0) {
Write-Host "`n [1] Orphelins (aucune reference) : $($orphanObjects.Count)" -ForegroundColor Yellow
foreach ($objName in $orphanObjects) {
Write-Host " ├─ " -NoNewline -ForegroundColor Red
Write-Host "$objName" -ForegroundColor Red
Write-Host " │ " -NoNewline -ForegroundColor DarkGray
Write-Host "$($DefinedObjects[$objName].Line)" -ForegroundColor White
}
}
# [2] Objets référencés mais non bindés
if ($referencedButUnboundObjects.Count -gt 0) {
Write-Host "`n [2] References mais non bindes : $($referencedButUnboundObjects.Count)" -ForegroundColor Yellow
foreach ($objName in ($referencedButUnboundObjects.Keys | Sort-Object)) {
Write-Host " ├─ " -NoNewline -ForegroundColor Red
Write-Host "$objName" -ForegroundColor Red
Write-Host " │ " -NoNewline -ForegroundColor DarkGray
Write-Host "$($DefinedObjects[$objName].Line)" -ForegroundColor White
Write-Host " │ " -NoNewline -ForegroundColor DarkGray
Write-Host "Reference par :" -ForegroundColor DarkGray
foreach ($ref in $referencedButUnboundObjects[$objName]) {
Write-Host " │ • " -NoNewline -ForegroundColor DarkGray
Write-Host "$ref" -ForegroundColor Yellow
}
}
}
}
# Objets utilisés
if ($boundObjectsList.Count -gt 0) {
Write-Host "`n[OBJETS UTILISES: $($boundObjectsList.Count)]" -ForegroundColor Green
foreach ($objName in $boundObjectsList) {
if ($ObjectType -match "Action$") {
Write-Host " [✓] $objName" -ForegroundColor Cyan
} else {
Write-Host " [✓] $objName" -ForegroundColor Green
}
foreach ($binding in $BoundObjects[$objName]) {
if ($binding['Description'] -match "GLOBAL_SYSTEM") {
Write-Host " └─ $($binding['Description'])" -ForegroundColor Cyan
} else {
Write-Host " └─ $($binding['Description'])" -ForegroundColor Gray
}
Write-Host " $($binding['Line'])" -ForegroundColor White
}
}
}
}
# ============================================================================
# EXECUTION PRINCIPALE
# ============================================================================
Clear-Host
Write-Host "`n" -NoNewline
Write-Host "╔" -NoNewline -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║" -NoNewline -ForegroundColor Cyan
Write-Host " " -NoNewline
Write-Host "║" -ForegroundColor Cyan
Write-Host "║" -NoNewline -ForegroundColor Cyan
Write-Host " NetScaler Authentication (AAA) Analysis - ENHANCED v2.4 " -NoNewline -ForegroundColor Yellow
Write-Host "║" -ForegroundColor Cyan
Write-Host "║" -NoNewline -ForegroundColor Cyan
Write-Host " " -NoNewline
Write-Host "║" -ForegroundColor Cyan
Write-Host "╚" -NoNewline -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
$configLines = Load-NSConf -FilePath $NS_CONF_PATH
if ($configLines.Count -eq 0) {
exit
}
Write-Host "Configuration loaded: $($configLines.Count) lines`n" -ForegroundColor Green
# Types d'objets à analyser (ordre logique)
$authTypes = @(
"authentication authnprofile",
"authentication vserver",
"authentication loginschema",
"authentication policy",
"authentication policylabel",
"authentication ldapAction",
"authentication OAuthAction",
"authentication samlAction",
"authentication radiusAction",
"authentication epaAction"
)
Write-Host "Starting authentication policy analysis..." -ForegroundColor Yellow
Write-Host "Objects will be analyzed in logical flow order (entry point → endpoints)" -ForegroundColor DarkGray
Write-Host ("=" * 80) -ForegroundColor DarkGray
Write-Host ""
$allPolicies = @{}
$totalDefined = 0
$totalBound = 0
$totalUnbound = 0
foreach ($authType in $authTypes) {
Write-Progress -Activity "Analysis in progress" -Status "Processing: $authType" `
-PercentComplete (($authTypes.IndexOf($authType) + 1) / $authTypes.Count * 100)
$defined = Find-DefinedObjects -ConfigLines $configLines -ObjectType $authType
$bound = Find-BoundObjects -ConfigLines $configLines -ObjectType $authType -DefinedObjects $defined
if ($defined.Count -gt 0) {
$boundCount = 0
foreach ($obj in $defined.Keys) {
if ($bound.ContainsKey($obj) -and $bound[$obj].Count -gt 0) {
$boundCount++
}
}
if ($DEBUG_MODE) {
Write-Host "DEBUG [$authType]: Defined=$($defined.Count), Bound=$boundCount, Unbound=$($defined.Count - $boundCount)" -ForegroundColor DarkYellow
}
$allPolicies[$authType] = @{
Defined = $defined
Bound = $bound
BoundCount = $boundCount
UnboundCount = ($defined.Count - $boundCount)
}
$totalDefined += $defined.Count
$totalBound += $boundCount
$totalUnbound += ($defined.Count - $boundCount)
}
}
Write-Progress -Completed -Activity "Analysis in progress"
# Afficher le RESUME
Write-Host ("=" * 80) -ForegroundColor Cyan
Write-Host " RESUME" -ForegroundColor Yellow
Write-Host ("=" * 80) -ForegroundColor Cyan
Write-Host ""
Write-Host "Authentication Objects Analysis:" -ForegroundColor White
Write-Host " |"
Write-Host " |-- Total objects defined: $totalDefined"
Write-Host " | |-- " -NoNewline
Write-Host "Bound (in use): $totalBound" -ForegroundColor Green
Write-Host " | |-- " -NoNewline
Write-Host "Unbound (unused): $totalUnbound" -ForegroundColor $(if ($totalUnbound -gt 0) { "Red" } else { "Green" })
Write-Host " |"
Write-Host " |-- Object types analyzed: $($allPolicies.Count)" -ForegroundColor White
Write-Host "`n==================================================================" -ForegroundColor Cyan
# Générer les commandes de suppression
$allUnusedObjects = @()
foreach ($authType in $authTypes) {
if ($allPolicies.ContainsKey($authType)) {
$policies = $allPolicies[$authType]
$defined = $policies.Defined
$bound = $policies.Bound
foreach ($objName in ($defined.Keys | Sort-Object)) {
if (-not $bound.ContainsKey($objName) -or $bound[$objName].Count -eq 0) {
$allUnusedObjects += @{
'Type' = $authType
'Name' = $objName
}
}
}
}
}
if ($allUnusedObjects.Count -gt 0) {
Write-Host "`n==================================================================" -ForegroundColor Yellow
Write-Host " COMMANDES DE SUPPRESSION (copier-coller)" -ForegroundColor Yellow -BackgroundColor Black
Write-Host "==================================================================" -ForegroundColor Yellow
Write-Host ""
foreach ($obj in $allUnusedObjects) {
$type = $obj['Type']
$name = $obj['Name']
# Générer la bonne commande selon le type
if ($type -match "Action$") {
$actualType = $type -replace "authentication ", ""
Write-Host "rm authentication $actualType $name" -ForegroundColor White
} else {
Write-Host "rm $type $name" -ForegroundColor White
}
}
Write-Host "`n==================================================================" -ForegroundColor Yellow
}
# Afficher les détails par type
Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
Write-Host " AUTHENTICATION OBJECTS - DETAILED ANALYSIS" -ForegroundColor Yellow
Write-Host ("=" * 80) -ForegroundColor Cyan
Write-Host ""
$configString = $configLines -join "`n"
foreach ($authType in $authTypes) {
if ($allPolicies.ContainsKey($authType)) {
$policies = $allPolicies[$authType]
$defined = $policies.Defined
$bound = $policies.Bound
$boundCount = $policies.BoundCount
$unboundCount = $policies.UnboundCount
$path = $policyPaths[$authType]
if (-not $path) { $path = "Path not defined" }
Write-Host "`n[OBJECT TYPE: $($authType.ToUpper())]" -ForegroundColor Yellow
Write-Host "Location: $path" -ForegroundColor DarkGray
Write-Host "Statistics: Total=$($defined.Count) | " -NoNewline
Write-Host "Bound=$boundCount " -ForegroundColor Green -NoNewline
Write-Host "| " -NoNewline
Write-Host "Unbound=$unboundCount" -ForegroundColor Red
Show-ObjectsWithSeparation -DefinedObjects $defined -BoundObjects $bound -ObjectType $authType -ConfigString $configString
}
}
Write-Host "`n" + ("=" * 80) -ForegroundColor Cyan
Write-Host "Analysis complete" -ForegroundColor Cyan
Write-Host ""