Netscaler server removal automation using powershell and RestAPI

Here we have a script (tested on powershell v3 running on server 2k8 as a scheduled task) that I wrote for a client to disable a server in a load balancer at a certain time for IIS app pool recycles, then to warm the websites up by hitting a list of URLs and emailing on failure. This script talks to the server via the NITRO API that the Citrix Netscaler implements.

What this script does not yet do is check for which netscaler is active in a cluster, nor does it work by disabling individual services at this time, but by the server (based on clients needs). It also doesn’t make sure that the server is a member of the particular VIP that you are checking, so beware if you have multiple VIPS.

Feel free to use parts of this script or the entire thing, modified as needed for your organization.

#VERSION 1.3
#Trey Smith
#trey@avari.tech
#ns-serverManipulate -env [development|production] -server [server] -action [ENABLE|DISABLE]

#note: only 2 environments are on here now. can be updated as needed. 


#FIXME:
#CHECK THAT EVERYTHING IS UP OR DOWN BEFORE CALLING IT A DAY
#POSSIBLY DO IT VIA SERVICE VS SERVER
#MAKE SURE SERVERS SERVICES BELONG TO THE VIP THAT YOU'RE CHECKING



 param (
 [string]$env = "development",
 [string]$server,
 [string]$action
 )


 ##################CONFIGURE PRIOR TO PROD####################
 $errorEmail = "" #email to send to if there is an error
 
 #$server = "server" 
 $mailServer = "" #your SMTP host. Not configured for authentication 

 $fromEmail = "" # rcpt from
 $environment = $env.ToString()
##############################################################
#ERROR CHECKING
if ($action -ne "enable" -and $action -ne "disable"){
    write-host "INCORRECTION ACTION, must be enable or disable. format ns-serverManipulate -env [development|production] -server [server] -action [ENABLE|DISABLE]"
    exit
}
if ($environment -ne "production" -and $environment -ne "development"){
    write-host "INCORRECTION ACTION, must be development or production. format ns-serverManipulate -env [development|production] -server [server] -action [ENABLE|DISABLE]"
    exit
}
$currTime = get-date -format F


 #FIXME: check for active netscaler
 #ENVIRONMENT SPECIFIC###### UPDATE FOR BOTH ENVIRONMNETS!!!!!!!
 if ($environment -eq "development"){
     $hostname = "my-netscaler" 
     $username = "my-operator-account" #dev
     $password = "my-pass" #dev
 
     $VIP_HTTP = "VIP_web_http" #VIP name for HTTP (DEV)
     $VIP_HTTPS = "VIP_web_https" #VIP name for HTTPS 
 }


 #fixme FIX THE WHOLE PROD SECTION###################
  if ($environment -eq "production"){
     $hostname = "" 
     $username = "" 
     $password = "" 
     $VIP_HTTP = "VIP_web_http" #VIP name for HTTP 
     $VIP_HTTPS = "VIP_web_https" #VIP name for HTTPS 
 }
 #fixme FIX THE WHOLE PROD SECTION###################




 $warmupURLS = "https://$server/",`
    "https://$server/store",`

$warmupTimes = @("URL,Total Seconds `n")


Send-MailMessage -From $fromEmail -to $errorEmail  -subject "AUTO-SERVER SCRIPT STARTING RUNNING" -SmtpServer $mailServer -body "(THIS EMAIL IS FROM THE AUTOMATED SCRIPT) ARGUMENTS are $action $environment $server`n CURRENT TIME IS $currTime"
 
 #fixme set enable or disable arguments to call whichever function
 #$response = ""#fixme delete this later for parsing


# Ignore Cert Errors
#[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } #from Carl, but for some reason, this appears to be what it takes:
###############################TRUST ALL CERTS###################################
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

#################################################################################

#FUNCTIONS ARE CALLED AT THE BOTTOM OF THE SCRIPT#################################
function Login {

    # Login to NetScaler and save session to global variable

    $body = ConvertTo-JSON @{

        "login"=@{

            "username"="$username";

            "password"="$password"

            }

        }
    
        try{Invoke-RestMethod -uri "$hostname/nitro/v1/config/login" -body $body -SessionVariable NSSession -ContentType "application/vnd.com.citrix.netscaler.login+json" -Method POST}
        catch{#write-host "invoke-restmethod failed to $hostname $VIP_HTTP error message is $_"; 
                HandleError("error connecting to Netscaler invoke-restmethod failed to $hostname $VIP_HTTP error message is $_")
            }


    $Script:NSSession = $local:NSSession

}

function Enable {

# disable server

    $body = ConvertTo-JSON @{
    "server"=@{
        "name"=$server
        
        }
    }
   # $body
   try{Invoke-RestMethod -uri "$hostname/nitro/v1/config/server?action=enable" -body $body -WebSession $NSSession -ContentType "application/json" -Method POST}
   catch{#write-host "invoke-restmethod failed to $hostname $VIP_HTTP error message is $_"; 
            HandleError("error connecting to Netscaler invoke-restmethod failed to $hostname $VIP_HTTP error message is $_")
        }

  
} #fixme: add error cehcking for anything other than 200

function Disable {

# disable server

    $body = ConvertTo-JSON @{
    "server"=@{
        "name"=$server;
        "graceful"="YES"
        }
    }
   # $body
   try{Invoke-RestMethod -uri "$hostname/nitro/v1/config/server?action=disable" -body $body -WebSession $NSSession -ContentType "application/json" -Method POST}
   catch{#write-host "invoke-restmethod failed to $hostname $VIP_HTTP error message is $_"; 
            HandleError("error connecting to Netscaler invoke-restmethod failed to $hostname $VIP_HTTP error message is $_")
        }
    #Invoke-RestMethod -uri "$hostname/nitro/v1/config/login" -body $body -SessionVariable NSSession -ContentType "application/vnd.com.citrix.netscaler.logout+json" -Method POST

    #$Script:NSSession = $local:NSSession
} #fixme: add error cehcking for anything other than 200

function Logout {

# Logout

    $body = ConvertTo-JSON @{
    "logout"=@{}
    }
   # $body
   try{Invoke-RestMethod -uri "$hostname/nitro/v1/config/logout" -body $body -WebSession $NSSession -ContentType "application/vnd.com.citrix.netscaler.logout+json" -Method POST}
   catch{#write-host "invoke-restmethod failed to $hostname $VIP_HTTP error message is $_"; 
            Send-MailMessage -From $fromEmail -to $errorEmail  -subject "AUTO-SERVER REMOVAL SCRIPT FAILED" -SmtpServer $mailServer -body "LOGOUT FAILED"
            exit
        }
    if ($action -eq "disable"){
        Send-MailMessage -From $fromEmail -to $errorEmail  -subject "AUTO-SERVER SCRIPT COMPLETED SUCCESSFULLY" -SmtpServer $mailServer -body "ARGUMENTS are $action $environment $server `n CURRENT TIME IS $currTime"
    }
    if ($action -eq "enable"){
        Send-MailMessage -From $fromEmail -to $errorEmail  -subject "AUTO-SERVER SCRIPT COMPLETED SUCCESSFULLY" -SmtpServer $mailServer -body "ARGUMENTS are $action $environment $server `n URL RESULTS ARE $warmupTimes CURRENT TIME IS $currTime"
        
    }
    $Script:NSSession = $local:NSSession
}

function SanityCheck{
    #fixme: see if actually disabled first. 
    #fixme: See if exist in VIP
   try{$response = Invoke-RestMethod -uri "$hostname/nitro/v1/config/lbvserver/$VIP_HTTPS" -WebSession $NSSession -ContentType "application/vnd.com.citrix.lbvserver_list+json" -Method GET}
   catch{#write-host "invoke-restmethod failed to $hostname $VIP_HTTP error message is $_"; 
            HandleError("error connecting to Netscaler invoke-restmethod failed to $hostname $VIP_HTTP error message is $_")
        }#$response.lbvserver

   $activeServices = $response.lbvserver.activeservices
   $totalservices = $response.lbvserver.totalservices
   #$activeServices;$totalservices
   
    if ($totalservices -gt $activeServices){HandleError("ONE OR MORE SERVERS ARE ALREADY DISABLED - $VIP_HTTPS VIP")}
        #get servers in VIP
        #if any disabled, stop, throw error or email! Exit script
        try{$response = Invoke-RestMethod -uri "$hostname/nitro/v1/config/lbvserver/$VIP_HTTP" -WebSession $NSSession -ContentType "application/vnd.com.citrix.lbvserver_list+json" -Method GET}
        catch{#write-host "invoke-restmethod failed to $hostname $VIP_HTTP error message is $_"; 
            HandleError("error connecting to Netscaler invoke-restmethod failed to $hostname $VIP_HTTP error message is $_")
        }
        $activeServices = $response.lbvserver.activeservices
        $totalservices = $response.lbvserver.totalservices
   
   if ($totalservices -gt $activeServices){HandleError("ONE OR MORE SERVERS ARE ALREADY DISABLED")}
}
function Warmup{

    foreach ($url in $warmupURLS){#Invoke-WebRequest -URI $url -method GET
        try{start-sleep 1
        write-host $url

        $result = measure-command{Invoke-WebRequest -URI $url -Method GET -TimeoutSec 200}

        $script:warmupTimes += "$url," + $result.TotalSeconds.ToString() + "`n"
        
        }catch{HandleError("ERROR WITH WARMUP ON $server")} 


    
    
    } 
}
function HandleError($description){
    $dateTime = Get-Date
    write-Host "SCRIPT STOPPING DUE TO $description"
       Send-MailMessage -From $fromEmail -to $errorEmail  -subject "AUTO-SERVER REMOVAL SCRIPT FAILED" -SmtpServer $mailServer -body "$environment $description $dateTime CURRENT TIME IS $currTime"
   Logout
   exit

}

#BEGIN CALLING FUNCTIONS. 
Login
if ($action -eq "disable"){
    SanityCheck #check to make sure no disabled servers
    Disable #disable the server
}
if ($action -eq "enable"){
    #check if actually disabled fixme    
    Warmup
    start-sleep 1
    Enable

    }

Logout

Leave a Reply

Your email address will not be published. Required fields are marked *