powershell max LB VSERVER

# NetScaler Load Balancing Objects Analyzer v1.0
# Analyse: Monitor -> Service -> ServiceGroup -> LB vServer
$NS_CONF_PATH = "C:\logs\ns.conf"

# EXTRACTION
function Get-LBVServers { param([string[]]$L); $v=@{}; foreach($l in $L){if($l -match "^add lb vserver\s+(\S+)"){$v[$Matches[1].Trim('"')]=@{'Line'=$l}}}; $v }
function Get-ServiceGroups { param([string[]]$L); $s=@{}; foreach($l in $L){if($l -match "^add serviceGroup\s+(\S+)"){$s[$Matches[1].Trim('"')]=@{'Line'=$l}}}; $s }
function Get-Services { param([string[]]$L); $s=@{}; foreach($l in $L){if($l -match "^add service\s+(\S+)"){$s[$Matches[1].Trim('"')]=@{'Line'=$l}}}; $s }
function Get-Monitors { param([string[]]$L); $m=@{}; foreach($l in $L){if($l -match "^add lb monitor\s+(\S+)"){$m[$Matches[1].Trim('"')]=@{'Line'=$l}}}; $m }

function Get-ServiceGroupBindings { 
    param([string[]]$L,[hashtable]$SG)
    $b=@{}
    foreach($l in $L){
        if($l -match "^bind lb vserver\s+(\S+)\s+(\S+)"){
            $vs=$Matches[1].Trim('"');$t=$Matches[2].Trim('"')
            if($SG.ContainsKey($t)){if(-not $b.ContainsKey($t)){$b[$t]=@()}; $b[$t]+=@{'VServer'=$vs;'Line'=$l}}
        }
    }
    $b
}

function Get-ServiceBindingsToVServer { 
    param([string[]]$L,[hashtable]$S)
    $b=@{}
    foreach($l in $L){
        if($l -match "^bind lb vserver\s+(\S+)\s+(\S+)"){
            $vs=$Matches[1].Trim('"');$t=$Matches[2].Trim('"')
            if($S.ContainsKey($t)){if(-not $b.ContainsKey($t)){$b[$t]=@()}; $b[$t]+=@{'VServer'=$vs;'Line'=$l}}
        }
    }
    $b
}

function Get-ServiceGroupMembers { 
    param([string[]]$L)
    $m=@{}
    foreach($l in $L){
        if($l -match "^bind serviceGroup\s+(\S+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+)"){
            $g=$Matches[1].Trim('"')
            if(-not $m.ContainsKey($g)){$m[$g]=@()}
            $m[$g]+=@{'IP'=$Matches[2];'Port'=$Matches[3];'Line'=$l}
        }
    }
    $m
}

function Get-MonitorBindings { 
    param([string[]]$L)
    $u=@{}
    foreach($l in $L){
        if($l -match "^bind service\s+(\S+)\s+-monitorName\s+(\S+)"){
            $s=$Matches[1].Trim('"');$mn=$Matches[2].Trim('"')
            if(-not $u.ContainsKey($mn)){$u[$mn]=@{'Services'=@();'ServiceGroups'=@()}}
            $u[$mn]['Services']+=@{'Name'=$s;'Line'=$l}
        }
        if($l -match "^bind serviceGroup\s+(\S+)\s+-monitorName\s+(\S+)"){
            $g=$Matches[1].Trim('"');$mn=$Matches[2].Trim('"')
            if(-not $u.ContainsKey($mn)){$u[$mn]=@{'Services'=@();'ServiceGroups'=@()}}
            $u[$mn]['ServiceGroups']+=@{'Name'=$g;'Line'=$l}
        }
    }
    $u
}

function Get-UsedMonitors { 
    param([hashtable]$MB,[hashtable]$BSG,[hashtable]$BSvc)
    $u=@{}
    foreach($mn in $MB.Keys){
        $d=@()
        foreach($svc in $MB[$mn]['Services']){if($BSvc.ContainsKey($svc['Name'])){$d+=@{'Type'='Service';'Name'=$svc['Name'];'Line'=$svc['Line']}}}
        foreach($sg in $MB[$mn]['ServiceGroups']){if($BSG.ContainsKey($sg['Name'])){$d+=@{'Type'='ServiceGroup';'Name'=$sg['Name'];'Line'=$sg['Line']}}}
        if($d.Count -gt 0){$u[$mn]=$d}
    }
    $u
}

# AFFICHAGE ROUGE - NON UTILISES
function Show-UnusedServiceGroups { 
    param([hashtable]$SG,[hashtable]$BSG)
    Write-Host "`n==================================================================" -ForegroundColor Red
    Write-Host " SERVICE GROUPS NON UTILISES" -ForegroundColor Red -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Red
    $unused=@(); foreach($n in ($SG.Keys|Sort-Object)){if(-not $BSG.ContainsKey($n)){$unused+=$n}}
    if($unused.Count -eq 0){Write-Host "`nAucun service group non utilise !" -ForegroundColor Green}
    else{
        Write-Host "`nNombre: $($unused.Count)" -ForegroundColor Red
        foreach($n in $unused){
            Write-Host "  |-- $n" -ForegroundColor Red
            Write-Host "  |   $($SG[$n]['Line'])" -ForegroundColor White
            Write-Host "  |   rm serviceGroup $n" -ForegroundColor White
        }
    }
}

function Show-UnusedServices { 
    param([hashtable]$S,[hashtable]$BSvc)
    Write-Host "`n==================================================================" -ForegroundColor Red
    Write-Host " SERVICES NON UTILISES" -ForegroundColor Red -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Red
    $unused=@(); foreach($n in ($S.Keys|Sort-Object)){if(-not $BSvc.ContainsKey($n)){$unused+=$n}}
    if($unused.Count -eq 0){Write-Host "`nAucun service non utilise !" -ForegroundColor Green}
    else{
        Write-Host "`nNombre: $($unused.Count)" -ForegroundColor Red
        foreach($n in $unused){
            Write-Host "  |-- $n" -ForegroundColor Red
            Write-Host "  |   $($S[$n]['Line'])" -ForegroundColor White
            Write-Host "  |   rm service $n" -ForegroundColor White
        }
    }
}

function Show-UnusedMonitors { 
    param([hashtable]$M,[hashtable]$UM,[hashtable]$MB)
    Write-Host "`n==================================================================" -ForegroundColor Red
    Write-Host " MONITORS NON UTILISES" -ForegroundColor Red -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Red
    $orph=@();$bnd=@{}
    foreach($n in ($M.Keys|Sort-Object)){
        if(-not $UM.ContainsKey($n)){
            if($MB.ContainsKey($n)){
                $r=@()
                foreach($svc in $MB[$n]['Services']){$r+="Service: $($svc['Name']) (non binde)"}
                foreach($sg in $MB[$n]['ServiceGroups']){$r+="ServiceGroup: $($sg['Name']) (non binde)"}
                $bnd[$n]=$r
            }else{$orph+=$n}
        }
    }
    $t=$orph.Count+$bnd.Count
    if($t -eq 0){Write-Host "`nAucun monitor non utilise !" -ForegroundColor Green}
    else{
        Write-Host "`nNombre: $t" -ForegroundColor Red
        if($orph.Count -gt 0){
            Write-Host "`n[1] Orphelins (aucun binding): $($orph.Count)" -ForegroundColor Yellow
            foreach($n in $orph){
                Write-Host "  |-- $n" -ForegroundColor Red
                Write-Host "  |   $($M[$n]['Line'])" -ForegroundColor White
                Write-Host "  |   rm lb monitor $n" -ForegroundColor White
            }
        }
        if($bnd.Count -gt 0){
            Write-Host "`n[2] Bindes a objets non utilises: $($bnd.Count)" -ForegroundColor Yellow
            foreach($n in ($bnd.Keys|Sort-Object)){
                Write-Host "  |-- $n" -ForegroundColor Red
                Write-Host "  |   $($M[$n]['Line'])" -ForegroundColor White
                Write-Host "  |   Reference par:" -ForegroundColor DarkGray
                foreach($r in $bnd[$n]){Write-Host "  |     * $r" -ForegroundColor Yellow}
                Write-Host "  |   rm lb monitor $n" -ForegroundColor White
            }
        }
    }
}

# AFFICHAGE VERT - UTILISES
function Show-UsedServiceGroups { 
    param([hashtable]$SG,[hashtable]$BSG,[hashtable]$M)
    Write-Host "`n==================================================================" -ForegroundColor Green
    Write-Host " SERVICE GROUPS UTILISES" -ForegroundColor Green -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Green
    $used=@(); foreach($n in ($SG.Keys|Sort-Object)){if($BSG.ContainsKey($n)){$used+=$n}}
    if($used.Count -eq 0){Write-Host "`nAucun service group utilise !" -ForegroundColor Yellow}
    else{
        Write-Host "`nNombre: $($used.Count)" -ForegroundColor Green
        foreach($n in $used){
            Write-Host "  |-- $n" -ForegroundColor Green
            Write-Host "  |   $($SG[$n]['Line'])" -ForegroundColor White
            Write-Host "  |   Binde sur:" -ForegroundColor DarkGray
            foreach($b in $BSG[$n]){
                Write-Host "  |     * LB vServer: $($b['VServer'])" -ForegroundColor Cyan
                Write-Host "  |       $($b['Line'])" -ForegroundColor White
            }
            if($M.ContainsKey($n)){Write-Host "  |   Membres: $($M[$n].Count)" -ForegroundColor DarkGray}
        }
    }
}

function Show-UsedServices { 
    param([hashtable]$S,[hashtable]$BSvc,[hashtable]$MB)
    Write-Host "`n==================================================================" -ForegroundColor Green
    Write-Host " SERVICES UTILISES" -ForegroundColor Green -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Green
    $used=@(); foreach($n in ($S.Keys|Sort-Object)){if($BSvc.ContainsKey($n)){$used+=$n}}
    if($used.Count -eq 0){Write-Host "`nAucun service utilise !" -ForegroundColor Yellow}
    else{
        Write-Host "`nNombre: $($used.Count)" -ForegroundColor Green
        foreach($n in $used){
            Write-Host "  |-- $n" -ForegroundColor Green
            Write-Host "  |   $($S[$n]['Line'])" -ForegroundColor White
            Write-Host "  |   Binde sur:" -ForegroundColor DarkGray
            foreach($b in $BSvc[$n]){
                Write-Host "  |     * LB vServer: $($b['VServer'])" -ForegroundColor Cyan
                Write-Host "  |       $($b['Line'])" -ForegroundColor White
            }
            $mf=$false
            foreach($mn in $MB.Keys){foreach($svc in $MB[$mn]['Services']){if($svc['Name'] -eq $n){Write-Host "  |   Monitor: $mn" -ForegroundColor Yellow; $mf=$true}}}
            if(-not $mf){Write-Host "  |   Monitor: tcp-default (implicite)" -ForegroundColor DarkYellow}
        }
    }
}

function Show-UsedMonitors { 
    param([hashtable]$M,[hashtable]$UM)
    Write-Host "`n==================================================================" -ForegroundColor Green
    Write-Host " MONITORS UTILISES" -ForegroundColor Green -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Green
    $used=@(); foreach($n in ($M.Keys|Sort-Object)){if($UM.ContainsKey($n)){$used+=$n}}
    if($used.Count -eq 0){Write-Host "`nAucun monitor utilise !" -ForegroundColor Yellow}
    else{
        Write-Host "`nNombre: $($used.Count)" -ForegroundColor Green
        foreach($n in $used){
            Write-Host "  |-- $n" -ForegroundColor Green
            Write-Host "  |   $($M[$n]['Line'])" -ForegroundColor White
            Write-Host "  |   Binde sur:" -ForegroundColor DarkGray
            foreach($u in $UM[$n]){
                Write-Host "  |     * $($u['Type']): $($u['Name'])" -ForegroundColor Cyan
                Write-Host "  |       $($u['Line'])" -ForegroundColor White
            }
        }
    }
}

# MAIN
Clear-Host
Write-Host "`n=== Analyse Load Balancing NetScaler v1.0 ===" -ForegroundColor Yellow
Write-Host "=== Monitor -> Service -> ServiceGroup -> LB vServer ===" -ForegroundColor DarkGray

if(-not (Test-Path $NS_CONF_PATH)){Write-Host "[ERREUR] Fichier introuvable: $NS_CONF_PATH" -ForegroundColor Red; exit 1}

Write-Host "`n[INFO] Chargement: $NS_CONF_PATH" -ForegroundColor Cyan
$lines = Get-Content -Path $NS_CONF_PATH -Encoding UTF8
Write-Host "[INFO] $($lines.Count) lignes chargees" -ForegroundColor Green

Write-Host "`n[ETAPE 1] Extraction des objets..." -ForegroundColor Cyan
$lbVS = Get-LBVServers -L $lines
$svcGrp = Get-ServiceGroups -L $lines
$svc = Get-Services -L $lines
$mon = Get-Monitors -L $lines

Write-Host "[ETAPE 2] Analyse des bindings..." -ForegroundColor Cyan
$bndSG = Get-ServiceGroupBindings -L $lines -SG $svcGrp
$bndSvc = Get-ServiceBindingsToVServer -L $lines -S $svc
$sgMembers = Get-ServiceGroupMembers -L $lines
$monBind = Get-MonitorBindings -L $lines

Write-Host "[ETAPE 3] Analyse en cascade des monitors..." -ForegroundColor Cyan
$usedMon = Get-UsedMonitors -MB $monBind -BSG $bndSG -BSvc $bndSvc

# Stats
$uSG=($svcGrp.Keys|Where-Object{-not $bndSG.ContainsKey($_)}).Count
$uSvc=($svc.Keys|Where-Object{-not $bndSvc.ContainsKey($_)}).Count
$uMon=($mon.Keys|Where-Object{-not $usedMon.ContainsKey($_)}).Count

Write-Host "`n==================================================================" -ForegroundColor Cyan
Write-Host "                            RESUME" -ForegroundColor Yellow
Write-Host "==================================================================" -ForegroundColor Cyan
Write-Host "`n  LB vServers:    $($lbVS.Count)" -ForegroundColor White
Write-Host "  ServiceGroups:  $($svcGrp.Count) total | " -NoNewline; Write-Host "$($svcGrp.Count-$uSG) utilises " -NoNewline -ForegroundColor Green; Write-Host "| " -NoNewline; Write-Host "$uSG non utilises" -ForegroundColor Red
Write-Host "  Services:       $($svc.Count) total | " -NoNewline; Write-Host "$($svc.Count-$uSvc) utilises " -NoNewline -ForegroundColor Green; Write-Host "| " -NoNewline; Write-Host "$uSvc non utilises" -ForegroundColor Red
Write-Host "  Monitors:       $($mon.Count) total | " -NoNewline; Write-Host "$($mon.Count-$uMon) utilises " -NoNewline -ForegroundColor Green; Write-Host "| " -NoNewline; Write-Host "$uMon non utilises" -ForegroundColor Red

# Commandes de suppression
$tot=$uSG+$uSvc+$uMon
if($tot -gt 0){
    Write-Host "`n==================================================================" -ForegroundColor Yellow
    Write-Host " COMMANDES DE SUPPRESSION (dans l'ordre)" -ForegroundColor Yellow -BackgroundColor Black
    Write-Host "==================================================================" -ForegroundColor Yellow
    Write-Host "`n# 1. D'abord les monitors" -ForegroundColor DarkGray
    foreach($n in ($mon.Keys|Sort-Object)){if(-not $usedMon.ContainsKey($n)){Write-Host "rm lb monitor $n"}}
    Write-Host "`n# 2. Ensuite les services" -ForegroundColor DarkGray
    foreach($n in ($svc.Keys|Sort-Object)){if(-not $bndSvc.ContainsKey($n)){Write-Host "rm service $n"}}
    Write-Host "`n# 3. Puis les service groups" -ForegroundColor DarkGray
    foreach($n in ($svcGrp.Keys|Sort-Object)){if(-not $bndSG.ContainsKey($n)){Write-Host "rm serviceGroup $n"}}
}

# Details par type - ROUGE puis VERT
Show-UnusedServiceGroups -SG $svcGrp -BSG $bndSG
Show-UsedServiceGroups -SG $svcGrp -BSG $bndSG -M $sgMembers

Show-UnusedServices -S $svc -BSvc $bndSvc
Show-UsedServices -S $svc -BSvc $bndSvc -MB $monBind

Show-UnusedMonitors -M $mon -UM $usedMon -MB $monBind
Show-UsedMonitors -M $mon -UM $usedMon

Write-Host "`n==================================================================" -ForegroundColor Cyan
Write-Host "Analyse terminee" -ForegroundColor Cyan