powershell max theme bind

# NetScaler Authentication Policy Analyzer
# ============================================================================
# Script d'analyse des Portal Themes NetScaler
# ============================================================================
# Ce script analyse le fichier ns.conf pour identifier :
#   - Tous les portal themes définis (add vpn portaltheme)
#   - Leurs bindings sur vpn vserver (Citrix Gateway)
#   - Leurs bindings sur authentication vserver (AAA)
#   - Les themes orphelins (non bindés) à supprimer
#
# Auteur  : Maximilien (ITMAX)
# Version : 1.0
# Date    : 12/11/2025
# ============================================================================

param(
    [Parameter(Mandatory=$false)]
    [string]$ConfigPath = "C:\logs\ns.conf"
)

# ============================================================================
# FONCTIONS UTILITAIRES
# ============================================================================

function Write-Header {
    param([string]$Title)
    Write-Host ""
    Write-Host "===============================================================================" -ForegroundColor Cyan
    Write-Host "  $Title" -ForegroundColor Yellow
    Write-Host "===============================================================================" -ForegroundColor Cyan
    Write-Host ""
}

function Write-Section {
    param([string]$Title)
    Write-Host ""
    Write-Host "-------------------------------------------------------------------------------" -ForegroundColor DarkCyan
    Write-Host "  $Title" -ForegroundColor White
    Write-Host "-------------------------------------------------------------------------------" -ForegroundColor DarkCyan
    Write-Host ""
}

function Write-SubSection {
    param([string]$Title)
    Write-Host ""
    Write-Host "  $Title" -ForegroundColor Gray
    Write-Host "  " + ("-" * ($Title.Length)) -ForegroundColor DarkGray
}

# ============================================================================
# CHARGEMENT ET VALIDATION DU FICHIER
# ============================================================================

Write-Header "ANALYSE DES PORTAL THEMES NETSCALER"

Write-Host "Fichier analyse : " -NoNewline -ForegroundColor White
Write-Host $ConfigPath -ForegroundColor Cyan

if (-not (Test-Path $ConfigPath)) {
    Write-Host ""
    Write-Host "ERREUR : Le fichier $ConfigPath est introuvable !" -ForegroundColor Red
    Write-Host ""
    exit 1
}

Write-Host "Fichier trouve - Chargement en cours..." -ForegroundColor Green
Write-Host ""

$configContent = Get-Content -Path $ConfigPath -Encoding UTF8 -ErrorAction Stop

Write-Host "Nombre de lignes : " -NoNewline -ForegroundColor White
Write-Host $configContent.Count -ForegroundColor Yellow

# ============================================================================
# PATTERNS DE RECHERCHE
# ============================================================================

$patterns = @{
    AddTheme = 'add\s+vpn\s+portaltheme\s+([^\s]+)'
    BindVpnVserver = 'bind\s+vpn\s+vserver\s+([^\s]+)\s+.*-portaltheme\s+([^\s]+)'
    BindAuthVserver = 'bind\s+authentication\s+vserver\s+([^\s]+)\s+.*-portaltheme\s+([^\s]+)'
}

# ============================================================================
# COLLECTE DES DONNÉES
# ============================================================================

Write-Section "ANALYSE DU FICHIER ns.conf"

# Structures de données
$allThemes = @{}  # Tous les themes définis
$vpnBindings = @{}  # Bindings sur vpn vserver
$authBindings = @{}  # Bindings sur authentication vserver

Write-Host "  Recherche des portal themes..." -ForegroundColor Gray

# 1. Collecter tous les themes définis
foreach ($line in $configContent) {
    if ($line -match $patterns.AddTheme) {
        $themeName = $Matches[1]
        if (-not $allThemes.ContainsKey($themeName)) {
            $allThemes[$themeName] = @{
                Name = $themeName
                VpnVservers = @()
                AuthVservers = @()
            }
        }
    }
}

Write-Host "  Trouve : " -NoNewline -ForegroundColor Gray
Write-Host "$($allThemes.Count) themes" -ForegroundColor Yellow

Write-Host "  Recherche des bindings vpn vserver..." -ForegroundColor Gray

# 2. Collecter les bindings sur vpn vserver
foreach ($line in $configContent) {
    if ($line -match $patterns.BindVpnVserver) {
        $vserverName = $Matches[1]
        $themeName = $Matches[2]
        
        if ($allThemes.ContainsKey($themeName)) {
            $allThemes[$themeName].VpnVservers += $vserverName
        }
    }
}

$totalVpnBindings = ($allThemes.Values | ForEach-Object { $_.VpnVservers.Count } | Measure-Object -Sum).Sum
Write-Host "  Trouve : " -NoNewline -ForegroundColor Gray
Write-Host "$totalVpnBindings bindings sur vpn vserver" -ForegroundColor Yellow

Write-Host "  Recherche des bindings authentication vserver..." -ForegroundColor Gray

# 3. Collecter les bindings sur authentication vserver
foreach ($line in $configContent) {
    if ($line -match $patterns.BindAuthVserver) {
        $vserverName = $Matches[1]
        $themeName = $Matches[2]
        
        if ($allThemes.ContainsKey($themeName)) {
            $allThemes[$themeName].AuthVservers += $vserverName
        }
    }
}

$totalAuthBindings = ($allThemes.Values | ForEach-Object { $_.AuthVservers.Count } | Measure-Object -Sum).Sum
Write-Host "  Trouve : " -NoNewline -ForegroundColor Gray
Write-Host "$totalAuthBindings bindings sur authentication vserver" -ForegroundColor Yellow

# ============================================================================
# CALCUL DES STATISTIQUES
# ============================================================================

$boundThemes = @()
$unboundThemes = @()

foreach ($theme in $allThemes.Values) {
    $totalBindings = $theme.VpnVservers.Count + $theme.AuthVservers.Count
    if ($totalBindings -gt 0) {
        $boundThemes += $theme
    } else {
        $unboundThemes += $theme
    }
}

# ============================================================================
# AFFICHAGE DU RÉSUMÉ
# ============================================================================

Write-Section "RESUME DE L'ANALYSE"

Write-Host "  Total Portal Themes  : " -NoNewline
Write-Host $allThemes.Count -ForegroundColor Yellow

Write-Host "  +- " -NoNewline -ForegroundColor DarkGray
Write-Host "Themes bindes      : " -NoNewline
Write-Host $boundThemes.Count -ForegroundColor Green

Write-Host "  +- " -NoNewline -ForegroundColor DarkGray
Write-Host "Themes orphelins   : " -NoNewline
Write-Host $unboundThemes.Count -ForegroundColor Red

Write-Host ""
Write-Host "  Total Bindings       : " -NoNewline
Write-Host ($totalVpnBindings + $totalAuthBindings) -ForegroundColor Yellow

Write-Host "  +- " -NoNewline -ForegroundColor DarkGray
Write-Host "VPN vserver          : " -NoNewline
Write-Host $totalVpnBindings -ForegroundColor Cyan

Write-Host "  +- " -NoNewline -ForegroundColor DarkGray
Write-Host "AAA vserver          : " -NoNewline
Write-Host $totalAuthBindings -ForegroundColor Magenta

# ============================================================================
# AFFICHAGE DES THEMES BINDÉS
# ============================================================================

if ($boundThemes.Count -gt 0) {
    Write-Section "PORTAL THEMES BINDES ($($boundThemes.Count))"
    
    $sortedBoundThemes = $boundThemes | Sort-Object { $_.Name }
    
    foreach ($theme in $sortedBoundThemes) {
        $totalBindings = $theme.VpnVservers.Count + $theme.AuthVservers.Count
        
        Write-Host ""
        Write-Host "  [OK] " -NoNewline -ForegroundColor Green
        Write-Host $theme.Name -NoNewline -ForegroundColor Green
        Write-Host " ($totalBindings binding(s))" -ForegroundColor DarkGray
        
        # Afficher les bindings VPN vserver
        if ($theme.VpnVservers.Count -gt 0) {
            Write-Host "     +- VPN vserver (" -NoNewline -ForegroundColor DarkGray
            Write-Host $theme.VpnVservers.Count -NoNewline -ForegroundColor Cyan
            Write-Host ")" -ForegroundColor DarkGray
            
            for ($i = 0; $i -lt $theme.VpnVservers.Count; $i++) {
                $isLast = ($i -eq $theme.VpnVservers.Count - 1) -and ($theme.AuthVservers.Count -eq 0)
                $prefix = if ($isLast) { "     |  +-" } else { "     |  +-" }
                
                Write-Host "$prefix " -NoNewline -ForegroundColor DarkGray
                Write-Host $theme.VpnVservers[$i] -ForegroundColor Cyan
            }
        }
        
        # Afficher les bindings AAA vserver
        if ($theme.AuthVservers.Count -gt 0) {
            Write-Host "     +- AAA vserver (" -NoNewline -ForegroundColor DarkGray
            Write-Host $theme.AuthVservers.Count -NoNewline -ForegroundColor Magenta
            Write-Host ")" -ForegroundColor DarkGray
            
            for ($i = 0; $i -lt $theme.AuthVservers.Count; $i++) {
                $isLast = $i -eq $theme.AuthVservers.Count - 1
                $prefix = if ($isLast) { "        +-" } else { "        +-" }
                
                Write-Host "$prefix " -NoNewline -ForegroundColor DarkGray
                Write-Host $theme.AuthVservers[$i] -ForegroundColor Magenta
            }
        }
    }
}

# ============================================================================
# AFFICHAGE DES THEMES ORPHELINS
# ============================================================================

if ($unboundThemes.Count -gt 0) {
    Write-Section "PORTAL THEMES ORPHELINS (NON BINDES) - $($unboundThemes.Count)"
    
    Write-Host "  ATTENTION : Ces themes ne sont bindes a aucun vserver et peuvent etre supprimes" -ForegroundColor Yellow
    Write-Host ""
    
    $sortedUnboundThemes = $unboundThemes | Sort-Object { $_.Name }
    
    foreach ($theme in $sortedUnboundThemes) {
        Write-Host "  [NON BINDE] " -NoNewline -ForegroundColor Red
        Write-Host $theme.Name -ForegroundColor Red
    }
    
    # ============================================================================
    # GÉNÉRATION DES COMMANDES DE SUPPRESSION
    # ============================================================================
    
    Write-Section "COMMANDES DE SUPPRESSION"
    
    Write-Host "  Copiez et executez ces commandes pour supprimer les themes orphelins :" -ForegroundColor Yellow
    Write-Host ""
    
    foreach ($theme in $sortedUnboundThemes) {
        Write-Host "  rm vpn portaltheme $($theme.Name)" -ForegroundColor DarkGray
    }
    
    Write-Host ""
    Write-Host "  Pour sauvegarder la configuration apres suppression :" -ForegroundColor Yellow
    Write-Host "  save ns config" -ForegroundColor DarkGray
    
} else {
    Write-Section "AUCUN THEME ORPHELIN DETECTE"
    Write-Host "  Tous les portal themes sont correctement bindes !" -ForegroundColor Green
}

# ============================================================================
# FOOTER
# ============================================================================

Write-Host ""
Write-Host "===============================================================================" -ForegroundColor Cyan
Write-Host "  Analyse terminee avec succes !" -ForegroundColor Green
Write-Host "===============================================================================" -ForegroundColor Cyan
Write-Host ""