#Requires -Version 5.1 <# .SYNOPSIS NetScaler NITRO API Configuration Extractor Connects live to a NetScaler ADC via the NITRO REST API and extracts configuration objects similar to the file-based extractor. .DESCRIPTION Prompts for NSIP, Username, and Password, authenticates via NITRO, then lets you select a vServer and extracts all dependent objects (services, monitors, policies, SSL certs, auth actions, etc.). .PARAMETER nsip IP or FQDN of the NetScaler management interface. Prompted if not supplied. .PARAMETER username NetScaler admin username. Prompted if not supplied. .PARAMETER password NetScaler admin password as SecureString. Prompted if not supplied. .PARAMETER vserver Partial or full vServer name to filter. Leave blank to list all. .PARAMETER outputFile Path to save extracted config. "screen" to print only. Prompted if blank. .PARAMETER textEditor Text editor to open output file after extraction. .PARAMETER useSSL Use HTTPS (default). Set to $false to use HTTP (not recommended). .PARAMETER skipCertCheck Skip SSL certificate validation (useful for self-signed certs on lab appliances). .PARAMETER nFactorNestingLevel How many nFactor Next Factor levels to traverse (default 5). .NOTES Change Log ---------- 2025 Mar - Initial release based on NITRO API v2 (NetScaler 12.x / 13.x / 14.x) Supports: lb, cs, vpn, authentication, gslb vServers Supports: services, serviceGroups, monitors, servers Supports: SSL certs/profiles/ciphers/policies Supports: rewrite, responder, appfw, cmp, cache, transform policies Supports: AAA / nFactor (ldap, radius, saml, cert, tacacs, oauth, etc.) Supports: GSLB sites/services Supports: System settings (features, modes, HA, IPs, routes, DNS) #> param ( [string] $nsip = "", [string] $username = "", [securestring] $password = $null, [string] $vserver = "", [string] $outputFile = "$env:USERPROFILE\Downloads\nsnitro_config.conf", [string] $textEditor = "notepad++.exe", [bool] $useSSL = $true, [switch] $skipCertCheck, [switch] $cswBind, [int] $nFactorNestingLevel = 5 ) Set-StrictMode -Off $ErrorActionPreference = "Stop" # ───────────────────────────────────────────────────────────────────────────── # TLS / Cert helpers # ───────────────────────────────────────────────────────────────────────────── if ($skipCertCheck) { if ($PSVersionTable.PSVersion.Major -ge 6) { # PowerShell Core / 7+ $script:InvokeParams = @{ SkipCertificateCheck = $true } } else { # Windows PowerShell 5.x – add a permissive policy once if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) { Add-Type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ } [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy $script:InvokeParams = @{} } } else { $script:InvokeParams = @{} } [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls13 # ───────────────────────────────────────────────────────────────────────────── # Prompt helpers # ───────────────────────────────────────────────────────────────────────────── function Prompt-Input ([string]$Prompt, [string]$Default = "") { $val = Read-Host $Prompt if (-not $val -and $Default) { return $Default } return $val } function Get-OutputFilePath { if ($IsMacOS) { $f = (('tell application "SystemUIServer"' + "`n" + 'activate' + "`n" + 'set theName to POSIX path of (choose file name default name "nsnitro_config.conf" with prompt "Save extracted config as")' + "`n" + 'end tell' | osascript -s s) -split '"')[1] return $f } [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $d = New-Object System.Windows.Forms.SaveFileDialog $d.Title = "Save Extracted NetScaler Config" $d.Filter = "NetScaler Config (*.conf)|*.conf|All files (*.*)|*.*" $d.ShowDialog() | Out-Null return $d.FileName } # ───────────────────────────────────────────────────────────────────────────── # Credential / connection setup # ───────────────────────────────────────────────────────────────────────────── cls Write-Host "╔══════════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ NetScaler NITRO API Configuration Extractor ║" -ForegroundColor Cyan Write-Host "╚══════════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" if (-not $nsip) { $nsip = Prompt-Input "Enter NetScaler Management IP or FQDN" } if (-not $username) { $username = Prompt-Input "Enter Username" "nsroot" } if (-not $password) { $password = Read-Host "Enter Password" -AsSecureString } $proto = if ($useSSL) { "https" } else { "http" } $baseUrl = $proto + "://" + $nsip + "/nitro/v1" $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) $plainPwd = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) # Session cookie store $script:Session = $null # ───────────────────────────────────────────────────────────────────────────── # NITRO Helper Functions # ───────────────────────────────────────────────────────────────────────────── function Invoke-Nitro { param( [string] $Method = "GET", [string] $Resource, [string] $Action = "", [object] $Body = $null, [hashtable] $Query = @{} ) $uri = "$baseUrl/config/$Resource" if ($Query.Count -gt 0) { $qs = ($Query.GetEnumerator() | ForEach-Object { "$($_.Key)=$([uri]::EscapeDataString($_.Value))" }) -join "&" $uri += "?$qs" } if ($Action) { $uri += "?action=$Action" } $headers = @{ "Content-Type" = "application/json" } if ($script:AuthToken) { $headers["Cookie"] = "NITRO_AUTH_TOKEN=$($script:AuthToken)" } $splat = @{ Uri = $uri Method = $Method Headers = $headers WebSession = $script:Session UseBasicParsing = $true } + $script:InvokeParams if ($Body) { $splat["Body"] = ($Body | ConvertTo-Json -Depth 10 -Compress) } try { $resp = Invoke-WebRequest @splat $json = $resp.Content | ConvertFrom-Json return $json } catch { $msg = $_.Exception.Message if ($_.Exception.Response) { try { $stream = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($stream) $errBody = $reader.ReadToEnd() | ConvertFrom-Json $msg = "NITRO Error $($errBody.errorcode): $($errBody.message)" } catch {} } Write-Warning "NITRO call failed [$Method $Resource]: $msg" return $null } } function Get-NitroObjects { param( [string] $Resource, [string] $Filter = "", [string[]] $Attrs = @(), [int] $PageSize = 0 ) $query = @{} if ($Filter) { $query["filter"] = $Filter } if ($Attrs) { $query["attrs"] = ($Attrs -join ",") } if ($PageSize -gt 0) { $query["count"] = "yes" } $result = Invoke-Nitro -Method GET -Resource $Resource -Query $query if (-not $result) { return @() } # The resource name is the key in the response object $key = $Resource -replace "/.*","" # strip any sub-resource path if ($result.PSObject.Properties[$key]) { return @($result.$key) } return @() } function Get-NitroBinding { param([string]$Resource, [string]$Name, [string]$BindType) $enc = [uri]::EscapeDataString($Name) $path = "${Resource}/${enc}" if ($BindType) { $path += "?type=$BindType" } $result = Invoke-Nitro -Method GET -Resource $path if (-not $result) { return @() } $key = ($Resource -replace "/.*","") + "_binding" if ($result.PSObject.Properties[$key]) { return @($result.$key) } # some bindings return the type directly $key2 = ($Resource -replace "/.*","") + "_" + $BindType + "_binding" if ($result.PSObject.Properties[$key2]) { return @($result.$key2) } return @() } # ───────────────────────────────────────────────────────────────────────────── # Login # ───────────────────────────────────────────────────────────────────────────── Write-Host "`nConnecting to $baseUrl ..." -ForegroundColor Yellow $loginBody = @{ login = @{ username = $username password = $plainPwd timeout = 3600 } } # Use SessionVariable to capture cookies $loginUri = "$baseUrl/config/login" $loginHeaders = @{ "Content-Type" = "application/json" } $loginSplat = @{ Uri = $loginUri Method = "POST" Headers = $loginHeaders Body = ($loginBody | ConvertTo-Json -Compress) SessionVariable = "webSession" UseBasicParsing = $true } + $script:InvokeParams try { $loginResp = Invoke-WebRequest @loginSplat $script:Session = $webSession $loginJson = $loginResp.Content | ConvertFrom-Json # Some versions return a token, others just use the session cookie if ($loginJson.PSObject.Properties["login"]) { $script:AuthToken = $loginJson.login.sessionid } Write-Host "✔ Login successful." -ForegroundColor Green } catch { Write-Host "✘ Login failed: $($_.Exception.Message)" -ForegroundColor Red exit 1 } $plainPwd = $null # clear plain-text password from memory # ───────────────────────────────────────────────────────────────────────────── # Output helpers # ───────────────────────────────────────────────────────────────────────────── $script:outputLines = [System.Collections.Generic.List[string]]::new() function Out-Line ([string]$line) { $script:outputLines.Add($line) } function Out-Section ([string]$title) { Out-Line "" Out-Line "# $title" Out-Line "# $("-" * $title.Length)" } function Write-Output-File { param([string]$path) $content = $script:outputLines -join "`n" # UNIX line endings [IO.File]::WriteAllText($path, $content) Write-Host "`nConfig written to: $path" -ForegroundColor Green } function Format-NitroObject { # Convert a NITRO object (PSCustomObject) into a NetScaler CLI-like line param([string]$Cmd, [object]$Obj) $line = $Cmd foreach ($prop in $Obj.PSObject.Properties) { $val = $prop.Value if ($null -eq $val -or $val -eq "" -or $val -eq 0 -or $val -eq $false) { continue } if ($val -is [array] -and $val.Count -eq 0) { continue } $name = $prop.Name # skip internal / metadata fields if ($name -in @("__count","bindpoint","stateflag","flags","statechangetimesec", "statechangetimelarge","statechangetime","tickssincelaststatechange", "cursynfloodrate","vsvrbindsvcip","vsvrbindsvcport","policysubtype", "curstate","status","monstatcode","monstatparam1","monstatparam2", "monstatparam3","responsetime","riseapbrstatsmsgcode","lbvserver", "nodefaultbindings","translationip","translationmask","weight", "dynamicweight","dbslb","totalrequestbytes","totalresponsebytes", "curclntconnections","cursrvrconnections","surgecount","svrestablishedconn", "requestsinflight","avgsvrtttfb","curpersistencesessions")) { continue } if ($val -is [array]) { $val = $val -join "," } # quote values with spaces if ("$val" -match "\s") { $val = "`"$val`"" } $line += " -$name $val" } return $line } # ───────────────────────────────────────────────────────────────────────────── # Fetch & catalogue all main object types up front (cached hashtable) # ───────────────────────────────────────────────────────────────────────────── Write-Host "`nFetching configuration objects from NetScaler..." -ForegroundColor Yellow $cache = @{} function Fetch-Cache ([string]$Type) { if (-not $cache.ContainsKey($Type)) { $objs = Get-NitroObjects -Resource $Type $cache[$Type] = $objs Write-Host (" Loaded {0,-40} ({1} objects)" -f $Type, $objs.Count) } return $cache[$Type] } # Pre-load common types $types = @( "lbvserver","csvserver","vpnvserver","authenticationvserver","gslbvserver", "service","servicegroup","server","lbmonitor", "sslvserver","sslcertkey","sslprofile","sslcipher","sslpolicy","sslaction", "rewritepolicy","rewriteaction","rewritepolicylabel", "responderpolicy","responderaction","responderpolicylabel", "cspolicy","csaction","cspolicylabel", "appfwpolicy","appfwprofile","appfwpolicylabel", "cmppolicy","cmpaction","cmppolicylabel", "cachepolicy","cachecontentgroup","cacheselector","cachepolicylabel", "transformpolicy","transformaction","transformprofile","transformpolicylabel", "authenticationldapaction","authenticationldappolicy", "authenticationradiusaction","authenticationradiuspolicy", "authenticationsamlaction","authenticationsamlpolicy", "authenticationcertaction","authenticationcertpolicy", "authenticationtacacsaction","authenticationtacacspolicy", "authenticationpolicy","authenticationpolicylabel","authenticationloginschemapolicy", "authenticationloginschema","authenticationauthnprofile", "vpnsessionpolicy","vpnsessionaction","vpntrafficpolicy","vpntrafficaction", "tmsessionpolicy","tmsessionaction","tmtrafficpolicy","tmtrafficaction", "vpnclientlessaccesspolicy","vpnclientlessaccessprofile", "authorizationpolicy","authorizationpolicylabel", "auditsyslogpolicy","auditsyslogaction","auditnslogpolicy","auditnslogaction", "netprofile","nshttpprofile","nstcpprofile","dnssuffix","dnsprofile","dnsview", "gslbsite","gslbservice","nslimitidentifier","nslimitselector", "nsacl","route","nsip","vlan","interface","haparam","hanode","nsfeature","nsmode", "systemparameter","systemuser","systemgroup" ) foreach ($t in $types) { $null = Fetch-Cache $t } Write-Host "`n✔ Object fetch complete." -ForegroundColor Green # ───────────────────────────────────────────────────────────────────────────── # vServer selection # ───────────────────────────────────────────────────────────────────────────── Write-Host "" # Collect all vServers from all types $allVServers = @() foreach ($vsType in @("lbvserver","csvserver","vpnvserver","authenticationvserver","gslbvserver")) { foreach ($vs in $cache[$vsType]) { $allVServers += [PSCustomObject]@{ Type = $vsType Name = $vs.name VIP = if ($vs.PSObject.Properties["ipv46"]) { $vs.ipv46 } elseif ($vs.PSObject.Properties["ip"]) { $vs.ip } else { "" } Port = if ($vs.PSObject.Properties["port"]) { $vs.port } else { "" } Protocol = if ($vs.PSObject.Properties["servicetype"]) { $vs.servicetype } else { "" } State = if ($vs.PSObject.Properties["curstate"]) { $vs.curstate } else { "" } } } } # Filter by $vserver if provided if ($vserver) { $filtered = $allVServers | Where-Object { $_.Name -match [regex]::Escape($vserver) } } else { $filtered = $allVServers } if ($filtered.Count -eq 0) { Write-Host "No vServers found matching '$vserver'." -ForegroundColor Red exit 1 } # Add System Settings option $sysOption = [PSCustomObject]@{ Type = "sys"; Name = "** System Settings **"; VIP = ""; Port = ""; Protocol = ""; State = "" } $selectionList = @($sysOption) + ($filtered | Sort-Object Type, Name) Write-Host "Select Virtual Server(s) to extract:`n" if ($IsMacOS) { $names = $selectionList | ForEach-Object { $_.Name.Trim('"') } $vsRaw = (('tell application "SystemUIServer"' + "`n" + 'activate' + "`n" + 'set vserver to (choose from list {"' + ($names -join '","') + '"} with prompt "Cmd+Select Multiple vServers" with multiple selections allowed)' + "`n" + 'end tell' | osascript -s s) -replace ', ',',') $selectedNames = [regex]::Matches($vsRaw,'(?:([\w\s\.\*\-]+))') | ForEach-Object { $_.Value } $selectedVServers = $selectionList | Where-Object { $selectedNames -contains $_.Name.Trim('"') } } else { $selectedVServers = $selectionList | Out-GridView -Title "Ctrl+Select Multiple Virtual Servers to extract" -PassThru } if (-not $selectedVServers) { Write-Host "No selection made. Exiting." -ForegroundColor Yellow; exit 0 } # ───────────────────────────────────────────────────────────────────────────── # Output file prompt # ───────────────────────────────────────────────────────────────────────────── if (-not $outputFile) { $outputFile = Get-OutputFilePath } if (-not $outputFile) { $outputFile = "screen" } # ───────────────────────────────────────────────────────────────────────────── # Extraction Engine # ───────────────────────────────────────────────────────────────────────────── # Lookup helpers – find object in cache by name function Get-ObjectByName ([string]$Type, [string]$Name) { return $cache[$Type] | Where-Object { $_.name -eq $Name } } function Get-BindingsFor ([string]$BindResource, [string]$Name) { # e.g. BindResource = "lbvserver_service_binding" Name = "vs1" $enc = [uri]::EscapeDataString($Name) $result = Invoke-Nitro -Method GET -Resource "${BindResource}/${enc}" if (-not $result) { return @() } if ($result.PSObject.Properties[$BindResource]) { return @($result.$BindResource) } return @() } # ── Write object config lines ───────────────────────────────────────────────── function Write-ObjectSection ([string]$Header, [string]$Type, [string[]]$Names, [string]$ExplainText="") { if (-not $Names -or $Names.Count -eq 0) { return } $uniqueNames = $Names | Select-Object -Unique Out-Section $Header foreach ($name in $uniqueNames) { $obj = Get-ObjectByName $Type $name if ($obj) { Out-Line (Format-NitroObject "add $($Type -replace 'vserver','vServer')" $obj) } else { Out-Line "# [not found in cache] $Type $name" } } if ($ExplainText) { Out-Line "# *** $ExplainText" } Out-Line "" } # ── SSL bindings helper ─────────────────────────────────────────────────────── function Get-SSLObjectsForVS ([string]$VSName, [string]$VSType) { # sslvserver bindings $sslBindRes = "${VSType}_sslcertkey_binding" $bindings = Get-BindingsFor $sslBindRes $VSName $certs = @() foreach ($b in $bindings) { if ($b.PSObject.Properties["certkeyname"]) { $certs += $b.certkeyname } } # ssl profile $sslCfg = (Invoke-Nitro -Method GET -Resource "sslvserver/$([uri]::EscapeDataString($VSName))") $profile = "" if ($sslCfg -and $sslCfg.PSObject.Properties["sslvserver"]) { $profile = $sslCfg.sslvserver | Select-Object -First 1 -ExpandProperty sslprofile -ErrorAction SilentlyContinue } return @{ Certs = $certs; Profile = $profile } } # ───────────────────────────────────────────────────────────────────────────── # Per-vServer extraction # ───────────────────────────────────────────────────────────────────────────── $extracted = @{ lbvservers = [System.Collections.Generic.List[string]]::new() csvservers = [System.Collections.Generic.List[string]]::new() vpnvservers = [System.Collections.Generic.List[string]]::new() authvservers = [System.Collections.Generic.List[string]]::new() gslbvservers = [System.Collections.Generic.List[string]]::new() services = [System.Collections.Generic.List[string]]::new() servicegroups = [System.Collections.Generic.List[string]]::new() servers = [System.Collections.Generic.List[string]]::new() monitors = [System.Collections.Generic.List[string]]::new() sslcerts = [System.Collections.Generic.List[string]]::new() sslprofiles = [System.Collections.Generic.List[string]]::new() sslciphers = [System.Collections.Generic.List[string]]::new() sslpolicies = [System.Collections.Generic.List[string]]::new() sslactions = [System.Collections.Generic.List[string]]::new() rewritepolicies = [System.Collections.Generic.List[string]]::new() rewriteactions = [System.Collections.Generic.List[string]]::new() rewritepolicylabels = [System.Collections.Generic.List[string]]::new() responderpolicies = [System.Collections.Generic.List[string]]::new() responderactions = [System.Collections.Generic.List[string]]::new() responderpolicylabels = [System.Collections.Generic.List[string]]::new() cspolicies = [System.Collections.Generic.List[string]]::new() csactions = [System.Collections.Generic.List[string]]::new() cspolicylabels = [System.Collections.Generic.List[string]]::new() appfwpolicies = [System.Collections.Generic.List[string]]::new() appfwprofiles = [System.Collections.Generic.List[string]]::new() cmppolicies = [System.Collections.Generic.List[string]]::new() cachepolicies = [System.Collections.Generic.List[string]]::new() transformpolicies = [System.Collections.Generic.List[string]]::new() transformactions = [System.Collections.Generic.List[string]]::new() transformprofiles = [System.Collections.Generic.List[string]]::new() ldapactions = [System.Collections.Generic.List[string]]::new() ldappolicies = [System.Collections.Generic.List[string]]::new() radiusactions = [System.Collections.Generic.List[string]]::new() radiuspolicies = [System.Collections.Generic.List[string]]::new() samlactions = [System.Collections.Generic.List[string]]::new() samlidppolicies = [System.Collections.Generic.List[string]]::new() certactions = [System.Collections.Generic.List[string]]::new() certpolicies = [System.Collections.Generic.List[string]]::new() tacacsactions = [System.Collections.Generic.List[string]]::new() tacacspolicies = [System.Collections.Generic.List[string]]::new() authpolicies = [System.Collections.Generic.List[string]]::new() authpolicylabels = [System.Collections.Generic.List[string]]::new() loginschemas = [System.Collections.Generic.List[string]]::new() loginschemapolicies = [System.Collections.Generic.List[string]]::new() authnprofiles = [System.Collections.Generic.List[string]]::new() vpnsessionpolicies = [System.Collections.Generic.List[string]]::new() vpnsessionactions = [System.Collections.Generic.List[string]]::new() vpntrafficpolicies = [System.Collections.Generic.List[string]]::new() vpntrafficactions = [System.Collections.Generic.List[string]]::new() auditsyslogpolicies = [System.Collections.Generic.List[string]]::new() auditsyslogactions = [System.Collections.Generic.List[string]]::new() auditnslogpolicies = [System.Collections.Generic.List[string]]::new() auditnslogactions = [System.Collections.Generic.List[string]]::new() authorizationpolicies = [System.Collections.Generic.List[string]]::new() netprofiles = [System.Collections.Generic.List[string]]::new() tcpprofiles = [System.Collections.Generic.List[string]]::new() httpprofiles = [System.Collections.Generic.List[string]]::new() gslbsites = [System.Collections.Generic.List[string]]::new() gslbservices = [System.Collections.Generic.List[string]]::new() doSys = $false } function Add-Unique ([string]$Key, [string]$Value) { if ($Value -and -not $extracted[$Key].Contains($Value)) { $extracted[$Key].Add($Value) } } # ── Pull bindings for an LB vServer ────────────────────────────────────────── function Process-LBvServer ([string]$Name) { Add-Unique "lbvservers" $Name Write-Host " Processing LB vServer: $Name" # Service bindings $svcBinds = Get-BindingsFor "lbvserver_service_binding" $Name foreach ($b in $svcBinds) { if ($b.PSObject.Properties["servicename"]) { $sn = $b.servicename; Add-Unique "services" $sn Process-Service $sn } } # ServiceGroup bindings $sgBinds = Get-BindingsFor "lbvserver_servicegroup_binding" $Name foreach ($b in $sgBinds) { if ($b.PSObject.Properties["servicegroupname"]) { $sg = $b.servicegroupname; Add-Unique "servicegroups" $sg Process-ServiceGroup $sg } } # Policies $polBinds = Get-BindingsFor "lbvserver_rewritepolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-RewritePolicy $b.policyname } } $polBinds = Get-BindingsFor "lbvserver_responderpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-ResponderPolicy $b.policyname } } $polBinds = Get-BindingsFor "lbvserver_appfwpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-AppFWPolicy $b.policyname } } $polBinds = Get-BindingsFor "lbvserver_cmppolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Add-Unique "cmppolicies" $b.policyname } } $polBinds = Get-BindingsFor "lbvserver_transformpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-TransformPolicy $b.policyname } } $polBinds = Get-BindingsFor "lbvserver_auditsyslogpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Add-Unique "auditsyslogpolicies" $b.policyname } } $polBinds = Get-BindingsFor "lbvserver_sslpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-SSLPolicy $b.policyname } } # SSL $ssl = Get-SSLObjectsForVS $Name "lbvserver" foreach ($c in $ssl.Certs) { Add-Unique "sslcerts" $c } if ($ssl.Profile) { Add-Unique "sslprofiles" $ssl.Profile } # Profiles $obj = Get-ObjectByName "lbvserver" $Name if ($obj) { if ($obj.PSObject.Properties["netprofile"] -and $obj.netprofile) { Add-Unique "netprofiles" $obj.netprofile } if ($obj.PSObject.Properties["tcpprofilename"] -and $obj.tcpprofilename) { Add-Unique "tcpprofiles" $obj.tcpprofilename } if ($obj.PSObject.Properties["httpprofilename"] -and $obj.httpprofilename) { Add-Unique "httpprofiles" $obj.httpprofilename } # auth if ($obj.PSObject.Properties["authnvsname"] -and $obj.authnvsname) { Process-AuthVServer $obj.authnvsname } } } function Process-Service ([string]$Name) { $obj = Get-ObjectByName "service" $Name if (-not $obj) { return } if ($obj.PSObject.Properties["servername"] -and $obj.servername) { Add-Unique "servers" $obj.servername } # Monitors $mBinds = Get-BindingsFor "service_lbmonitor_binding" $Name foreach ($b in $mBinds) { if ($b.PSObject.Properties["monitor_name"]) { Add-Unique "monitors" $b.monitor_name } } if ($obj.PSObject.Properties["sslprofile"] -and $obj.sslprofile) { Add-Unique "sslprofiles" $obj.sslprofile } } function Process-ServiceGroup ([string]$Name) { $obj = Get-ObjectByName "servicegroup" $Name if (-not $obj) { return } # Members $mems = Get-BindingsFor "servicegroup_servicegroupmember_binding" $Name foreach ($m in $mems) { if ($m.PSObject.Properties["servername"] -and $m.servername) { Add-Unique "servers" $m.servername } } # Monitors $mBinds = Get-BindingsFor "servicegroup_lbmonitor_binding" $Name foreach ($b in $mBinds) { if ($b.PSObject.Properties["monitor_name"]) { Add-Unique "monitors" $b.monitor_name } } if ($obj.PSObject.Properties["sslprofile"] -and $obj.sslprofile) { Add-Unique "sslprofiles" $obj.sslprofile } } function Process-CSvServer ([string]$Name) { Add-Unique "csvservers" $Name Write-Host " Processing CS vServer: $Name" $polBinds = Get-BindingsFor "csvserver_cspolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policyname"] -and $b.policyname) { Add-Unique "cspolicies" $b.policyname # Get action -> target LB $pol = Get-ObjectByName "cspolicy" $b.policyname if ($pol -and $pol.PSObject.Properties["action"] -and $pol.action) { Add-Unique "csactions" $pol.action $act = Get-ObjectByName "csaction" $pol.action if ($act) { if ($act.PSObject.Properties["targetlbvserver"] -and $act.targetlbvserver) { Process-LBvServer $act.targetlbvserver } if ($act.PSObject.Properties["targetvserver"] -and $act.targetvserver) { # Could be vpn or auth if ($cache["vpnvserver"] | Where-Object { $_.name -eq $act.targetvserver }) { Process-VPNvServer $act.targetvserver } if ($cache["authenticationvserver"] | Where-Object { $_.name -eq $act.targetvserver }) { Process-AuthVServer $act.targetvserver } } } } if ($b.PSObject.Properties["targetlbvserver"] -and $b.targetlbvserver) { Process-LBvServer $b.targetlbvserver } } } # Default LB $obj = Get-ObjectByName "csvserver" $Name if ($obj -and $obj.PSObject.Properties["lbvserver"] -and $obj.lbvserver) { Process-LBvServer $obj.lbvserver } # Policies on the CS vServer itself $polBinds = Get-BindingsFor "csvserver_rewritepolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-RewritePolicy $b.policyname } } $polBinds = Get-BindingsFor "csvserver_responderpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-ResponderPolicy $b.policyname } } $polBinds = Get-BindingsFor "csvserver_auditsyslogpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Add-Unique "auditsyslogpolicies" $b.policyname } } $polBinds = Get-BindingsFor "csvserver_sslpolicy_binding" $Name; foreach ($b in $polBinds) { if ($b.policyname) { Process-SSLPolicy $b.policyname } } $ssl = Get-SSLObjectsForVS $Name "csvserver" foreach ($c in $ssl.Certs) { Add-Unique "sslcerts" $c } if ($ssl.Profile) { Add-Unique "sslprofiles" $ssl.Profile } if ($obj -and $obj.PSObject.Properties["netprofile"] -and $obj.netprofile) { Add-Unique "netprofiles" $obj.netprofile } } function Process-VPNvServer ([string]$Name) { Add-Unique "vpnvservers" $Name Write-Host " Processing VPN/Gateway vServer: $Name" $polBinds = Get-BindingsFor "vpnvserver_vpnsessionpolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-VPNSessionPolicy $b.policy } } $polBinds = Get-BindingsFor "vpnvserver_authenticationldappolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-LDAPPolicy $b.policy } } $polBinds = Get-BindingsFor "vpnvserver_authenticationradiuspolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-RADIUSPolicy $b.policy } } $polBinds = Get-BindingsFor "vpnvserver_authenticationsamlpolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Add-Unique "samlidppolicies" $b.policy } } $polBinds = Get-BindingsFor "vpnvserver_responderpolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-ResponderPolicy $b.policy } } $polBinds = Get-BindingsFor "vpnvserver_rewritepolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-RewritePolicy $b.policy } } $polBinds = Get-BindingsFor "vpnvserver_authenticationpolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-AuthPolicy $b.policy } if ($b.PSObject.Properties["nextfactor"] -and $b.nextfactor) { Process-AuthPolicyLabel $b.nextfactor } } $ssl = Get-SSLObjectsForVS $Name "vpnvserver" foreach ($c in $ssl.Certs) { Add-Unique "sslcerts" $c } if ($ssl.Profile) { Add-Unique "sslprofiles" $ssl.Profile } $obj = Get-ObjectByName "vpnvserver" $Name if ($obj -and $obj.PSObject.Properties["authnprofile"] -and $obj.authnprofile) { Process-AuthnProfile $obj.authnprofile } } function Process-AuthVServer ([string]$Name) { Add-Unique "authvservers" $Name Write-Host " Processing AAA/Auth vServer: $Name" $polBinds = Get-BindingsFor "authenticationvserver_authenticationldappolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-LDAPPolicy $b.policy } } $polBinds = Get-BindingsFor "authenticationvserver_authenticationradiuspolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-RADIUSPolicy $b.policy } } $polBinds = Get-BindingsFor "authenticationvserver_authenticationpolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-AuthPolicy $b.policy } if ($b.PSObject.Properties["nextfactor"] -and $b.nextfactor) { Process-AuthPolicyLabel $b.nextfactor } } $polBinds = Get-BindingsFor "authenticationvserver_authenticationloginschemapolicy_binding" $Name foreach ($b in $polBinds) { if ($b.PSObject.Properties["policy"] -and $b.policy) { Process-LoginSchemaPolicy $b.policy } } $ssl = Get-SSLObjectsForVS $Name "authenticationvserver" foreach ($c in $ssl.Certs) { Add-Unique "sslcerts" $c } if ($ssl.Profile) { Add-Unique "sslprofiles" $ssl.Profile } } function Process-GSLBvServer ([string]$Name) { Add-Unique "gslbvservers" $Name Write-Host " Processing GSLB vServer: $Name" $svcBinds = Get-BindingsFor "gslbvserver_gslbservice_binding" $Name foreach ($b in $svcBinds) { if ($b.PSObject.Properties["servicename"] -and $b.servicename) { Add-Unique "gslbservices" $b.servicename $svc = Get-ObjectByName "gslbservice" $b.servicename if ($svc -and $svc.PSObject.Properties["sitename"] -and $svc.sitename) { Add-Unique "gslbsites" $svc.sitename } } } $ssl = Get-SSLObjectsForVS $Name "gslbvserver" foreach ($c in $ssl.Certs) { Add-Unique "sslcerts" $c } if ($ssl.Profile) { Add-Unique "sslprofiles" $ssl.Profile } } function Process-RewritePolicy ([string]$Name) { Add-Unique "rewritepolicies" $Name $obj = Get-ObjectByName "rewritepolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "rewriteactions" $obj.action } } function Process-ResponderPolicy ([string]$Name) { Add-Unique "responderpolicies" $Name $obj = Get-ObjectByName "responderpolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "responderactions" $obj.action } } function Process-AppFWPolicy ([string]$Name) { Add-Unique "appfwpolicies" $Name $obj = Get-ObjectByName "appfwpolicy" $Name if ($obj -and $obj.PSObject.Properties["profilename"] -and $obj.profilename) { Add-Unique "appfwprofiles" $obj.profilename } } function Process-TransformPolicy ([string]$Name) { Add-Unique "transformpolicies" $Name $obj = Get-ObjectByName "transformpolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "transformactions" $obj.action $act = Get-ObjectByName "transformaction" $obj.action if ($act -and $act.PSObject.Properties["profilename"] -and $act.profilename) { Add-Unique "transformprofiles" $act.profilename } } } function Process-SSLPolicy ([string]$Name) { Add-Unique "sslpolicies" $Name $obj = Get-ObjectByName "sslpolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "sslactions" $obj.action } } function Process-LDAPPolicy ([string]$Name) { Add-Unique "ldappolicies" $Name $obj = Get-ObjectByName "authenticationldappolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "ldapactions" $obj.action } } function Process-RADIUSPolicy ([string]$Name) { Add-Unique "radiuspolicies" $Name $obj = Get-ObjectByName "authenticationradiuspolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "radiusactions" $obj.action } } function Process-AuthPolicy ([string]$Name) { Add-Unique "authpolicies" $Name $obj = Get-ObjectByName "authenticationpolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { $action = $obj.action # Detect action type by searching sub-caches foreach ($atype in @("authenticationldapaction","authenticationradiusaction", "authenticationsamlaction","authenticationcertaction", "authenticationtacacsaction")) { if ($cache[$atype] | Where-Object { $_.name -eq $action }) { switch ($atype) { "authenticationldapaction" { Add-Unique "ldapactions" $action } "authenticationradiusaction" { Add-Unique "radiusactions" $action } "authenticationsamlaction" { Add-Unique "samlactions" $action } "authenticationcertaction" { Add-Unique "certactions" $action } "authenticationtacacsaction" { Add-Unique "tacacsactions" $action } } } } } } function Process-AuthPolicyLabel ([string]$Name) { if ($extracted["authpolicylabels"].Contains($Name)) { return } Add-Unique "authpolicylabels" $Name Write-Host " Processing Auth Policy Label: $Name" $binds = Get-BindingsFor "authenticationpolicylabel_authenticationpolicy_binding" $Name foreach ($b in $binds) { if ($b.PSObject.Properties["policyname"] -and $b.policyname) { Process-AuthPolicy $b.policyname } if ($b.PSObject.Properties["nextfactor"] -and $b.nextfactor) { Process-AuthPolicyLabel $b.nextfactor } } } function Process-LoginSchemaPolicy ([string]$Name) { Add-Unique "loginschemapolicies" $Name $obj = Get-ObjectByName "authenticationloginschemapolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "loginschemas" $obj.action } } function Process-VPNSessionPolicy ([string]$Name) { Add-Unique "vpnsessionpolicies" $Name $obj = Get-ObjectByName "vpnsessionpolicy" $Name if ($obj -and $obj.PSObject.Properties["action"] -and $obj.action) { Add-Unique "vpnsessionactions" $obj.action } } function Process-AuthnProfile ([string]$Name) { Add-Unique "authnprofiles" $Name $obj = Get-ObjectByName "authenticationauthnprofile" $Name if ($obj -and $obj.PSObject.Properties["authnvsname"] -and $obj.authnvsname) { Process-AuthVServer $obj.authnvsname } } # ── Dispatch selected vServers ──────────────────────────────────────────────── Write-Host "`nExtracting configuration for selected vServers..." -ForegroundColor Yellow foreach ($sel in $selectedVServers) { switch ($sel.Type) { "lbvserver" { Process-LBvServer $sel.Name } "csvserver" { Process-CSvServer $sel.Name } "vpnvserver" { Process-VPNvServer $sel.Name } "authenticationvserver" { Process-AuthVServer $sel.Name } "gslbvserver" { Process-GSLBvServer $sel.Name } "sys" { $extracted["doSys"] = $true } } } # ───────────────────────────────────────────────────────────────────────────── # Build Output # ───────────────────────────────────────────────────────────────────────────── Write-Host "`nBuilding output..." -ForegroundColor Yellow $vsNames = ($selectedVServers | Where-Object { $_.Type -ne "sys" } | ForEach-Object { $_.Name }) -join ", " Out-Line "# NetScaler NITRO Config Extract" Out-Line "# NSIP : $nsip" Out-Line "# Extracted : $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" Out-Line "# vServers : $vsNames" Out-Line "" # ── Helper to emit all objects of a type ───────────────────────────────────── function Emit-Objects ([string]$SectionTitle, [string]$CacheType, [string[]]$NameList, [string]$Cmd, [string]$Note="") { if (-not $NameList -or $NameList.Count -eq 0) { return } Out-Section $SectionTitle if ($Note) { Out-Line "# *** $Note" } foreach ($n in ($NameList | Select-Object -Unique)) { $obj = Get-ObjectByName $CacheType $n if ($obj) { Out-Line (Format-NitroObject $Cmd $obj) } else { Out-Line "# [not found in live config] $CacheType $n" } } Out-Line "" } # ── System Settings ─────────────────────────────────────────────────────────── if ($extracted["doSys"]) { Out-Section "System Settings" $sysParam = Invoke-Nitro -Method GET -Resource "systemparameter" if ($sysParam -and $sysParam.PSObject.Properties["systemparameter"]) { Out-Line (Format-NitroObject "set system parameter" $sysParam.systemparameter) } Out-Section "Enabled Features" $features = Invoke-Nitro -Method GET -Resource "nsfeature" if ($features -and $features.PSObject.Properties["nsfeature"]) { $f = $features.nsfeature $enabled = $f.PSObject.Properties | Where-Object { $_.Value -eq "YES" -or $_.Value -eq $true } | ForEach-Object { $_.Name } Out-Line ("enable ns feature " + ($enabled -join " ")) } Out-Section "Enabled Modes" $modes = Invoke-Nitro -Method GET -Resource "nsmode" if ($modes -and $modes.PSObject.Properties["nsmode"]) { $m = $modes.nsmode $enabledM = $m.PSObject.Properties | Where-Object { $_.Value -eq "YES" -or $_.Value -eq $true } | ForEach-Object { $_.Name } Out-Line ("enable ns mode " + ($enabledM -join " ")) } Out-Section "NSIP Addresses" foreach ($ip in $cache["nsip"]) { Out-Line (Format-NitroObject "add ns ip" $ip) } Out-Section "VLANs" foreach ($v in $cache["vlan"]) { Out-Line (Format-NitroObject "add vlan" $v) } Out-Section "Routes" foreach ($r in $cache["route"]) { Out-Line (Format-NitroObject "add route" $r) } Out-Section "HA Nodes" foreach ($h in $cache["hanode"]) { Out-Line (Format-NitroObject "add ha node" $h) } Out-Section "System Users" foreach ($u in $cache["systemuser"]) { Out-Line (Format-NitroObject "add system user" $u) } Out-Section "System Groups" foreach ($g in $cache["systemgroup"]) { Out-Line (Format-NitroObject "add system group" $g) } Out-Section "ACLs" foreach ($a in $cache["nsacl"]) { Out-Line (Format-NitroObject "add ns acl" $a) } Out-Line "" } # ── SSL ─────────────────────────────────────────────────────────────────────── Emit-Objects "SSL Certificates" "sslcertkey" $extracted["sslcerts"] "add ssl certKey" "Certificate files must be present in /nsconfig/ssl" Emit-Objects "SSL Profiles" "sslprofile" $extracted["sslprofiles"] "add ssl profile" Emit-Objects "SSL Policies" "sslpolicy" $extracted["sslpolicies"] "add ssl policy" Emit-Objects "SSL Actions" "sslaction" $extracted["sslactions"] "add ssl action" # ── Networking / Profiles ───────────────────────────────────────────────────── Emit-Objects "Net Profiles" "netprofile" $extracted["netprofiles"] "add netprofile" Emit-Objects "TCP Profiles" "nstcpprofile" $extracted["tcpprofiles"] "add ns tcpProfile" Emit-Objects "HTTP Profiles" "nshttpprofile" $extracted["httpprofiles"] "add ns httpProfile" # ── Servers, Services, Monitors ────────────────────────────────────────────── Emit-Objects "Servers" "server" $extracted["servers"] "add server" Emit-Objects "Monitors" "lbmonitor" $extracted["monitors"] "add lb monitor" Emit-Objects "Services" "service" $extracted["services"] "add service" Emit-Objects "Service Groups" "servicegroup" $extracted["servicegroups"] "add serviceGroup" # ── Rewrite / Responder ─────────────────────────────────────────────────────── Emit-Objects "Rewrite Actions" "rewriteaction" $extracted["rewriteactions"] "add rewrite action" Emit-Objects "Rewrite Policies" "rewritepolicy" $extracted["rewritepolicies"] "add rewrite policy" Emit-Objects "Responder Actions" "responderaction" $extracted["responderactions"] "add responder action" Emit-Objects "Responder Policies" "responderpolicy" $extracted["responderpolicies"] "add responder policy" # ── AppFW ───────────────────────────────────────────────────────────────────── Emit-Objects "AppFW Profiles" "appfwprofile" $extracted["appfwprofiles"] "add appfw profile" "Manually export/import AppFW signatures and XML schema objects" Emit-Objects "AppFW Policies" "appfwpolicy" $extracted["appfwpolicies"] "add appfw policy" # ── Compression ─────────────────────────────────────────────────────────────── Emit-Objects "CMP Policies" "cmppolicy" $extracted["cmppolicies"] "add cmp policy" # ── Transform ───────────────────────────────────────────────────────────────── Emit-Objects "Transform Profiles" "transformprofile" $extracted["transformprofiles"] "add transform profile" Emit-Objects "Transform Actions" "transformaction" $extracted["transformactions"] "add transform action" Emit-Objects "Transform Policies" "transformpolicy" $extracted["transformpolicies"] "add transform policy" # ── CS ──────────────────────────────────────────────────────────────────────── Emit-Objects "CS Actions" "csaction" $extracted["csactions"] "add cs action" Emit-Objects "CS Policies" "cspolicy" $extracted["cspolicies"] "add cs policy" # ── AAA / Authentication ────────────────────────────────────────────────────── Emit-Objects "LDAP Actions" "authenticationldapaction" $extracted["ldapactions"] "add authentication ldapAction" "LDAP CA certs are in /nsconfig/truststore" Emit-Objects "LDAP Policies" "authenticationldappolicy" $extracted["ldappolicies"] "add authentication ldapPolicy" Emit-Objects "RADIUS Actions" "authenticationradiusaction" $extracted["radiusactions"] "add authentication radiusAction" Emit-Objects "RADIUS Policies" "authenticationradiuspolicy" $extracted["radiuspolicies"] "add authentication radiusPolicy" Emit-Objects "SAML Actions" "authenticationsamlaction" $extracted["samlactions"] "add authentication samlAction" Emit-Objects "Cert Actions" "authenticationcertaction" $extracted["certactions"] "add authentication certAction" Emit-Objects "TACACS Actions" "authenticationtacacsaction" $extracted["tacacsactions"] "add authentication tacacsAction" Emit-Objects "TACACS Policies" "authenticationtacacspolicy" $extracted["tacacspolicies"] "add authentication tacacsPolicy" Emit-Objects "Adv Auth Policies" "authenticationpolicy" $extracted["authpolicies"] "add authentication Policy" Emit-Objects "Auth Policy Labels" "authenticationpolicylabel" $extracted["authpolicylabels"] "add authentication policylabel" Emit-Objects "Login Schemas" "authenticationloginschema" $extracted["loginschemas"] "add authentication loginSchema" Emit-Objects "Login Schema Policies" "authenticationloginschemapolicy" $extracted["loginschemapolicies"] "add authentication loginSchemaPolicy" Emit-Objects "Authentication Profiles" "authenticationauthnprofile" $extracted["authnprofiles"] "add authentication authnProfile" # ── VPN Session ─────────────────────────────────────────────────────────────── Emit-Objects "VPN Session Actions" "vpnsessionaction" $extracted["vpnsessionactions"] "add vpn sessionAction" Emit-Objects "VPN Session Policies" "vpnsessionpolicy" $extracted["vpnsessionpolicies"] "add vpn sessionPolicy" Emit-Objects "VPN Traffic Actions" "vpntrafficaction" $extracted["vpntrafficactions"] "add vpn trafficAction" Emit-Objects "VPN Traffic Policies" "vpntrafficpolicy" $extracted["vpntrafficpolicies"] "add vpn trafficPolicy" # ── Audit Syslog ────────────────────────────────────────────────────────────── Emit-Objects "Audit Syslog Actions" "auditsyslogaction" $extracted["auditsyslogactions"] "add audit syslogAction" Emit-Objects "Audit Syslog Policies" "auditsyslogpolicy" $extracted["auditsyslogpolicies"] "add audit syslogPolicy" Emit-Objects "Audit NSLog Actions" "auditnslogaction" $extracted["auditnslogactions"] "add audit nslogAction" Emit-Objects "Audit NSLog Policies" "auditnslogpolicy" $extracted["auditnslogpolicies"] "add audit nslogPolicy" # ── Authorization ───────────────────────────────────────────────────────────── Emit-Objects "Authorization Policies" "authorizationpolicy" $extracted["authorizationpolicies"] "add authorization policy" # ── GSLB ───────────────────────────────────────────────────────────────────── Emit-Objects "GSLB Sites" "gslbsite" $extracted["gslbsites"] "add gslb site" Emit-Objects "GSLB Services" "gslbservice" $extracted["gslbservices"] "add gslb service" # ── Authentication vServers (AAA) ───────────────────────────────────────────── Emit-Objects "Authentication Virtual Servers" "authenticationvserver" $extracted["authvservers"] "add authentication vServer" # ── vServers ────────────────────────────────────────────────────────────────── Emit-Objects "Load Balancing Virtual Servers" "lbvserver" $extracted["lbvservers"] "add lb vServer" Emit-Objects "Content Switching Virtual Servers" "csvserver" $extracted["csvservers"] "add cs vServer" Emit-Objects "Citrix Gateway Virtual Servers" "vpnvserver" $extracted["vpnvservers"] "add vpn vServer" Emit-Objects "GSLB Virtual Servers" "gslbvserver" $extracted["gslbvservers"] "add gslb vServer" # ── vServer bindings (SSL / Policies) ──────────────────────────────────────── Out-Section "SSL Virtual Server Bindings" function Emit-SSLvServerBindings ([string]$VSType, [System.Collections.Generic.List[string]]$VSNames) { foreach ($vsName in ($VSNames | Select-Object -Unique)) { Out-Line "# --- SSL bindings for $VSType $vsName ---" # Cert bindings $cBinds = Get-BindingsFor "${VSType}_sslcertkey_binding" $vsName foreach ($b in $cBinds) { if ($b.PSObject.Properties["certkeyname"] -and $b.certkeyname) { $isCaCert = if ($b.PSObject.Properties["ca"] -and $b.ca) { " -CA" } else { "" } Out-Line "bind ssl $VSType $vsName -certkeyName $($b.certkeyname)$isCaCert" } } # Cipher bindings $cipBinds = Get-BindingsFor "${VSType}_sslciphersuite_binding" $vsName if ($cipBinds.Count -gt 0) { Out-Line "unbind ssl $VSType $vsName -cipherName DEFAULT" foreach ($b in $cipBinds) { if ($b.PSObject.Properties["ciphername"] -and $b.ciphername) { Out-Line "bind ssl $VSType $vsName -cipherName $($b.ciphername)" } } } # SSL profile $sslCfg = Invoke-Nitro -Method GET -Resource "sslvserver/$([uri]::EscapeDataString($vsName))" if ($sslCfg -and $sslCfg.PSObject.Properties["sslvserver"]) { $s = $sslCfg.sslvserver | Select-Object -First 1 if ($s -and $s.PSObject.Properties["sslprofile"] -and $s.sslprofile) { Out-Line "set ssl $VSType $vsName -sslProfile $($s.sslprofile)" } } Out-Line "" } } Emit-SSLvServerBindings "vserver" $extracted["lbvservers"] Emit-SSLvServerBindings "vserver" $extracted["csvservers"] Emit-SSLvServerBindings "vserver" $extracted["vpnvservers"] Emit-SSLvServerBindings "vserver" $extracted["authvservers"] # ── Summary ─────────────────────────────────────────────────────────────────── Out-Section "Extraction Summary" Out-Line "# LB vServers : $($extracted['lbvservers'].Count)" Out-Line "# CS vServers : $($extracted['csvservers'].Count)" Out-Line "# VPN vServers : $($extracted['vpnvservers'].Count)" Out-Line "# Auth vServers : $($extracted['authvservers'].Count)" Out-Line "# GSLB vServers : $($extracted['gslbvservers'].Count)" Out-Line "# Services : $($extracted['services'].Count)" Out-Line "# Service Groups : $($extracted['servicegroups'].Count)" Out-Line "# Servers : $($extracted['servers'].Count)" Out-Line "# Monitors : $($extracted['monitors'].Count)" Out-Line "# SSL Certs : $($extracted['sslcerts'].Count)" Out-Line "# SSL Profiles : $($extracted['sslprofiles'].Count)" Out-Line "# Rewrite Policies : $($extracted['rewritepolicies'].Count)" Out-Line "# Responder Policies : $($extracted['responderpolicies'].Count)" Out-Line "# AppFW Policies : $($extracted['appfwpolicies'].Count)" Out-Line "# Auth Policies (Adv) : $($extracted['authpolicies'].Count)" Out-Line "# LDAP Actions : $($extracted['ldapactions'].Count)" Out-Line "# RADIUS Actions : $($extracted['radiusactions'].Count)" Out-Line "# VPN Session Policies : $($extracted['vpnsessionpolicies'].Count)" # ───────────────────────────────────────────────────────────────────────────── # Write output # ───────────────────────────────────────────────────────────────────────────── if ($outputFile -and $outputFile -ne "screen") { Write-Output-File $outputFile # Try to open in a text editor - resolve full path automatically $editorPath = $null # 1. Check if the param value is already a valid full path or on PATH if ($textEditor) { if (Test-Path $textEditor -PathType Leaf) { $editorPath = $textEditor } elseif (Get-Command $textEditor -ErrorAction SilentlyContinue) { $editorPath = $textEditor } } # 2. Auto-detect Notepad++ in common install locations if (-not $editorPath) { $nppPaths = @( "$env:ProgramFiles\Notepad++\notepad++.exe", "${env:ProgramFiles(x86)}\Notepad++\notepad++.exe", "$env:LOCALAPPDATA\Programs\Notepad++\notepad++.exe" ) foreach ($p in $nppPaths) { if (Test-Path $p -PathType Leaf) { $editorPath = $p; break } } } # 3. Try VS Code if (-not $editorPath) { foreach ($code in @("code","code.cmd")) { if (Get-Command $code -ErrorAction SilentlyContinue) { $editorPath = $code; break } } } # 4. Fall back to built-in Notepad (always present on Windows) if (-not $editorPath -and -not $IsMacOS) { $editorPath = "notepad.exe" } if ($editorPath) { Write-Host "Opening output file with: $editorPath" -ForegroundColor Cyan Start-Process -FilePath $editorPath -ArgumentList "`"$outputFile`"" } else { Write-Host "No text editor found. Output saved to: $outputFile" -ForegroundColor Yellow } } else { $script:outputLines | ForEach-Object { Write-Output $_ } } # ───────────────────────────────────────────────────────────────────────────── # Logout # ───────────────────────────────────────────────────────────────────────────── $logoutBody = @{ logout = @{} } try { Invoke-Nitro -Method POST -Resource "logout" -Body $logoutBody | Out-Null Write-Host "✔ Logged out of NetScaler." -ForegroundColor Green } catch { # non-fatal } Write-Host "`nDone." -ForegroundColor Cyan