Let’s Encrypt Certificates on a NetScaler 60


For a while now it’s possible to use Let’s Encrypt certificates, they are trusted (cross signed), secure and most of all FREE!

There are already a lot of tools available to generate these certificates. I haven’t come across a tool or script to generate these certificates and upload them to a Citrix NetScaler. So I thought why not build it myself. I already tried it in a previous attempt, but I wanted more automation and thus I created this version.

To learn more about the Let’s Encrypt, check how it works..

What my script does in very basic steps (for example you want a certificate for www.domain.com):

Ask LE (Let’s Encrypt) to validate “www.domain.com” (1)

LE returns data (2) among them:

  • URL To check : “http://www.domain.com/.well-known/acme-challenge/34sS6lKqRtmEH6nccSVNF8ifykpA12eVhHz0yvheY0o”
  • Answer string: “34sS6lKqRtmEH6nccSVNF8ifykpA12eVhHz0yvheY0o.3-40nFYEAf5ItpgZuuISW1hg4fNm-vVW3T0R2mdzNkU”.

This returned data will later be used to validate the requested domain. LE will (when you have everything in place) check the URL and expects to find the provided answer. This validation will prove you are the owner of that requested domain.

With the received data we need to configure the Citrix NetScaler (3), for this we will use a responder policy.

The policy will contain a expression:

HTTP.REQ.URL.CONTAINS("well-known/acme-challenge/34sS6lKqRtmEH6nccSVNF8ifykpA12eVhHz0yvheY0o")

and the response (if this policy is true) will be:

"HTTP/1.0 200 OK\r\n\r\n34sS6lKqRtmEH6nccSVNF8ifykpA12eVhHz0yvheY0o.3-40nFYEAf5ItpgZuuISW1hg4fNm-vVW3T0R2mdzNkU"

With this in place we can let LE check the validation (4) & (5) and if all goes well we’ll get a response: “valid”.

And with a valid response we can retrieve the certificate and upload it to the NetScaler!

NOTE: You can not create a wildcard certificate at the moment with the current version of my script, but you can create a SAN certificate. All you need to do is validate each hostname through the previous explained steps. (SAN certificates are a better / more secure than wildcards in my opinion)

To Achieve this a NetScaler Content Switch is used. A requirement for this is that each dns hostname that needs to be validated must have the same pubic IP Address configured to it. That IP Address must point to the NetScaler Content Switch for example via NAT.

The above story visualized:

Certificates are (currently) valid for a period of 90 days. After this period the certificate needs to be renewed. At this moment all the above described steps must be taken again. That’s why I created an automated way to create the certificate. You can schedule it for example to run every 85 days or so. I hope to add some improvements later on.

NOTE: You should use the staging environment for testing, before using the production environment. This will allow you to get things right before issuing trusted certificates and reduce the chance of hitting the rate limits.

There are limits in place, that’s why there is a “staging” (test) environment is available. You can use this server to test and make sure the circle can be completed before you use the Production server to get the “real” (trusted) certificates. These staging certificates are not publicly trusted.

Some rate limits to take into consideration:

  • Certificates per Registered Domain (20 per week).
  • 100 Names per Certificate
  • Duplicate Certificate limit of 5 certificates per week

More info about rate limits can be found here

But enough talked about LE, here are the parameters you need to run this script:

ParameterAliasExample valueRequiredExplanation
-Help-?OptionalDisplay the detailed information about this script
-CleanNSOptionalCleanup the NetScaler configuration made within this script, for when somewhere it gone wrong
-NSManagementURL-URL"http://192.168.100.1"YesManagement URL, used to connect to the NetScaler
-NSUserName-Username or -User"nsroot"Yes*NetScaler username with enough access to configure it
-NSPassword-Password"nsroot"Yes*NetScaler username password
-NSCredential-Credential$(get-credential)Yes*Use a PSCredential object instead of a username or password. Use "Get-Credential" to generate a credential object
-NSCsVipName"cs_domain.com_http"YesName of the HTTP NetScaler Content Switch used for the domain validation
-NSCsVipBinding50OptionalNetScaler Content Switch binding used for the validation
Default: 11
-NSSvcName"svc_letsencrypt_cert_dummy"OptionalNetScaler Load Balance service name
Default "svc_letsencrypt_cert_dummy"
-NSSvcDestination"1.2.3.4"OptionalIP Address used for the NetScaler Service (leave default 1.2.3.4, only change when already used
-NSLbName"lb_letsencrypt_cert"OptionalNetScaler Load Balance VIP name
Default: "lb_letsencrypt_cert"
-NSRspName"rsp_letsencrypt"OptionalNetScaler Responder Policy name
Default: "rsp_letsencrypt"
-NSRsaName"rsa_letsencrypt"OptionalNetScaler Responder Action name
Default: "rsa_letsencrypt"
-NSCspName"csp_NSCertCsp"OptionalNetScaler Content Switch Policy name
Default: "csp_NSCertCsp"
-NSCertNameToUpdate"san_domain.com"OptionalNetScaler SSL Certkey name currently in use, that needs to be renewd
-CertDir"C:\Certificates"YesDirectory where to store the certificates
-PfxPassword"P@ssw0rd"OptionalPassword for the PFX certificate, generated at the end
-EmailAddress"admin@domain.com"YesThe email address used to request the certificates and receive a notification when the certificates (almost) expires
-cn"domain.com"YesCommon Name) The Primary (first) dns record for the certificaten
-san"sts.domain.com","www.domain.com"Optional(Subject Alternate Name) every following domain listed in this certificate. sepatated via an comma , and between quotes "".
E.g.: "sts.domain.com","www.domain.com","vpn.domain.com"
-ProductionOptional**Use the production Let's encryt server
-RemoveTestCertificatesOptionalSpecify this parameter to remove all the staging/test certificates
-DisableIPCheckOptionalIf you want to skip the IP Address verification, specify this parameter
-CleanVaultOptionalForce initialization of the vault before use
-SaveNSConfigOptionalSave the NetScaler config after all the changes.
-ns10xOptionalIf you are using v10 (please upgrade to v11.1 or higher) specify this parameter

* Use the -NSCredential parameter OR -NSUsername & -NSPassword

** Use the -Production switch after you did a successful run of the script. This is to make sure you don’t hit the limit’s of the production servers.

For example, if you want to generate a (Production)certificate for hostname “domain.com” with alternate names : “sts.domain.com, www.domain.com, vpn.domain.com”. Using the emailaddress “hostmaster@domain.com”. And at the end storing the certificates in “C:\Certificates” and uploading them to the NetScaler. Also Cleaning the vault on the NetScaler the content Switch “cs_domain.com_http” will be used to validate the certificates.:

 .\GenLeCertForNS.ps1 -CN "domain.com" `
-EmailAddress "hostmaster@domain.com" `
-SAN "sts.domain.com","www.domain.com","vpn.domain.com" `
-PfxPassword "P@ssw0rd" `
-CertDir "C:\Certificates" `
-NSManagementURL "http://192.168.100.1" `
-NSCsVipName "cs_domain.com_http" `
-NSPassword "P@ssw0rd" `
-NSUserName "nsroot" `
-NSCertNameToUpdate "san_domain_com" `
-Production `
-CleanVault `
-Verbose

If something went wrong during a previous attempt to generate new certificates. You can use for example the following command:

.\GenLeCertForNS.ps1 -CleanNS `
-NSManagementURL "http://192.168.100.1" `
-NSCsVipName "cs_domain.com_http" `
-NSPassword "P@ssw0rd" `
-NSUserName "nsroot" `
-Verbose

And the PowerSchell Script (GenLeCertForNS.ps1), you can also find it on GitHub: https://github.com/j81blog/GenLeCertForNS

<#
.SYNOPSIS
	Create a new or update an existing Let's Encrypt certificate for one or more domains and add it to a store then update the SSL bindings for a NetScaler
.DESCRIPTION
	The script will use ACMESharp to create a new or update an existing certificate for one or more domains. If generated successfully the script will add the certificate to the NetScaler and update the SSL binding for a web site. This script is for use with a Citrix NetScaler (v11.x and up). The script will validate the dns records provided. For example, the domain(s) listed must be configured with the same IP Address that is configured (via NAT) to a Content Switch.
.PARAMETER Help
	Display the detailed information about this script
.PARAMETER CleanNS
	Cleanup the NetScaler configuration made within this script, for when somewhere it gone wrong
.PARAMETER RemoveTestCertificates
	Tries to remove all the Test certificates signed by the "Fake LE Intermediate X1" staging intermediate
.PARAMETER NSManagementURL
	Management URL, used to connect to the NetScaler
.PARAMETER NSUserName
	NetScaler username with enough access to configure it
.PARAMETER NSPassword
	NetScaler username password
.PARAMETER NSCredential
	Use a PSCredential object instead of a username or password. Use "Get-Credential" to generate a credential object
	C:\PS> $Credential = Get-Credential
.PARAMETER NSCsVipName
	Name of the HTTP NetScaler Content Switch used for the domain validation
.PARAMETER NSCsVipBinding
	NetScaler Content Switch binding used for the validation
.PARAMETER NSSvcName
	NetScaler Load Balance service name
.PARAMETER NSSvcDestination
	IP Address used for the NetScaler Service (leave default 1.2.3.4), only change when already used
.PARAMETER NSLbName
	NetScaler Load Balance VIP name
.PARAMETER NSRspName
	NetScaler Responder Policy name
.PARAMETER NSRsaName
	NetScaler Responder Action name
.PARAMETER NSCspName
	NetScaler Content Switch Policy name
.PARAMETER NSCertNameToUpdate
	NetScaler SSL Certkey name currently in use, that needs to be renewd
.PARAMETER CertDir
	Directory where to store the certificates
.PARAMETER PfxPassword
	Password for the PFX certificate, generated at the end
.PARAMETER EmailAddress
	The email address used to request the certificates and receive a notification when the certificates (almost) expires
.PARAMETER cn
	(Common Name) The Primary (first) dns record for the certificaten
.PARAMETER san
	(Subject Alternate Name) every following domain listed in this certificate. sepatated via an comma , and between quotes "".
	E.g.: "sts.domain.com","www.domain.com","vpn.domain.com"
.PARAMETER Production
	Use the production Let's encryt server
.PARAMETER DisableIPCheck
	If you want to skip the IP Address verification, specify this parameter
.PARAMETER CleanVault
	Force initialization of the vault before use
.PARAMETER SaveNSConfig
	Save the NetScaler config after all the changes.
.PARAMETER ns10x
	When using v10x, some nitro functions will not work propperly, run the script with this parameter.
.EXAMPLE
	.\GenLeCertForNS.ps1 -CN "domain.com" -EmailAddress "hostmaster@domain.com" -SAN "sts.domain.com","www.domain.com","vpn.domain.com" -PfxPassword "P@ssw0rd" -CertDir "C:\Certificates" -NSManagementURL "http://192.168.100.1" -NSCsVipName "cs_domain.com_http" -NSPassword "P@ssw0rd" -NSUserName "nsroot" -NSCertNameToUpdate "san_domain_com" -Production -CleanVault -Verbose
	Generate a (Production)certificate for hostname "domain.com" with alternate names : "sts.domain.com, www.domain.com, vpn.domain.com". Using the emailaddress "hostmaster@domain.com". At the end storing the certificates  in "C:\Certificates" and uploading them to the NetScaler. Also Cleaning the vault on the NetScaler the content Switch "cs_domain.com_http" will be used to validate the certificates.
.EXAMPLE
	.\GenLeCertForNS.ps1 -CleanNS -NSManagementURL "http://192.168.100.1" -NSCsVipName "cs_domain.com_http" -NSPassword "P@ssw0rd" -NSUserName "nsroot" -Verbose
	Cleaning left over configuration from this schript when something went wrong during a previous attempt to generate new certificates and generating Verbose output.
.EXAMPLE
	.\GenLeCertForNS.ps1 -RemoveTestCertificates -NSManagementURL "http://192.168.100.1" -NSPassword "P@ssw0rd" -NSUserName "nsroot" -Verbose
	Removing ALL the test certificates from your NetScaler.
.NOTES
	File Name : GenLeCertForNS.ps1
	Version   : v0.9.4
	Author    : John Billekens
	Requires  : PowerShell v3 and up
	            NetScaler 11.x and up
	            Run As Administrator
	            ACMESharp 0.9.1.326 (can be installed via this script)
.LINK
	https://blog.j81.nl
#>

[cmdletbinding(DefaultParametersetName="ConfigNetScaler")]
param(
		[Parameter(ParameterSetName="Help",Mandatory=$false)]
		[alias("h")]
		[switch]$Help,
		
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$true)]
		[switch]$CleanNS,

		[Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
		[alias("RemTestCert")]
		[switch]$RemoveTestCertificates,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$true)]
		[Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		[alias("URL")]
		[string]$NSManagementURL,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
		[alias("User", "Username")]
		[string]$NSUserName,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
		[ValidateScript({
			if ($_ -is [SecureString]) {
				return $true
			} elseif ($_ -is [string]) {
				$Script:NSPassword=ConvertTo-SecureString -String $_ -AsPlainText -Force
				return $true
			} else {
				Write-Error "You passed an unexpected object type for the credential (-NSPassword)"
			}
		})]
		[alias("Password")][object]$NSPassword,

		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
		[ValidateScript({
			if ($_ -is [System.Management.Automation.PSCredential]) {
				return $true
			} elseif ($_ -is [string]) {
				$Script:Credential=Get-Credential -Credential $_
				return $true
			} else {
				Write-Error "You passed an unexpected object type for the credential (-NSCredential)"
			}
		})][alias("Credential")]
		[object]$NSCredential,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		[string]$NSCsVipName,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSCsVipBinding = 11,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSSvcName = "svc_letsencrypt_cert_dummy",
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSSvcDestination = "1.2.3.4",
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSLbName = "lb_letsencrypt_cert",
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSRspName = "rsp_letsencrypt",
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSRsaName = "rsa_letsencrypt",
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[string]$NSCspName = "csp_NSCertCsp",
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[string]$NSCertNameToUpdate,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		[string]$CertDir,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[ValidateScript({
			if (([string]::IsNullOrEmpty($_))) {
				$Script:PfxPassword=$null
				return $true
			} elseif ($_ -is [SecureString]) {
				return $true
			} elseif ($_ -is [string]) {
				$Script:PfxPassword=ConvertTo-SecureString -String $_ -AsPlainText -Force
				return $true
			} else {
				Write-Error "You passed an unexpected object type for the credential (-PfxPassword)"
			}
		})][object]$PfxPassword = $null,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
		[ValidateNotNullOrEmpty()]
		[string]$CN,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
		[string]$EmailAddress,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[string[]]$SAN=@(),
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[switch]$Production,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[switch]$DisableIPCheck,

		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[switch]$CleanVault,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[switch]$SaveNSConfig,
		
		[Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
		[Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
		[switch]$ns10x
)

#requires -version 3.0
#requires -runasadministrator
$ScriptVersion = "v0.9.3"

#region Functions

function InvokeNSRestApi {
	[CmdletBinding()]
	param (
		[Parameter(Mandatory=$true)]
		[PSObject]$Session,

		[Parameter(Mandatory=$true)]
		[ValidateSet('DELETE', 'GET', 'POST', 'PUT')]
		[string]$Method,

		[Parameter(Mandatory=$true)]
		[string]$Type,

		[string]$Resource,

		[string]$Action,

		[hashtable]$Arguments = @{},

		[switch]$Stat = $false,

		[ValidateScript({$Method -eq 'GET'})]
		[hashtable]$Filters = @{},

		[ValidateScript({$Method -ne 'GET'})]
		[hashtable]$Payload = @{},

		[switch]$GetWarning = $false,

		[ValidateSet('EXIT', 'CONTINUE', 'ROLLBACK')]
		[string]$OnErrorAction = 'EXIT'
	)
	# https://github.com/devblackops/NetScaler
	if ([string]::IsNullOrEmpty($($Session.ManagementURL))) {
		throw "ERROR. Probably not logged into the NetScaler"
	}
	if ($Stat) {
		$uri = "$($Session.ManagementURL)/nitro/v1/stat/$Type"
	} else {
		$uri = "$($Session.ManagementURL)/nitro/v1/config/$Type"
	}
	if (-not ([string]::IsNullOrEmpty($Resource))) {
		$uri += "/$Resource"
	}
	if ($Method -ne 'GET') {
		if (-not ([string]::IsNullOrEmpty($Action))) {
			$uri += "?action=$Action"
		}

		if ($Arguments.Count -gt 0) {
			$queryPresent = $true
			if ($uri -like '*?action*') {
				$uri += '&args='
			} else {
				$uri += '?args='
			}
			$argsList = @()
			foreach ($arg in $Arguments.GetEnumerator()) {
				$argsList += "$($arg.Name):$([System.Uri]::EscapeDataString($arg.Value))"
			}
			$uri += $argsList -join ','
		}
	} else {
		$queryPresent = $false
		if ($Arguments.Count -gt 0) {
			$queryPresent = $true
			$uri += '?args='
			$argsList = @()
			foreach ($arg in $Arguments.GetEnumerator()) {
				$argsList += "$($arg.Name):$([System.Uri]::EscapeDataString($arg.Value))"
			}
			$uri += $argsList -join ','
		}
		if ($Filters.Count -gt 0) {
			$uri += if ($queryPresent) { '&filter=' } else { '?filter=' }
			$filterList = @()
			foreach ($filter in $Filters.GetEnumerator()) {
				$filterList += "$($filter.Name):$([System.Uri]::EscapeDataString($filter.Value))"
			}
			$uri += $filterList -join ','
		}
	}
	Write-Verbose -Message "URI: $uri"

	$jsonPayload = $null
	if ($Method -ne 'GET') {
		$warning = if ($GetWarning) { 'YES' } else { 'NO' }
		$hashtablePayload = @{}
		$hashtablePayload.'params' = @{'warning' = $warning; 'onerror' = $OnErrorAction; <#"action"=$Action#>}
		$hashtablePayload.$Type = $Payload
		$jsonPayload = ConvertTo-Json -InputObject $hashtablePayload -Depth 100
		Write-Verbose -Message "JSON Payload:`n$jsonPayload"
	}

	$response = $null
	$restError = $null
	try {
		$restError = @()
		$restParams = @{
			Uri = $uri
			ContentType = 'application/json'
			Method = $Method
			WebSession = $Session.WebSession
			ErrorVariable = 'restError'
			Verbose = $false
		}

		if ($Method -ne 'GET') {
			$restParams.Add('Body', $jsonPayload)
		}

		$response = Invoke-RestMethod @restParams

		if ($response) {
			if ($response.severity -eq 'ERROR') {
				throw "Error. See response: `n$($response | Format-List -Property * | Out-String)"
			} else {
				Write-Verbose -Message "Response:`n$(ConvertTo-Json -InputObject $response | Out-String)"
				if ($Method -eq "GET") { return $response }
			}
		}
	}
	catch [Exception] {
		if ($Type -eq 'reboot' -and $restError[0].Message -eq 'The underlying connection was closed: The connection was closed unexpectedly.') {
			Write-Verbose -Message 'Connection closed due to reboot'
		} else {
			throw $_
		}
	}
}

function Connect-NetScaler {
	[cmdletbinding()]
	param(
		[parameter(Mandatory)]
		[string]$ManagementURL,

		[parameter(Mandatory)]
		[pscredential]$Credential = (Get-Credential -Message 'NetScaler credential'),

		[int]$Timeout = 3600,

		[switch]$PassThru
	)
	# https://github.com/devblackops/NetScaler
	Write-Verbose -Message "Connecting to $ManagementURL..."
	try {
		if ($script:ns10x) {
			$login = @{
				login = @{
					username = $Credential.UserName;
					password = $Credential.GetNetworkCredential().Password
				}
			}
		} else {
			$login = @{
				login = @{
					username = $Credential.UserName;
					password = $Credential.GetNetworkCredential().Password
					timeout = $Timeout
				}
			}
		}
		$loginJson = ConvertTo-Json -InputObject $login
		Write-Verbose "JSON Data:`n$($loginJson | Out-String)"
		$saveSession = @{}
		$params = @{
			Uri = "$ManagementURL/nitro/v1/config/login"
			Method = 'POST'
			Body = $loginJson
			SessionVariable = 'saveSession'
			ContentType = 'application/json'
			ErrorVariable = 'restError'
			Verbose = $false
		}
		$response = Invoke-RestMethod @params

		if ($response.severity -eq 'ERROR') {
			throw "Error. See response: `n$($response | Format-List -Property * | Out-String)"
		} else {
			Write-Verbose -Message "Response:`n$(ConvertTo-Json -InputObject $response | Out-String)"
		}
	} catch [Exception] {
		throw $_
	}
	$session = [PSObject]@{
		ManagementURL=[string]$ManagementURL;
		WebSession=[Microsoft.PowerShell.Commands.WebRequestSession]$saveSession;
		Username=$Credential.UserName;
		Version="UNKNOWN";
	}

	try {
		Write-Verbose -Message "Trying to retreive the NetScaler version"
		$params = @{
			Uri = "$ManagementURL/nitro/v1/config/nsversion"
			Method = 'GET'
			WebSession = $Session.WebSession
			ContentType = 'application/json'
			ErrorVariable = 'restError'
			Verbose = $false
		}
		$response = Invoke-RestMethod @params
		Write-Verbose -Message "Response:`n$(ConvertTo-Json -InputObject $response | Out-String)"
		$version = $response.nsversion.version.Split(",")[0]
		if (-not ([string]::IsNullOrWhiteSpace($version))) {
			$session.version = $version
		}
	} catch {
		Write-Verbose -Message "Error. See response: `n$($response | Format-List -Property * | Out-String)"
	}
	$Script:NSSession = $session
	
	if($PassThru){
		return $session
	}
}

#endregion Functions

#region Help

if($Help){
	Write-Verbose "Generating help for `"$ScriptFilename`""
	Get-Help "$ScriptFilename" -Full
	Exit(0)
}

#endregion Help

#region Script variables

Write-Verbose "Script version: $ScriptVersion"
if ($ns10x){
	Write-Verbose "ns10x parameter used, some options are now disabled."
}
Write-Verbose "Setting session DATE/TIME variable"
[datetime]$ScriptDateTime = Get-Date
[string]$SessionDateTime = $ScriptDateTime.ToString("yyyyMMdd-HHmmss")
[string]$IdentifierDate = $ScriptDateTime.ToString("yyyyMMdd")
Write-Verbose "Session DATE/TIME variable value: `"$SessionDateTime`""

if (-not([string]::IsNullOrWhiteSpace($NSCredential))) {
	Write-Verbose "Using NSCredential"
} elseif ((-not([string]::IsNullOrWhiteSpace($NSUserName))) -and (-not([string]::IsNullOrWhiteSpace($NSPassword)))){
	Write-Verbose "Using NSUsername / NSPassword"
	if (-not ($NSPassword -is [securestring])){
		[securestring]$NSPassword = ConvertTo-SecureString -String $NSPassword -AsPlainText -Force
	}
	[pscredential]$NSCredential = New-Object System.Management.Automation.PSCredential ($NSUserName, $NSPassword)
} else {
	Write-Verbose "No valid username/password or credential specified. Enter a username and password, e.g. `"nsroot`""
	[pscredential]$NSCredential = Get-Credential -Message "NetScaler username and password:"
}
Write-Verbose "Starting new session"
if(-not ([string]::IsNullOrWhiteSpace($SAN))){
	[string[]]$SAN = @($SAN.Split(","))
}

#endregion Script variables

#region Load Module

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Load ACMESharp Modules"
	if (-not(Get-Module ACMESharp)){
		try {
			$ACMEVersions = (get-Module -Name ACMESharp -ListAvailable).Version
			$ACMEUpdateRequired = $false
			ForEach ($ACMEVersion in $ACMEVersions) {
				if (($ACMEVersion.Minor -eq 9) -and ($ACMEVersion.Build -eq 1) -and (-not $ACMEUpdateRequired)) {
					Write-Verbose "v0.9.1 of ACMESharp is installed, continuing"
				} else {
					Write-Verbose "v0.9.1 of ACMESharp is NOT installed, update/downgrade required"
					$ACMEUpdateRequired = $true
				}
			}
			if ($ACMEUpdateRequired) {
				Write-Verbose "Trying to update the ACMESharp modules"
				Install-Module -Name ACMESharp -Scope AllUsers -RequiredVersion 0.9.1 -Force -ErrorAction SilentlyContinue
			}
			Write-Verbose "Try loading module ACMESharp"
			Import-Module ACMESharp -ErrorAction Stop
		} catch [System.IO.FileNotFoundException] {
			Write-Verbose "Checking for PackageManagement"
			if ([string]::IsNullOrWhiteSpace($(Get-Module -ListAvailable -Name PackageManagement))) {
				Write-Warning "PackageManagement is not available please install this first or manually install ACMESharp"
				Write-Warning "Visit `"https://docs.microsoft.com/en-us/powershell/gallery/psget/get_psget_module`" to download Package Management"
				Write-Warning "ACMESharp: https://github.com/ebekker/ACMESharp"
				Start-Process "https://www.microsoft.com/en-us/download/details.aspx?id=49186"
				Exit (1)
			} else {
				try {
					if (-not ((Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue).Version -ge [System.Version]"2.8.5.208")) {
						Write-Verbose "Installing Nuget"
						Get-PackageProvider -Name NuGet -Force -ErrorAction SilentlyContinue | Out-Null
					}
					$installationPolicy = (Get-PSRepository -Name PSGallery).InstallationPolicy
					if (-not ($installationPolicy.ToLower() -eq "trusted")){
						Write-Verbose "Defining PSGallery PSRepository as trusted"
						Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
					}
					Write-Verbose "Installing ACMESharp"
					try {
						Install-Module -Name ACMESharp -Scope AllUsers -RequiredVersion 0.9.1.326 -Force -AllowClobber
					} catch {
						Write-Verbose "Installing ACMESharp again but without the -AllowClobber option"
						Install-Module -Name ACMESharp -Scope AllUsers -RequiredVersion 0.9.1.326 -Force
					}
					if (-not ((Get-PSRepository -Name PSGallery).InstallationPolicy -eq $installationPolicy)){
						Write-Verbose "Returning the PSGallery PSRepository InstallationPolicy to previous value"
						Set-PSRepository -Name "PSGallery" -InstallationPolicy $installationPolicy | Out-Null
					}
					Write-Verbose "Try loading module ACMESharp"
					Import-Module ACMESharp -ErrorAction Stop
				} catch {
					Write-Verbose "Error Details: $($_.Exception.Message)"
					Write-Error "Error while loading and/or installing module"
					Write-Warning "PackageManagement is not available please install this first or manually install ACMESharp"
					Write-Warning "Visit `"https://docs.microsoft.com/en-us/powershell/gallery/psget/get_psget_module`" to download Package Management"
					Write-Warning "ACMESharp: https://github.com/ebekker/ACMESharp"
					Start-Process "https://www.microsoft.com/en-us/download/details.aspx?id=49186"
					Exit (1)
				}
			}
		}
	}
}

#endregion Load Module

#region NetScaler Check

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Login to NetScaler and save session to global variable"
	Write-Host -ForeGroundColor White "`r`nNetScaler:"
	$NSSession = Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential -PassThru
	Write-Host -ForeGroundColor White -NoNewLine "- URL: "
	Write-Host -ForeGroundColor Green "$NSManagementURL"
	Write-Host -ForeGroundColor White -NoNewLine "- Username: "
	Write-Host -ForeGroundColor Green "$($NSSession.Username)"
	Write-Host -ForeGroundColor White -NoNewLine "- Version: "
	Write-Host -ForeGroundColor Green "$($NSSession.Version)"
	try {
		Write-Verbose "Verifying Content Switch"
		$response = InvokeNSRestApi -Session $NSSession -Method GET -Type csvserver -Resource $NSCsVipName
	} catch {
		$ExcepMessage = $_.Exception.Message
		Write-Verbose "Error Details: $ExcepMessage"
	} finally {
		if (($response.errorcode -eq "0") -and `
				($response.csvserver.type -eq "CONTENT") -and `
				($response.csvserver.curstate -eq "UP") -and `
				($response.csvserver.servicetype -eq "HTTP") -and `
				($response.csvserver.port -eq "80") ) {
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
			Write-Host -ForeGroundColor Green "`"$NSCsVipName`" -> Found"
			Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
			Write-Host -ForeGroundColor Green "OK`r`n"
		} elseif ($ExcepMessage -like "*(404) Not Found*") {
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
			Write-Host -ForeGroundColor Red "ERROR: The Content Switch `"$NSCsVipName`" does NOT exist!`r`n"
			Write-Host -ForeGroundColor White -NoNewLine "- Error message: "
			Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
			Write-Host -ForeGroundColor Yellow "  IMPORTANT: Please make sure a HTTP Content Switch is available`r`n"
			Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
			Write-Host -ForeGroundColor Red "FAILED!`r`n"
			Write-Host -ForeGroundColor Red "  Exiting now`r`n"
			Exit (1)
		}  elseif ($ExcepMessage -like "*The remote server returned an error*") {
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
			Write-Host -ForeGroundColor Red "ERROR: Unknown error found while checking the Content Switch"
			Write-Host -ForeGroundColor White -NoNewLine "- Error message: "
			Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
			Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
			Write-Host -ForeGroundColor Red "FAILED!`r`n"
			Write-Host -ForeGroundColor Red "  Exiting now`r`n"
			Exit (1)
		} elseif (($response.errorcode -eq "0") -and (-not ($response.csvserver.servicetype -eq "HTTP"))) {
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
			Write-Host -ForeGroundColor Red "ERROR: Content Switch is $($response.csvserver.servicetype) and NOT HTTP`r`n"
			if (-not ([string]::IsNullOrWhiteSpace($ExcepMessage))){
				Write-Host -ForeGroundColor White -NoNewLine "- Error message: "
				Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
			}
			Write-Host -ForeGroundColor Yellow "  IMPORTANT: Please use a HTTP (Port 80) Content Switch!`r`n  This is required for the validation.`r`n"
			Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
			Write-Host -ForeGroundColor Red "FAILED!`r`n"
			Write-Host -ForeGroundColor Red "  Exiting now`r`n"
			Exit (1)
		} else {
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
			Write-Host -ForeGroundColor Green "Found"
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch state: "
			if ($response.csvserver.curstate -eq "UP") {
				Write-Host -ForeGroundColor Green "UP"
			} else {
				Write-Host -ForeGroundColor RED "$($response.csvserver.curstate)"
			}
			Write-Host -ForeGroundColor White -NoNewLine "- Content Switch type: "
			if ($response.csvserver.type -eq "CONTENT") {
				Write-Host -ForeGroundColor Green "CONTENT"
			} else {
				Write-Host -ForeGroundColor RED "$($response.csvserver.type)"
			}
			if (-not ([string]::IsNullOrWhiteSpace($ExcepMessage))){
				Write-Host -ForeGroundColor White -NoNewLine "`r`n- Error message: "
				Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
			}
			Write-Host -ForeGroundColor White -NoNewLine "- Data: "
			$response.csvserver  | Format-List -Property * | Out-String
			Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
			Write-Host -ForeGroundColor Red "FAILED!`r`n"
			Write-Host -ForeGroundColor Red "  Exiting now`r`n"
			Exit (1)
		}
	}
}

#endregion NetScaler Check

#region Vault

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	if ($Production) {
		$VaultName = ":sys"
		$BaseService = "LetsEncrypt"
		Write-Verbose "Using the vault `"$VaultName`" for production certificates"
	} else {
		$VaultName = ":user"	
		$BaseService = "LetsEncrypt-STAGING"
		Write-Verbose "Using the vault `"$VaultName`" for test/staging purposes"
	}
	try {
		Write-Verbose "Get ACMEVault `"$VaultName`"" 
		$VaultData = ACMESharp\Get-ACMEVault -VaultProfile $VaultName
	} catch {
		Write-Verbose "`"$VaultName`" Vault not available, initialize"
		$CleanVault = $true
	}
	if ($CleanVault) {
		Write-Verbose "Initializing Vault"
		ACMESharp\Initialize-ACMEVault -VaultProfile $VaultName -Force
		Write-Verbose "Finished initializing"
		$VaultData = ACMESharp\Get-ACMEVault -VaultProfile $VaultName
	}
	Write-Verbose "Configure vault `"$VaultName`" for `"$BaseService`""
	ACMESharp\Set-ACMEVault -VaultProfile $VaultName -BaseService $BaseService
}

#endregion Vault

#region Registration

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Host -NoNewLine -ForeGroundColor Yellow "`n`nIMPORTANT: "
	Write-Host -ForeGroundColor White "By running this script you agree with the terms specified by Let's Encrypt."
	try {
		Write-Verbose "Retreive existing Registration"
		$Registration = ACMESharp\Get-ACMERegistration -VaultProfile $VaultName
		if ($Registration.Contacts -contains "mailto:$($EmailAddress)"){
			Write-Verbose "Existing registration found, no changes necessary"
		} else {
			Write-Verbose "Current registration `"$($Registration.Contacts)`" is not equal to `"$EmailAddress`", setting new registration"
			$Registration = ACMESharp\New-ACMERegistration -VaultProfile $VaultName -Contacts "mailto:$($EmailAddress)" -AcceptTos
		}
	} catch {
		Write-Verbose "Setting new registration to `"$EmailAddress`""
		
		$Registration = ACMESharp\New-ACMERegistration -VaultProfile $VaultName -Contacts "mailto:$($EmailAddress)" -AcceptTos
	}
	Write-Host -ForeGroundColor Yellow "`n`n`nTerms of Agreement:`n$($Registration.TosLinkUri)`n`n`n"
}

#endregion Registration

#region DNS

#region Primary DNS

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Validating DNS record(s)"
	$DNSObjects = @()
	
	Write-Verbose "Checking `"$CN`""
	try {
		if ($DisableIPCheck){
			Write-Warning "Skipping IP check, validation might fail"
			$PrimaryIP = "NoIPCheck"
		} else {
			$PublicDnsServer = "208.67.222.222"
			Write-Verbose "Using public DNS server (OpenDNS, 208.67.222.222) to verify dns records"
			Write-Verbose "Trying to get IP Address"
			$PrimaryIP = (Resolve-DnsName -Server $PublicDnsServer -Name $CN -DnsOnly -Type A -ErrorAction SilentlyContinue).IPAddress
			if ([string]::IsNullOrWhiteSpace($PrimaryIP)) {
				throw "ERROR: No valid entry found for DNSName:`"$CN`""
			}
			if ($PrimaryIP -is [system.array]){
				Write-Warning "More than one ip address found`n$($PrimaryIP | Format-List | Out-String)"
				$PrimaryIP = $PrimaryIP[0]
				Write-Warning "using the first one`"$PrimaryIP`""
			}
		}
	} catch {
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Host -ForeGroundColor Red "`nError while retreiving IP Address,"
		Write-Host -ForeGroundColor Red "you can try to re-run the script with the -DisableIPCheck parameter.`n"
		throw "Error while retreiving IP Address, does not exist?"
	}
	
	$Identifier = $null
	$IdentifierAlias = $null
	try {
		Write-Verbose "Find pre-existing registration for `"$CN`""
		$IdentifierAlias = "DNS-$($CN)-$IdentifierDate"
		$Identifier = ACMESharp\Get-ACMEIdentifier -IdentifierRef $IdentifierAlias -VaultProfile $VaultName
	} catch {
		try {
			Write-Verbose "Registration does not exist, registering `"$CN`""
			$Identifier = ACMESharp\New-ACMEIdentifier -Dns $CN -Alias $IdentifierAlias -VaultProfile $VaultName
		} catch {
			Write-Verbose "Registration is invalid"
			$Identifier = [PSCustomObject]@{
				Status = "invalid"
				Expires = $null
			}
		}
	}
	try {
		if ($Identifier.Uri) {
			Write-Verbose "Extracting data, checking validation"
			$response = Invoke-RestMethod -Uri $Identifier.Uri -Method Get
			#$result = $response  | Select-Object status,expires
			if ((-not([string]::IsNullOrWhiteSpace($response.status))) -and (-not([string]::IsNullOrWhiteSpace($response.expires)))) {
				$httpIdentifier = ($response | Select-Object -expand Challenges | Where-Object {$_.type -eq "http-01"})
			}
		} else {
			Write-Verbose "No URI available to check..."
		}
	}catch{
		Write-Verbose "Someting went wrong with the validation:`n$($response | Format-List | Out-String)"
	}
	Write-Verbose "Checking if current validation is still valid"
	if (($response.status -eq "valid") -and ($([datetime]$response.Expires - $(Get-Date)).TotalDays -gt 1)) {
		Write-Verbose "Registration for `"$CN`" is still valid"
		$Validation = $true
		Write-Verbose "Validation response:`n$($($response | Select-Object Identifier,Status,Expires) | Format-List | Out-String)"
	} else {
		Write-Verbose "Registration for `"$CN`" is NOT valid, validation required"
		$Validation = $false
		Write-Verbose "Validation response:`n$($($Identifier | Select-Object Identifier,Status,Expires) | Format-List | Out-String)"
	}
	Write-Verbose "Storing values for reference"
	$DNSObjects += [PSCustomObject]@{
		DNSName = $CN
		IPAddress = $PrimaryIP
		Status = $(if ([string]::IsNullOrWhiteSpace($PrimaryIP)) {$false} else {$true})
		Match = $null
		SAN = $false
		DNSValid = $Validation
		Alias = $IdentifierAlias
	}
	Write-Verbose "SAN Objects:`n$($DNSObjects | Format-List | Out-String)"
}

#endregion Primary DNS

#region SAN

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	$DNSRecord = $null
	Write-Verbose "Checking if SAN entries are available"
	if ([string]::IsNullOrWhiteSpace($SAN)) {
		Write-Verbose "No SAN entries found"
	} else {
		Write-Verbose "$($SAN.Count) found, checking each one"
		foreach ($DNSRecord in $SAN) {
			Write-Verbose "Start with SAN: `"$DNSRecord`""
			try {
				if ($DisableIPCheck) {
					Write-Verbose "Skipping IP check"
					$SANIP = "NoIPCheck"
				} else {
					Write-Verbose "Start basic IP Check for `"$DNSRecord`", trying to get IP Address"
					$SANIP = (Resolve-DnsName -Server $PublicDnsServer -Name $DNSRecord -DnsOnly -Type A -ErrorAction SilentlyContinue).IPAddress
					if ($SANIP -is [system.array]){
						Write-Warning "More than one ip address found`n$($SANIP | Format-List | Out-String)"
						$SANIP = $SANIP[0]
						Write-Warning "using the first one`"$SANIP`""
					}
					Write-Verbose "Finished, Result: $SANIP"
				}
				
			} catch {
				Write-Verbose "Error Details: $($_.Exception.Message)"
				Write-Host -ForeGroundColor Red "`nError while retreiving IP Address,"
				Write-Host -ForeGroundColor Red "you can try to re-run the script with the -DisableIPCheck parameter."
				Write-Host -ForeGroundColor Red "The script will continue but `"$DNSRecord`" will be skipped`n"
				$SANIP = "Skipped"
			}
			if ([string]::IsNullOrWhiteSpace($SANIP)) {
				Write-Verbose "No valid entry found for DNSName:`"$DNSRecord`""
				$SANMatch = $false
				$SANStatus = $false
			} else {
				Write-Verbose "Valid entry found"
				$SANStatus = $true
				if ($SANIP -eq "NoIPCheck") {
					Write-Verbose "IP address checking was disabled"
					$SANMatch = $true
				} elseif ($SANIP -eq "Skipped") {
					Write-Verbose "IP address checking failed, `"$DNSRecord`" will be skipped"
					$SANMatch = $true
				} else {
					Write-Verbose "All IP Adressess must match, checking"
					if ($SANIP -match $($DNSObjects[0].IPAddress)) {
						Write-Verbose "`"$SANIP ($DNSRecord)`" matches to `"$($DNSObjects[0].IPAddress) ($($DNSObjects[0].DNSName))`""
						$SANMatch = $true
					} else {
						Write-Verbose "`"$SANIP`" ($DNSRecord) NOT matches to `"$($DNSObjects[0].IPAddress)`" ($($DNSObjects[0].DNSName))"
						$SANMatch = $false
					}
				}
			}
			if (-not($SANIP -eq "Skipped")) {
				$Identifier = $null
				$IdentifierAlias = $null
				try {
					Write-Verbose "Find pre-existing registration for `"$DNSRecord`""
					$IdentifierAlias = "DNS-$($DNSRecord)-$IdentifierDate"
					$Identifier = ACMESharp\Get-ACMEIdentifier -IdentifierRef $IdentifierAlias -VaultProfile $VaultName
				} catch {
					try {
						Write-Verbose "Registration does not exist, registering `"$DNSRecord`""
						$Identifier = ACMESharp\New-ACMEIdentifier -Dns $DNSRecord -Alias $IdentifierAlias -VaultProfile $VaultName
					} catch {
						Write-Verbose "Registration is invalid"
						$Identifier = [PSCustomObject]@{
							Status = "invalid"
							Expires = $null
						}
					}
				}
				
				try {
					if ($Identifier.Uri) {
						Write-Verbose "Extracting data, checking validation"
						$response = Invoke-RestMethod -Uri $Identifier.Uri -Method Get
						#$result = $response  | Select-Object status,expires
						if ((-not([string]::IsNullOrWhiteSpace($response.status))) -and (-not([string]::IsNullOrWhiteSpace($response.expires)))) {
							$httpIdentifier = ($response | Select-Object -expand Challenges | Where-Object {$_.type -eq "http-01"})
						}
					} else {
						Write-Verbose "No URI available to check..."
					}
				}catch{
					Write-Verbose "Someting went wrong with the validation:`n$($response | Format-Table | Out-String)"
				}
				
				Write-Verbose "Checking if current validation is still valid"
				if (($response.status -eq "valid") -and ($([datetime]$response.Expires - $(Get-Date)).TotalDays -gt 1)) {
					Write-Verbose "Registration for `"$DNSRecord`" is still valid"
					$Validation = $true
					Write-Verbose "Validation response:`n$($($response | Select-Object Identifier,Status,Expires) | Format-Table | Out-String)"
				} else {
					Write-Verbose "Registration for `"$DNSRecord`" is NOT valid, validation required"
					$Validation = $false
					Write-Verbose "Validation response:`n$($($Identifier | Select-Object Identifier,Status,Expires) | Format-Table | Out-String)"
				}
				Write-Verbose "Storing values for reference"
				$DNSObjects += [PSCustomObject]@{
					DNSName = $DNSRecord
					IPAddress = $SANIP
					Status = $SANStatus
					Match = $SANMatch
					SAN = $true
					DNSValid = $Validation
					Alias = $IdentifierAlias
				}
			}
			Write-Verbose "Finished with SAN: `"$DNSRecord`""
		}
	}
	Write-Verbose "SAN Objects:`n$($DNSObjects | Format-List | Out-String)"
}

#endregion SAN

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Checking for invalid DNS Records"
	$InvalidDNS = $DNSObjects | Where-Object {$_.Status -eq $false}
	$SkippedDNS = $DNSObjects | Where-Object {$_.IPAddress -eq "Skipped"}
	if ($InvalidDNS) {
		Write-Verbose "Invalid DNS object(s):`n$($InvalidDNS | Select-Object DNSName,Status | Format-List | Out-String)"
		$DNSObjects[0] | Select-Object DNSName,IPAddress | Format-List | Out-String | ForEach-Object {Write-Host -ForeGroundColor Green "$_"}
		$InvalidDNS | Select-Object DNSName,IPAddress | Format-List | Out-String | ForEach-Object {Write-Host -ForeGroundColor Red "$_"}
		throw "ERROR, invalid (not registered?) DNS Record(s) found!"
	} else {
		Write-Verbose "None found, continuing"
	}
	if ($SkippedDNS) {
		Write-Warning "The following DNS object(s) will be skipped:`n$($SkippedDNS | Select-Object DNSName | Format-List | Out-String)"
	} 
	Write-Verbose "Checking non matching DNS Records"
	$DNSNoMatch = $DNSObjects | Where-Object {$_.Match -eq $false}
	if ($DNSNoMatch -and (-not $DisableIPCheck)) {
		Write-Verbose "$($DNSNoMatch | Select-Object DNSName,Match | Format-List | Out-String)"
		$DNSObjects[0] | Select-Object DNSName,IPAddress | Format-List | Out-String | ForEach-Object {Write-Host -ForeGroundColor Green "$_"}
		$DNSNoMatch | Select-Object DNSName,IPAddress | Format-List | Out-String | ForEach-Object {Write-Host -ForeGroundColor Red "$_"}
		throw "ERROR: Non-matching records found, must match to `"$($DNSObjects[0].DNSName)`" ($($DNSObjects[0].IPAddress))"
	} elseif ($DisableIPCheck) {
		Write-Verbose "IP Adressess checking was skipped"
	} else {
		Write-Verbose "All IP Adressess match"
	}
}


#region ACME DNS Verification

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Checking if validation is required"
	$DNSValidationRequired = $DNSObjects | Where-Object {$_.DNSValid -eq $false}
	if ($DNSValidationRequired) {
		Write-Verbose "Validation NOT required"
		$NetScalerActionsRequired = $true
	} else {
		Write-Verbose "Validation required for the following objects:`n$($DNSValidationRequired | Select-Object DNSName | Format-List | Out-String)"
		$NetScalerActionsRequired = $false
	
	}
}

#region NetScaler pre dns
	
if ((-not ($CleanNS)) -and ($NetScalerActionsRequired) -and (-not ($RemoveTestCertificates))) {
	try {
		Write-Verbose "Login to NetScaler and save session to global variable"
		$NSSession = Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential -PassThru
		Write-Verbose "Enable required NetScaler Features, Load Balancer, Responder, Content Switch and SSL"
		$payload = @{"feature"="LB RESPONDER CS SSL"}
		$response = InvokeNSRestApi -Session $NSSession -Method POST -Type nsfeature -Payload $payload -Action enable
		try {
			Write-Verbose "Verifying Content Switch"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type csvserver -Resource $NSCsVipName
		} catch {
			$ExcepMessage = $_.Exception.Message
			Write-Verbose "Error Details: $ExcepMessage"
			throw "Could not find/read out the content switch `"$NSCsVipName`" not available?"
		} finally {
			if ($ExcepMessage -like "*(404) Not Found*") {
				Write-Host -ForeGroundColor Red "`nThe Content Switch `"$NSCsVipName`" does NOT exist!"
				Exit (1)
			} elseif ($ExcepMessage -like "*The remote server returned an error*") {
				Write-Host -ForeGroundColor Red "`nUnknown error found while checking the Content Switch: `"$NSCsVipName`""
				Write-Host -ForeGroundColor Red "Error message: `"$ExcepMessage`""
				Exit (1)
			} elseif (($response.errorcode -eq "0") -and (-not ($response.csvserver.servicetype -eq "HTTP"))) {
				Write-Host -ForeGroundColor Red "`nThe Content Switch is $($response.csvserver.servicetype) and NOT HTTP"
				Write-Host -ForeGroundColor Red "Please use a HTTP (Port 80) Content Switch this is required for the validation. Exiting now`n"
				Exit (1)
			}
		}
		try { 
			Write-Verbose "Configuring NetScaler: Check if Load Balancer Service exists"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type service -Resource $NSSvcName
			Write-Verbose "Yep it exists, continuing"
		} catch {
			Write-Verbose "It does not exist, continuing"
			Write-Verbose "Configuring NetScaler: Create Load Balance Service `"$NSSvcName`""
			$payload = @{"name"="$NSSvcName";"ip"="$NSSvcDestination";"servicetype"="HTTP";"port"="80";"healthmonitor"="NO";} 
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type service -Payload $payload -Action add
		}
		try { 
			Write-Verbose "Configuring NetScaler: Check if Load Balancer exists"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type lbvserver -Resource $NSLbName
			Write-Verbose "Yep it exists, continuing"
		} catch {
			Write-Verbose "Nope, continuing"
			Write-Verbose "Configuring NetScaler: Create Load Balance Vip `"$NSLbName`""
			$payload = @{"name"="$NSLbName";"servicetype"="HTTP";"ipv46"="0.0.0.0";"Port"="0";}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type lbvserver -Payload $payload -Action add
		} finally {
			Write-Verbose "Configuring NetScaler: Bind Service `"$NSSvcName`" to Load Balance Vip `"$NSLbName`""
			Write-Verbose "Checking LB Service binding"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type lbvserver_service_binding -Resource $NSLbName
			if ($response.lbvserver_service_binding.servicename -eq $NSSvcName) {
				Write-Verbose "LB Service binding is ok"
			} else {
				$payload = @{"name"="$NSLbName";"servicename"="$NSSvcName";}
				$response = InvokeNSRestApi -Session $NSSession -Method PUT -Type lbvserver_service_binding -Payload $payload
			}
		}
		try {
			Write-Verbose "Configuring NetScaler: Check if Responder Action exists"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderaction -Resource $NSRsaName
			try {
				Write-Verbose "Yep it exists, continuing"
				Write-Verbose "Configuring NetScaler: Change Responder Action to default values"
				$payload = @{"name"="$NSRsaName";"target"='"HTTP/1.0 200 OK" +"\r\n\r\n" + "XXXX"';}
				$response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderaction -Payload $payload -Action set
			} catch {
				throw "Something went wrong with reconfiguring the existing action `"$NSRsaName`", exiting now..."
			}	
		} catch {
			$payload = @{"name"="$NSRsaName";"type"="respondwith";"target"='"HTTP/1.0 200 OK" +"\r\n\r\n" + "XXXX"';}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderaction -Payload $payload -Action add
		}
		try { 
			Write-Verbose "Configuring NetScaler: Check if Responder Policy exists"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderpolicy -Resource $NSRspName
			try {
				Write-Verbose "Yep it exists, continuing"
				Write-Verbose "Configuring NetScaler: Change Responder Policy to default values"
				$payload = @{"name"="$NSRspName";"action"="rsa_letsencrypt";"rule"='HTTP.REQ.URL.CONTAINS(".well-known/acme-challenge/XXXX")';}
				$response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderpolicy -Payload $payload -Action set

			} catch {
				throw "Something went wrong with reconfiguring the existing policy `"$NSRspName`", exiting now..."
			}	
		} catch {
			$payload = @{"name"="$NSRspName";"action"="$NSRsaName";"rule"='HTTP.REQ.URL.CONTAINS(".well-known/acme-challenge/XXXX")';}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderpolicy -Payload $payload -Action add
		} finally {
			$payload = @{"name"="$NSLbName";"policyname"="$NSRspName";"priority"=100;}
			$response = InvokeNSRestApi -Session $NSSession -Method PUT -Type lbvserver_responderpolicy_binding -Payload $payload -Resource $NSLbName
		}
		try { 
			Write-Verbose "Configuring NetScaler: Check if Content Switch Policy exists"
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type cspolicy -Resource $NSCspName
			Write-Verbose "It does, continuing"
			if (-not($response.cspolicy.rule -eq "HTTP.REQ.URL.CONTAINS(`"well-known/acme-challenge/`")")) {
				$payload = @{"policyname"="$NSCspName";"rule"="HTTP.REQ.URL.CONTAINS(`"well-known/acme-challenge/`")";}
				$response = InvokeNSRestApi -Session $NSSession -Method PUT -Type cspolicy -Payload $payload
			}
		} catch {
			Write-Verbose "Configuring NetScaler: Create Content Switch Policy"
			$payload = @{"policyname"="$NSCspName";"rule"='HTTP.REQ.URL.CONTAINS("well-known/acme-challenge/")';}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type cspolicy -Payload $payload -Action add
			
			
		}
		Write-Verbose "Configuring NetScaler: Bind Load Balancer `"$NSLbName`" to Content Switch `"$NSCsVipName`" with prio: $NSCsVipBinding"
		$payload = @{"name"="$NSCsVipName";"policyname"="$NSCspName";"priority"="$NSCsVipBinding";"targetlbvserver"="$NSLbName";"gotopriorityexpression"="END";}
		$response = InvokeNSRestApi -Session $NSSession -Method PUT -Type csvserver_cspolicy_binding -Payload $payload
		Write-Verbose "Finished configuring the NetScaler"
	} catch {
		Write-Verbose "Error Details: $($_.Exception.Message)"
		throw "ERROR: Could not configure the NetScaler, exiting now"
	}
	Start-Sleep -Seconds 2
}

#endregion NetScaler pre dns

#region Test NS CS

if ((-not ($CleanNS)) -and ($NetScalerActionsRequired) -and (-not ($RemoveTestCertificates))) {
	Write-Host -ForeGroundColor White "Executing some tests, can take a couple of seconds/minutes..."
	Write-Host -ForeGroundColor Yellow "`r`nPlease note that if a test fails, the script still tries to continue!`r`n"
	ForEach ($DNSObject in $DNSObjects ) {
		Write-Host -ForeGroundColor White -NoNewLine " -Checking: => "
		Write-Host -ForeGroundColor Yellow "`"$($DNSObject.DNSName)`" ($($DNSObject.IPAddress))"
		$TestURL = "http://$($DNSObject.DNSName)/.well-known/acme-challenge/XXXX"
		Write-Verbose "Testing if the Content Switch is available on `"$TestURL`" (via internal DNS)"
		try {
			Write-Verbose "Retreiving data"
			$Result = Invoke-WebRequest -URI $TestURL -TimeoutSec 2
			Write-Verbose "Success, output: $($Result| Out-String)"
		} catch {
			$Result = $null
			Write-Verbose "Internal check failed, error Details: $($_.Exception.Message)"
		}
		if ($Result.RawContent -eq "HTTP/1.0 200 OK" + "`r`n`r`n" + "XXXX") {
			Write-Host -ForeGroundColor White -NoNewLine " -Test (Int. DNS): "
			Write-Host -ForeGroundColor Green "OK"
		} else {
			Write-Host -ForeGroundColor White -NoNewLine " -Test (Int. DNS): "
			Write-Host -ForeGroundColor Yellow "Not successfull, maybe not resolvable internally?"
			Write-Verbose "Output: $($Result| Out-String)"
		}
		
		try {
			Write-Verbose "Checking if Public IP is available for external DNS testing"
			[ref]$ValidIP = [ipaddress]::None
			if (([ipaddress]::TryParse("$($DNSObject.IPAddress)",$ValidIP)) -and (-not ($DisableIPCheck))) {
				Write-Verbose "Testing if the Content Switch is available on `"$TestURL`" (via external DNS)"
				$TestURL = "http://$($DNSObject.IPAddress)/.well-known/acme-challenge/XXXX"
				$Headers = @{"Host"="$($DNSObject.DNSName)"}
				Write-Verbose "Retreiving data"
				$Result = Invoke-WebRequest -URI $TestURL -Headers $Headers -TimeoutSec 2
				Write-Verbose "Success, output: $($Result| Out-String)"
			} else {
				Write-Verbose "Public IP is not available for external DNS testing"
			}
		} catch {
			$Result = $null
			Write-Verbose "External check failed, error Details: $($_.Exception.Message)"
		}
		[ref]$ValidIP = [ipaddress]::None
		if (([ipaddress]::TryParse("$($DNSObject.IPAddress)",$ValidIP)) -and (-not ($DisableIPCheck))) {
			if ($Result.RawContent -eq "HTTP/1.0 200 OK" + "`r`n`r`n" + "XXXX") {
				Write-Host -ForeGroundColor White -NoNewLine " -Test (Ext. DNS): "
				Write-Host -ForeGroundColor Green "OK"
			} else {
				Write-Host -ForeGroundColor White -NoNewLine " -Test (Ext. DNS): "
				Write-Host -ForeGroundColor Yellow "Not successfull, maybe not resolvable externally?"
				Write-Verbose "Output: $($Result| Out-String)"
			}
		}
	}
	Write-Host -ForeGroundColor White "`r`nFinished the tests, script will continue again."
}

#endregion Test NS CS

#region DNS Check

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Check if DNS Records need to be validated"
	Write-Host -ForeGroundColor White "Verification:"
	foreach ($DNSObject in $DNSObjects) {
		$DNSRecord = $DNSObject.DNSName
		$Challenge = $null
		$UpdateIdentifier = $null
		Write-Verbose "Checking validation for `"$DNSRecord`""
		if ($DNSObject.DNSValid){
			Write-Host -ForeGroundColor White -NoNewLine " -DNS: "
			Write-Host -ForeGroundColor Green "`"$DNSRecord`""
			Write-Host -ForeGroundColor White -NoNewLine " -Status: "
			Write-Host -ForeGroundColor Green "=> Still valid"
		} else {
			Write-Verbose "New validation required, Start verifying"
			$IdentifierAlias = $DNSObject.Alias
			try {
				try {
					$CompletedChallenge = ACMESharp\Complete-ACMEChallenge -IdentifierRef $IdentifierAlias -ChallengeType http-01 -Handler manual -VaultProfile $VaultName -Force
					if ($([datetime]$CompletedChallenge.Expires - $(Get-Date)).TotalDays -gt 1) {
						$Challenge = ($CompletedChallenge.Challenges | Where-Object { $_.Type -eq "http-01" }).Challenge
					} else {
						
					}
				} catch {
					Write-Verbose "Error Details: $($_.Exception.Message)"
					throw "Error while creating the Challenge"
				}
				Write-Verbose "Configuring NetScaler: Change Responder Policy `"$NSRspName`" to: `"HTTP.REQ.URL.CONTAINS(`"$($Challenge.FilePath)`")`""
				$payload = @{"name"="$NSRspName";"action"="$NSRsaName";"rule"="HTTP.REQ.URL.CONTAINS(`"$($Challenge.FilePath)`")";}
				$response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderpolicy -Payload $payload -Action set
				
				Write-Verbose "Configuring NetScaler: Change Responder Action `"$NSRsaName`" to return "
				Write-Verbose "`"HTTP/1.0 200 OK\r\n\r\n$($Challenge.FileContent)`""
				$payload = @{"name"="$NSRsaName";"target"="`"HTTP/1.0 200 OK\r\n\r\n$($Challenge.FileContent)`"";}
				$response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderaction -Payload $payload -Action set
				
				Write-Verbose "Wait 1 second"
				Start-Sleep -Seconds 1
				Write-Verbose "Start Submitting Challenge"
				try {
					ACMESharp\Submit-ACMEChallenge -IdentifierRef $IdentifierAlias -ChallengeType http-01 -VaultProfile $VaultName | Out-Null
				} catch {
					Write-Verbose "Error Details: $($_.Exception.Message)"
					throw "Error while submitting the Challenge"
				}
				Write-Verbose "Retreiving validation status"
				try {
					$UpdateIdentifier = (ACMESharp\Update-ACMEIdentifier -IdentifierRef $IdentifierAlias -ChallengeType http-01 -VaultProfile $VaultName).Challenges | Where-Object {$_.Type -eq "http-01"}
				} catch {
					Write-Verbose "Error Details: $($_.Exception.Message)"
					throw "Error while retreiving validation status"
				}
				$i = 0
				Write-Host -ForeGroundColor White -NoNewLine " -DNS: "
				Write-Host -ForeGroundColor Green "`"$DNSRecord`""
				Write-Host -ForeGroundColor White -NoNewLine " -Status: "
				while(-NOT ($UpdateIdentifier.Status.ToLower() -eq "valid")) {
					Write-Host -ForeGroundColor Yellow -NoNewLine "="
					$i++
					Write-Verbose "($($i.ToString())) $DNSRecord is not (yet) validated, Wait 2 second"
					Start-Sleep -Seconds 2
					Write-Verbose "Retreiving validation status"
					try {
						$UpdateIdentifier = (ACMESharp\Update-ACMEIdentifier -IdentifierRef $IdentifierAlias -ChallengeType http-01 -VaultProfile $VaultName).Challenges | Where-Object {$_.Type -eq "http-01"}
					} catch {
						Write-Verbose "Error Details: $($_.Exception.Message)"
						throw "Error while retreiving validation status"
					}
					if (($i -ge 60) -or ($UpdateIdentifier.Status.ToLower() -eq "invalid")) {break}
				}
				switch ($UpdateIdentifier.Status.ToLower()) {
					"pending" {
						Write-Host -ForeGroundColor Red "ERROR"
						throw "It took to long for the validation ($DNSRecord) to complete, exiting now."
					}
					"invalid" {
						Write-Host -ForeGroundColor Red "ERROR"
						throw "Validation for `"$DNSRecord`" is invalid! Exiting now."
					}
					"valid" {
						Write-Host -ForeGroundColor Green "> validated successfully"
					}
					default {
						Write-Host -ForeGroundColor Red "ERROR"
						throw "Unexpected status for `"$DNSRecord`" is `"$($UpdateIdentifier.Status)`", exiting now."
					}
				}
			} catch {
				Write-Verbose "Error Details: $($_.Exception.Message)"
				throw "Error while verifying `"$DNSRecord`", exiting now"
			}
		}
	}
	"`r`n"
}

#endregion DNS Check

#region NetScaler post DNS

if (($NetScalerActionsRequired) -or ($CleanNS) -and (-not ($RemoveTestCertificates))) {
	Write-Verbose "Login to NetScaler and save session to global variable"
	Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential
	try {
		Write-Verbose "Checking if a binding exists for `"$NSCspName`""
		$Filters = @{"policyname"="$NSCspName"}
		$response = InvokeNSRestApi -Session $NSSession -Method GET -Type csvserver_cspolicy_binding -Resource "$NSCsVipName" -Filters $Filters
		if ($response.csvserver_cspolicy_binding.policyname -eq $NSCspName) {
			Write-Verbose "Removing Content Switch Loadbalance Binding"
			$Arguments = @{"name"="$NSCsVipName";"policyname"="$NSCspName";"priority"="$NSCsVipBinding";}
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type csvserver_cspolicy_binding -Arguments $Arguments
		} else {
			Write-Verbose "No binding found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Content Switch Loadbalance Binding"
	}
	try {
		Write-Verbose "Checking if Content Switch Policy `"$NSCspName`" exists"
		try { 
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type cspolicy -Resource "$NSCspName"
		} catch{}
		if ($response.cspolicy.policyname -eq $NSCspName) {
			Write-Verbose "Removing Content Switch Policy"
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type cspolicy -Resource "$NSCspName"
		} else {
			Write-Verbose "Content Switch Policy not found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Content Switch Policy" 
	}
	try {
		Write-Verbose "Checking if Load Balance vServer `"$NSLbName`" exists"
		try { 
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type lbvserver -Resource "$NSLbName"
		} catch{}
		if ($response.lbvserver.name -eq $NSLbName) {
			Write-Verbose "Removing the Load Balance vServer"
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type lbvserver -Resource "$NSLbName"
		} else {
			Write-Verbose "Load Balance vServer not found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Load Balance vserver" 
	}
	try {
		Write-Verbose "Checking if Service `"$NSSvcName`" exists"
		try { 
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type service -Resource "$NSSvcName"
		} catch{}
		if ($response.service.name -eq $NSSvcName) {
			Write-Verbose "Removing Service `"$NSSvcName`""
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type service -Resource "$NSSvcName"
		} else {
			Write-Verbose "Service not found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Service" 
	}
	try {
		Write-Verbose "Checking if server `"$NSSvcDestination`" exists"
		try { 
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type server -Resource "$NSSvcDestination"
		} catch{}
		if ($response.server.name -eq $NSSvcDestination) {
			Write-Verbose "Removing Server `"$NSSvcDestination`""
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type server -Resource "$NSSvcDestination"
		} else {
			Write-Verbose "Server not found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Server" 
	}
	try {
		Write-Verbose "Checking if Responder Policy `"$NSRspName`" exists"
		try { 
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderpolicy -Resource "$NSRspName"
		} catch{}
		if ($response.responderpolicy.name -eq $NSRspName) {
			Write-Verbose "Removing Responder Policy `"$NSRspName`""
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type responderpolicy -Resource "$NSRspName" 
		} else {
			Write-Verbose "Responder Policy not found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Responder Policy" 
	}
	try {
		Write-Verbose "Checking if Responder Action `"$NSRsaName`" exists"
		try { 
			$response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderaction -Resource "$NSRsaName"
		} catch{}
		if ($response.responderaction.name -eq $NSRsaName) {
			Write-Verbose "Removing Responder Action `"$NSRsaName`""
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type responderaction -Resource $NSRsaName
		} else {
			Write-Verbose "Responder Action not found"
		}
	} catch { 
		Write-Verbose "Error Details: $($_.Exception.Message)"
		Write-Warning "Not able to remove the Responder Action" 
	}
}	

#endregion NetScaler Post DNS

#endregion ACME DNS Verification

#endregion DNS

#region Certificates
	
if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	$SANs = $DNSObjects | Where-Object {$_.SAN -eq $true}
	$IdentifierAlias = $DNSObjects[0].Alias
	try {
		$CertificateAlias = "CRT-SAN-$SessionDateTime-$CN"
		if ($SANs) {
			Write-Verbose "Get certificate with SANs"
			Write-Verbose "Domain:`n$($DNSObjects[0] | Select-Object DNSName,Alias | Format-List | Out-String)"
			Write-Verbose "Subject Alternative Names:`n$(@($SANs) | Select-Object DNSName,Alias | Format-List | Out-String)"
			$NewCertificate = ACMESharp\New-ACMECertificate $IdentifierAlias `
				-AlternativeIdentifierRefs @($SANs.Alias) `
				-Alias $CertificateAlias `
				-Generate `
				-VaultProfile $VaultName
		} else {
			Write-Verbose "Get single DNS Name certificate"
			Write-Verbose "Domain:`n$($($DNSObjects[0].DNSName) | Format-List * | Out-String)"
			$NewCertificate = ACMESharp\New-ACMECertificate $IdentifierAlias `
				-Alias $CertificateAlias `
				-Generate `
				-VaultProfile $VaultName
		}
		Write-Verbose "Submit Certificate request"
		ACMESharp\Submit-ACMECertificate $CertificateAlias -VaultProfile $VaultName | Out-Null
	} catch {
		throw "ERROR. Certificate completion failed, details: $($_.Exception.Message | Out-String)"
	}
	$i = 0
	while (-not (ACMESharp\Update-ACMECertificate $CertificateAlias -VaultProfile $VaultName | Select-Object IssuerSerialNumber)) {
		$i++
		$imax = 120
		if ($i -ge $imax) {
			throw "Error: Retreiving certificate failed, took to long to complete"
		}
		Write-Host "Will continue $(($imax-$i)*2) more seconds for the certificate to come available..."
		Start-Sleep -seconds 2
	}
	
	$CertificateDirectory = Join-Path -Path $CertDir -ChildPath $CertificateAlias
	Write-Verbose "Create directory `"$CertificateDirectory`" for storing the new certificates"
	New-Item $CertificateDirectory -ItemType directory -force | Out-Null
	$CertificateName = "$($ScriptDateTime.ToString("yyyyMMddHHmm"))-$cn"
	if (Test-Path $CertificateDirectory){
		if ($Production){
			Write-Verbose "Writing production certificates"
			$IntermediateCACertKeyName = "Lets Encrypt Authority X3-int"
			$IntermediateCAFileName = "$($IntermediateCACertKeyName).crt"
			$IntermediateCAFullPath = Join-Path -Path $CertificateDirectory -ChildPath $IntermediateCAFileName
			$IntermediateCASerial = "0a0141420000015385736a0b85eca708"
		} else {
			Write-Verbose "Writing test/staging certificates"
			$IntermediateCACertKeyName = "Fake LE Intermediate X1-int"
			$IntermediateCAFileName = "$($IntermediateCACertKeyName).crt"
			$IntermediateCAFullPath = Join-Path -Path $CertificateDirectory -ChildPath $IntermediateCAFileName
			$IntermediateCASerial = "8be12a0e5944ed3c546431f097614fe5"
		}
		Write-Verbose "Intermediate: `"$IntermediateCAFileName`""
		ACMESharp\Get-ACMECertificate $CertificateAlias -ExportIssuerPEM $IntermediateCAFullPath -VaultProfile $VaultName | Out-Null
		if ($Production){
			if ($CertificateName.length -ge 31) {
				$CertificateName = "$($CertificateName.subString(0,31))"
				Write-Verbose "CertificateName (new name): `"$CertificateName`" ($($CertificateName.length) max 31)"
			} else {
				$CertificateName = "$CertificateName"
				Write-Verbose "CertificateName: `"$CertificateName`" ($($CertificateName.length) max 31)"
			}
			if ($CertificateAlias.length -ge 59) {
				$CertificateFileName = "$($CertificateAlias.subString(0,59)).crt"
				Write-Verbose "Certificate (new name): `"$CertificateFileName`"($($CertificateFileName.length) max 63)"
				$CertificateKeyFileName = "$($CertificateAlias.subString(0,59)).key"
				Write-Verbose "Key (new name): `"$CertificateKeyFileName`"($($CertificateFileName.length) max 63)"
			} else {
				$CertificateFileName = "$($CertificateAlias).crt"
				Write-Verbose "Certificate: `"$CertificateFileName`" ($($CertificateFileName.length) max 63)"
				$CertificateKeyFileName = "$($CertificateAlias).key"
				Write-Verbose "Key: `"$CertificateKeyFileName`"($($CertificateFileName.length) max 63)"
			}
			$CertificatePfxFileName = "$CertificateAlias.pfx"
		} else {
			if ($CertificateName.length -ge 27) {
				$CertificateName = "TST-$($CertificateName.subString(0,27))"
				Write-Verbose "CertificateName (new name): `"$CertificateName`" ($($CertificateName.length) max 31)"
			} else {
				$CertificateName = "TST-$($CertificateName)"
				Write-Verbose "CertificateName: `"$CertificateName`" ($($CertificateName.length) max 31)"
			}
			if ($CertificateAlias.length -ge 55) {
				$CertificateFileName = "TST-$($CertificateAlias.subString(0,55)).crt"
				Write-Verbose "Certificate (new name): `"$CertificateFileName`"($($CertificateFileName.length) max 63)"
				$CertificateKeyFileName = "TST-$($CertificateAlias.subString(0,55)).key"
				Write-Verbose "Key (new name): `"$CertificateKeyFileName`"($($CertificateFileName.length) max 63)"
			} else {
				$CertificateFileName = "TST-$($CertificateAlias).crt"
				Write-Verbose "Certificate: `"$CertificateFileName`"($($CertificateFileName.length) max 63)"
				$CertificateKeyFileName = "TST-$($CertificateAlias).key"
				Write-Verbose "Key: `"$CertificateKeyFileName`"($($CertificateFileName.length) max 63)"
			}
			$CertificatePfxFileName = "TST-$CertificateAlias.pfx"
		}
		$CertificateFullPath = Join-Path -Path $CertificateDirectory -ChildPath $CertificateFileName
		ACMESharp\Get-ACMECertificate $CertificateAlias -ExportCertificatePEM $CertificateFullPath -VaultProfile $VaultName | Out-Null
		$CertificateKeyFullPath = Join-Path -Path $CertificateDirectory -ChildPath $CertificateKeyFileName
		ACMESharp\Get-ACMECertificate $CertificateAlias -ExportKeyPEM $CertificateKeyFullPath -VaultProfile $VaultName | Out-Null
		$CertificatePfxFullPath = Join-Path -Path $CertificateDirectory -ChildPath $CertificatePfxFileName 
		if ($PfxPassword){
			Write-Verbose "PFX: `"$CertificatePfxFileName`" ($($CertificatePfxFileName.length))"
			ACMESharp\Get-ACMECertificate $CertificateAlias -ExportPkcs12 "$CertificatePfxFullPath" -CertificatePassword "$PfxPassword" -VaultProfile $VaultName | Out-Null
		} else {
			try {
				$length=15
				Add-Type -AssemblyName System.Web | Out-Null
				$PfxPassword = [System.Web.Security.Membership]::GeneratePassword($length,2)
				Write-Warning "No Password was specified, so a random password was generated!"
				Write-Host -ForeGroundColor Yellow "`n***********************"
				Write-Host -ForeGroundColor Yellow "*   PFX Password:     *"
				Write-Host -ForeGroundColor Yellow "*                     *"
				Write-Host -ForeGroundColor Yellow "*   $PfxPassword   *"
				Write-Host -ForeGroundColor Yellow "*                     *"
				Write-Host -ForeGroundColor Yellow "***********************`n"
				ACMESharp\Get-ACMECertificate $CertificateAlias -ExportPkcs12 "$CertificatePfxFullPath" -CertificatePassword "$PfxPassword" -VaultProfile $VaultName | Out-Null
			} catch {
				Write-Verbose "An error occured while generating a Password."
			}
		}
	}
}

#endregion Certificates

#region Upload certificates to NetScaler

if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
	try {
		Write-Verbose "Retreiving existing certificates"
		$CertDetails = InvokeNSRestApi -Session $NSSession -Method GET -Type sslcertkey
		Write-Verbose "Checking if IntermediateCA `"$IntermediateCACertKeyName`" already exists"
		if ($ns10x) {
			$IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.cert -match $IntermediateCAFileName}
		} else {
			$IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.serial -eq $IntermediateCASerial}
		}
		if (-not ($IntermediateCADetails)) {
			Write-Verbose "Uploading `"$IntermediateCAFileName`" to the NetScaler"
			$IntermediateCABase64 = [System.Convert]::ToBase64String($(Get-Content $IntermediateCAFullPath -Encoding "Byte"))
			$payload = @{"filename"="$IntermediateCAFileName";"filecontent"="$IntermediateCABase64";"filelocation"="/nsconfig/ssl/";"fileencoding"="BASE64";}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type systemfile -Payload $payload
			Write-Verbose "Succeeded"
			Write-Verbose "Add the certificate to the NetScaler config"
			$payload = @{"certkey"="$IntermediateCACertKeyName";"cert"="/nsconfig/ssl/$($IntermediateCAFileName)";}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload
			Write-Verbose "Succeeded"
		} else {
			$IntermediateCACertKeyName = $IntermediateCADetails.certkey
			Write-Verbose "Saving existing name `"$IntermediateCACertKeyName`" for later use"
		}
		$ExistingCertificateDetails = $CertDetails.sslcertkey | Where-Object {$_.certkey -eq $NSCertNameToUpdate}
		if (($NSCertNameToUpdate) -and ($ExistingCertificateDetails)) {
			$CertificateCertKeyName = $($ExistingCertificateDetails.certkey)
			Write-Verbose "Existing certificate `"$($ExistingCertificateDetails.certkey)`" found on the netscaler, start updating"
			try {
				Write-Verbose "Unlinking certificate"
				$payload = @{"certkey"="$($ExistingCertificateDetails.certkey)";}
				$response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action unlink
				
			} catch {
				Write-Verbose "Certificate was not linked"
			}
			$NSUpdating = $true
		} else {
			$CertificateCertKeyName = $CertificateName
			$ExistingCertificateDetails = $CertDetails.sslcertkey | Where-Object {$_.certkey -eq $CertificateCertKeyName}
			if ($ExistingCertificateDetails) {
				Write-Warning "Certificate `"$CertificateCertKeyName`" already exists, please update manually"
				exit(1)
			}
			$NSUpdating = $false
		}
		$CertificateCrtBase64 = [System.Convert]::ToBase64String($(Get-Content $CertificateFullPath -Encoding "Byte"))
		$CertificateKeyBase64 = [System.Convert]::ToBase64String($(Get-Content $CertificateKeyFullPath -Encoding "Byte"))
		Write-Verbose "Uploading the certificate"
		$payload = @{"filename"="$CertificateFileName";"filecontent"="$CertificateCrtBase64";"filelocation"="/nsconfig/ssl/";"fileencoding"="BASE64";}
		$response = InvokeNSRestApi -Session $NSSession -Method POST -Type systemfile -Payload $payload
		
		Write-Verbose "Uploading the certificate key"
		$payload = @{"filename"="$CertificateKeyFileName";"filecontent"="$CertificateKeyBase64";"filelocation"="/nsconfig/ssl/";"fileencoding"="BASE64";}
		$response = InvokeNSRestApi -Session $NSSession -Method POST -Type systemfile -Payload $payload
		Write-Verbose "Finished uploading"
		if ($NSUpdating) {
			Write-Verbose "Update the certificate and key to the NetScaler config"
			$payload = @{"certkey"="$CertificateCertKeyName";"cert"="$($CertificateFileName)";"key"="$($CertificateKeyFileName)"}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action update
			Write-Verbose "Succeeded"
	
		} else {
			Write-Verbose "Add the certificate and key to the NetScaler config"
			$payload = @{"certkey"="$CertificateCertKeyName";"cert"="$($CertificateFileName)";"key"="$($CertificateKeyFileName)"}
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload
			Write-Verbose "Succeeded"
		}
		Write-Verbose "Link `"$CertificateCertKeyName`" to `"$IntermediateCACertKeyName`""
		$payload = @{"certkey"="$CertificateCertKeyName";"linkcertkeyname"="$IntermediateCACertKeyName";}
		$response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action link
		Write-Verbose "Succeeded"
		if ($SaveNSConfig) {
			Write-Verbose "Saving NetScaler configuration"
			InvokeNSRestApi -Session $NSSession -Method POST -Type nsconfig -Action save
		}
		""
		Write-Host -ForeGroundColor Green "Finished with the certificates!"
		if (-not $Production){
			Write-Host -ForeGroundColor Green "You are now ready for the Production version!"
			Write-Host -ForeGroundColor Green "Add the `"-Production`" parameter and rerun the same script."
		}
	} catch {
		throw "ERROR. Certificate completion failed, details: $($_.Exception.Message | Out-String)"
	}
}

#endregion Upload certificates to NetScaler

#region Remove Test Certificates

if ((-not ($CleanNS)) -and $RemoveTestCertificates) {
	Write-Verbose "Login to NetScaler and save session to global variable"
	$NSSession = Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential -PassThru
	$IntermediateCACertKeyName = "Fake LE Intermediate X1"
	$IntermediateCASerial = "8be12a0e5944ed3c546431f097614fe5"
	Write-Verbose "Retreiving existing certificates"
	$CertDetails = InvokeNSRestApi -Session $NSSession -Method GET -Type sslcertkey
	Write-Verbose "Checking if IntermediateCA `"$IntermediateCACertKeyName`" already exists"
	if ($ns10x) {
		$IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.cert -match $IntermediateCAFileName}
	} else {
		$IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.serial -eq $IntermediateCASerial}
	}
	$LinkedCertificates = $CertDetails.sslcertkey | Where-Object {$_.linkcertkeyname -eq $IntermediateCADetails.certkey}
	Write-Verbose "The following certificates were found:`n$($LinkedCertificates | Select-Object certkey,linkcertkeyname,serial | Format-List | Out-String)"
	ForEach ($LinkedCertificate in $LinkedCertificates) {
		$payload = @{"certkey"="$($LinkedCertificate.certkey)";}
		try {
			$response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action unlink
			Write-Host -NoNewLine "NetScaler, unlinked: "
			Write-Host -ForeGroundColor Green "$($LinkedCertificate.certkey)"
		} catch {
			Write-Warning "Could not unlink certkey `"$($LinkedCertificate.certkey)`""
		}
	}
	$FakeCerts = $CertDetails.sslcertkey | Where-Object {$_.issuer -match $IntermediateCACertKeyName}
	ForEach ($FakeCert in $FakeCerts) {
		try {
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type sslcertkey -Resource $($FakeCert.certkey)
			Write-Host -NoNewLine "NetScaler, removing: "
			Write-Host -ForeGroundColor Green "$($FakeCert.certkey)"
		} catch {
			Write-Warning "Could not delete certkey `"$($FakeCert.certkey)`" from the netscaler"
		}
		$CertFilePath = (split-path $($FakeCert.cert) -Parent).Replace("\","/")
		if ([string]::IsNullOrEmpty($CertFilePath)) {
			$CertFilePath = "/nsconfig/ssl/"
		}
		$CertFileName = split-path $($FakeCert.cert) -Leaf
		Write-Host -NoNewLine "NetScaler, deleted: "
		Write-Host -ForeGroundColor Green "$(Join-Path -Path $CertFilePath -ChildPath $CertFileName)"
		$KeyFilePath = (split-path $($FakeCert.key) -Parent).Replace("\","/")
		if ([string]::IsNullOrEmpty($KeyFilePath)) {
			$KeyFilePath = "/nsconfig/ssl/"
		}
		$KeyFileName = split-path $($FakeCert.key) -Leaf
		Write-Host -NoNewLine "NetScaler, deleted: "
		Write-Host -ForeGroundColor Green "$(Join-Path -Path $KeyFilePath -ChildPath $KeyFileName)"
		$Arguments = @{"filelocation"="$CertFilePath";}
		try {
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type systemfile -Resource $CertFileName -Arguments $Arguments
		} catch {
			Write-Warning "Could not delete file: `"$CertFileName`" from location: `"$CertFilePath`""
		}
		$Arguments = @{"filelocation"="$KeyFilePath";}
		try {
			$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type systemfile -Resource $KeyFileName -Arguments $Arguments
		} catch {
			Write-Warning "Could not delete file: `"$KeyFileName`" from location: `"$KeyFilePath`""
		}
		
	}
	$Arguments = @{"filelocation"="/nsconfig/ssl";}
	$CertFiles = InvokeNSRestApi -Session $NSSession -Method Get -Type systemfile -Arguments $Arguments
	$CertFilesToRemove = $CertFiles.systemfile | Where-Object {$_.filename -match "TST-"}
	ForEach ($CertFileToRemove in $CertFilesToRemove) {
		$Arguments = @{"filelocation"="$($CertFileToRemove.filelocation)";}
		try {
		Write-Host -NoNewLine "File deleted: "
		$response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type systemfile -Resource $($CertFileToRemove.filename) -Arguments $Arguments
		Write-Host -ForeGroundColor Green "$($CertFileToRemove.filename)"
		} catch {
			Write-Host -ForeGroundColor Red "$($CertFileToRemove.filename) (Error, not removed)"
			Write-Warning "Could not delete file: `"$($CertFileToRemove.filename)`" from location: `"$($CertFileToRemove.filelocation)`""
		}
	}
}

#endregion Remove Test Certificates

 

And if you want to schedule it you can use the following batchfile (GenLeCertForNS.cmd):

@ECHO OFF
setlocal EnableDelayedExpansion
REM  --> Check for permissions
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
    echo Requesting administrative privileges...
    goto UACPrompt
) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    set params = %*:"=""
    echo UAC.ShellExecute "cmd.exe", "/c %~s0 %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"

    "%temp%\getadmin.vbs"
    del "%temp%\getadmin.vbs"
    exit /B

:gotAdmin
    pushd "%CD%"
    CD /D "%~dp0"

goto StartScript

rem ===== Help Example =====

SET OPTIONS=-CN "domain.com"
SET OPTIONS=%OPTIONS% -EmailAddress "hostmaster@domain.com"
SET OPTIONS=%OPTIONS% -SAN "sts.domain.com","www.domain.com","vpn.domain.com"
SET OPTIONS=%OPTIONS% -PfxPassword "P@ssw0rd"
SET OPTIONS=%OPTIONS% -CertDir "C:\Certificates"
SET OPTIONS=%OPTIONS% -NSManagementURL "http://192.168.100.1"
SET OPTIONS=%OPTIONS% -NSCsVipName "cs_domain.com_http"
SET OPTIONS=%OPTIONS% -NSPassword "P@ssw0rd"
SET OPTIONS=%OPTIONS% -NSUsername "nsroot"
SET OPTIONS=%OPTIONS% -NSCertNameToUpdate "san_domain_com"
rem SET OPTIONS=%OPTIONS% -Production
SET OPTIONS=%OPTIONS% -CleanVault
SET OPTIONS=%OPTIONS% -Verbose

NOTE: Use the "-Production" only if you're sure everything works, you can only use the Let's Encrypt production server 5 times per week.
NOTE: Use the "-Verbose" parameter to get diagnostic output

rem ===== End Help Example =====

:StartScript

SET OPTIONS=-CN "domain.com"
SET OPTIONS=%OPTIONS% -EmailAddress "hostmaster@domain.com"
SET OPTIONS=%OPTIONS% -SAN "sts.domain.com","www.domain.com","vpn.domain.com"
SET OPTIONS=%OPTIONS% -PfxPassword "P@ssw0rd"
SET OPTIONS=%OPTIONS% -CertDir "C:\Certificates"
SET OPTIONS=%OPTIONS% -NSManagementURL "http://192.168.100.1"
SET OPTIONS=%OPTIONS% -NSCsVipName "cs_domain.com_http"
SET OPTIONS=%OPTIONS% -NSPassword "P@ssw0rd"
SET OPTIONS=%OPTIONS% -NSUsername "nsroot"
SET OPTIONS=%OPTIONS% -NSCertNameToUpdate "san_domain_com"
rem SET OPTIONS=%OPTIONS% -Production
SET OPTIONS=%OPTIONS% -CleanVault
SET OPTIONS=%OPTIONS% -Verbose

%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File "%~dp0GenLeCertForNS.ps1" %OPTIONS%

Edit (08-04-2017, v0.6): Removed 2 bugs from the script. Also it currently only supports ipv4

Edit (10-04-2017, v0.7): Changed the “Load Module” region, to also run smoothly on an Server OS, and removed a bug. (Thank you @MartinZugec for helping me with this one)

Edit (23-04-2017, v0.7.1): Changed the “Load Module” region, sometimes the -AllowClobber parameter is needed when installing modules.

Let me know if you have issues with it or have some ideas.

Edit (9-11-2017, v0.8.1): Added the script on GitHub, https://github.com/j81blog/GenLeCertForNS

Edit (24-06-2018, v0.9.4): Fixed some issues in the scipt, merged dev branch into master.


Leave a comment

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

60 thoughts on “Let’s Encrypt Certificates on a NetScaler

  • Edwin de Bruin

    Hey John

    Nice work, have to replace my Startcom/StartSLL certificates for my private home environment. This will fit right in. Awesome.
    Have a nice day and see ya in the office 🙂

    Edwin

    • John Billekens Post author

      Thank you for the feedback. This option is not available in all versions of Windows. But I will change the script, add both options.

  • Daniel

    Having an annoying 404 error that I can’t resolve, this is a 404 from the NetScaler correct? On NS 12.0 build 41.22.

    My command line is: .\letsencrypt.ps1 -CN “citrix.xxxx.com” -CertDir “C:\Users\daniel\Desktop” -NSManagementURL “http://192.168.1.103” -NSCsVipName “LEUpdateVIPforPSScript” -NSPassword “myPassword” -NSUserName “myUsername” -NSCertNameToUpdate “LEServer” -Verbose -CleanVault -EmailAddress “myEmail”

    VERBOSE: JSON Payload:
    {
    “csvserver_cspolicy_binding”: {
    “priority”: “11”,
    “policyname”: “csp_NSCertCsp”,
    “name”: “LEUpdateVIPforPSScript”,
    “targetlbvserver”: “lb_letsencrypt_cert”,
    “gotopriorityexpression”: “END”
    },
    “params”: {
    “onerror”: “EXIT”,
    “warning”: “NO”
    }
    }
    VERBOSE: Error Details: The remote server returned an error: (404) Not Found.
    ERROR: Could not configure the NetScaler, exiting now
    At C:\Users\daniel\Desktop\letsencrypt.ps1:800 char:3
    + throw “ERROR: Could not configure the NetScaler, exiting now”
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (ERROR: Could no…er, exiting now:String) [], RuntimeException
    + FullyQualifiedErrorId : ERROR: Could not configure the NetScaler, exiting now

    • John Billekens Post author

      Hi Daniel,

      Does the “LEUpdateVIPforPSScript” Content Switch VIP exist on the NetScaler? Looks like it doesn’t.
      You can also use the following version https://pastebin.com/Q3B2zCiM, this is a newer version with some more error checking.

      • Daniel

        I incorrectly assumed the script would temporarily create the content switch since it was creating all the policies and bindings… so I created one on port 80 and the script continued.

        The following issue I had was that after uploading the TST certificates to /nsconfig/ssl, the script would bail out on a (599) NetScaler specific error. The files uploaded just fine to the NetScaler, so looking through a bit (I’m not the best at PS) it looks like it’s not supposed to go any further since I was running the test so I wouldn’t hit my rate limit. When I tossed in the -Production argument everything worked out awesome!

        Excellent script and so far the best I’ve seen yet for NetScaler integration. I would suggest that you exit gracefully after the end of a successful test so the end user knows he is good to go with a production run.

        • John Billekens Post author

          Great to hear it worked out! And thank you for your suggestion and compliment.
          What version/build of the NetScaler software are you running. Didn’t hear something about the error 599 before.
          I’ve updated the test version at https://pastebin.com/Q3B2zCiM to return a success message, and a bit of extra info if not running in Production mode.
          Please could you send me the (verbose) output from the console to me (use the contact form).

  • Julien

    Hi, I used it with NetScaler 12.0 53.6 and it worked, thanks a lot!!!

    Only small issue, it seems the certificate is requested twice, I had 2 folders with 2 different certs, and it ends up with an error “Server Returned An Error Response 409 Conflict” with the second one.

    Cheers,
    J

    • John Billekens Post author

      Hi Julien, thank you. I will look into it, and make some changes. I will update this post when the new version is available.

        • John Billekens Post author

          Hi Brian, the 409 error indicates that a resource already exists. So I guess that the certificate you are trying to create already exists on the NetScaler. I hope this helps?

  • Christian

    Hey John,
    nice script and compliments for the work.
    I just started to use lets encrypt with a brand new netscaler vpx and windows 2016 server standard ed.
    The process hangs when creating the ssl cert ( cert + private key) ’cause the ssl cert name exceed the 31 character.
    See image here https://imgur.com/a/pbWzY

    Env: NetScaler VPX NS12.0: Build 53.6.nc and windows 2016 server standard ed.

    Regards
    Christian

    • John Billekens Post author

      Thank you. I will look into it. Unfortunately it won’t be before te beginning of Oktober. On line 1112 is the name being defined. For now I think you can change it to something with less than 31 char.

      E.g. : $CertificateCertKeyName = “yourownname”. Keep in mind that for test certificates(running the script without -production parameter) -TST is being added so max 27 char.

      • Christian

        Hi John,
        thanks for the update and pointing me to the right modifications.
        I’ll try to run the script with -TST parameter and/or modify the line 1112.
        Regards
        Christian

        • John Billekens Post author

          -TST is no parameter for this script. If you don’t add the “-production” parameter a test (staging) certificate will be created. The name will then be “yourname-TST”. A production ready certificate will be created if you specify the “-production” parameter, the name will be “yourname”. If you don’t modify the script, the comonname will be used as name for the certificate.

  • Lars Randers

    Great work, but I wonder if you’d consider throwing the script on Github. Made some alterations already to make it work for the current ACMESharp and I would like to feed them back…

  • Nicola

    hi i’ve this error when i try to run the script on ns 12.x and 11.x (the same error at the same line)

    ERROR. Certificate completion failed, details: Errore del server remoto: (599) Netscaler specific error.
    In GenLeCertForNS-master\GenLeCertForNS.ps1:1508 car:3
    + throw “ERROR. Certificate completion failed, details: $($_.Ex …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (ERROR. Certific…ecific error.
    :String) [], RuntimeException
    + FullyQualifiedErrorId : ERROR. Certificate completion failed, details: Errore del server remoto: (599) Netscaler
    specific error.

    • Nicola

      noway… after a lot of test nothing change..
      ———————————————————————————-
      Finished the tests, script will continue again.
      VERBOSE: Check if DNS Records need to be validated
      Verification:
      VERBOSE: Checking validation for “XXX.com”
      VERBOSE: New validation required, Start verifying
      VERBOSE: Error Details: No registrations found
      VERBOSE: Error Details: Error while creating the Challenge
      Error while verifying “remote.int-drugstore.com”, exiting now
      At C:\Scripts\GenLeCertForNS.ps1:1184 char:5
      + … throw “Error while verifying `”$DNSRecord`”, exiting now” …
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : OperationStopped: (Error while ver…m”, exiting now:String) [], RuntimeException
      + FullyQualifiedErrorId : Error while verifying “remote.int-drugstore.com”, exiting now

  • Michael Switzer

    John,

    Windows 10 didn’t like the script on Github, but the pastebin one worked flawlessly. (not sure if I goofed up somehow)
    I hated the idea of buying certs for my lab, and you’ve basically resolved that.
    Now I’m just waiting on 02/27 when Let’s Encrypt starts issuing wildcards & I’ll be set to test the cooler cSW features of NS (Exchange & cVPN stuff)
    -very cool and much appreciated

    • John Billekens Post author

      Hi Michael, thank you!
      Free certs for my lab was also the main reason I build this script.
      Will look into your issue.

  • Mohamed Ali

    Hi John,

    I’m getting below errors when I run the powershell script

    At C:\LetsEncrypt\GenLeCertForNS.ps1:134 char:19
    +
    + ~
    The ‘<' operator is reserved for future use.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:138 char:19
    +
    + ~
    The ‘<' operator is reserved for future use.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:143 char:19
    +
    + ~
    The ‘<' operator is reserved for future use.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:148 char:19
    +
    + ~
    The ‘<' operator is reserved for future use.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:152 char:19
    +
    + ~
    The ‘
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
    quotation marks (“&”) to pass it as part of a string.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:7196 char:10
    +
    + ~
    The ‘<' operator is reserved for future use.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:7212 char:24
    + © 2018 <span title="0.41498s from unicorn-5bf86db8b6 …
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
    quotation marks ("&") to pass it as part of a string.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:7212 char:36
    + © 2018 <span title="0.41498s from unicorn-5bf86db8b6 …
    + ~
    The '<' operator is reserved for future use.
    At C:\LetsEncrypt\GenLeCertForNS.ps1:7212 char:42
    + © 2018 GitHub‘ in expression or statement.
    Not all parse errors were reported. Correct the reported errors and try again.
    + CategoryInfo : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : RedirectionNotSupported

  • Markus

    Hi John,

    really good idea to use NetScaler.
    But I have problems to get a certificate issued. The script always aborts with “Error while verifying “mydomain.my”, exiting now”
    Do you have any ideas what the reason could be?

    Thank you

    Regards
    Markus

    • John Billekens Post author

      Hi Markus, that can have several reasons. Can you run it with the -verbose parameter and send me the output?

      • Markus

        Error while verifying “……….”, exiting now
        At C:\LE\GenLeCertForNS-master\GenLeCertForNS.ps1:928 char:5
        + throw “Error while verifying `”$($DNSObject.DNSName)`”, exiting now”
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : OperationStopped: (Error while ver…t”, exiting now:String) [], RuntimeException
        + FullyQualifiedErrorId : Error while verifying “……….”, exiting now

        • Markus

          Hi John,

          now with more info:

          VERBOSE: Wait 1 second
          VERBOSE: Start Submitting Challenge
          VERBOSE: Retreiving validation status
          VERBOSE: (1) mpmj.at is not (yet) validated, Wait 2 second
          VERBOSE: Retreiving validation status
          VERBOSE: (2) mpmj.at is not (yet) validated, Wait 2 second
          VERBOSE: Retreiving validation status
          VERBOSE: (3) mpmj.at is not (yet) validated, Wait 2 second
          VERBOSE: Retreiving validation status
          VERBOSE: (4) mpmj.at is not (yet) validated, Wait 2 second
          VERBOSE: Retreiving validation status
          VERBOSE: Error Details: ERROR. Validation for “……..” is invalid! Exiting now.
          Error while verifying “……..”, exiting now
          At C:\LE\GenLeCertForNS-master\GenLeCertForNS.ps1:928 char:5
          + throw “Error while verifying `”$($DNSObject.DNSName)`”, exiting now”
          + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo : OperationStopped: (Error while ver…t”, exiting now:String) [], RuntimeException
          + FullyQualifiedErrorId : Error while verifying “……..”, exiting now

          Thank you

  • Brian Vickers

    We’ve done about 2,000 certificates in the last 60 days through this process and, as long as we have made sure internal and external DNS is correct there have been no issues, but have come across an error that we can’t seem to solve. We’ve double and triple checked everything and compared to several of the other domains, but we’re coming up empty. Even adding the Force flag doesn’t work.

    VERBOSE: Wait 1 second
    VERBOSE: Start Submitting Challenge
    PS>TerminatingError(Submit-ACMEChallenge): “authorization already contains challenges in an invalid state; use Force flag to override this validation”
    VERBOSE: Error Details: authorization already contains challenges in an invalid state; use Force flag to override this validation
    VERBOSE: Error Details: Error while submitting the Challenge
    PS>TerminatingError(): “Error while verifying “www.xxxxxxventuracounty.com”, exiting now”
    At C:\Scripts\FranchiseCerts\Production\Prod-SanCertificate23-LetsEncrCertForNS.ps1:1237 char:5
    + … throw “Error while verifying `”$DNSRecord`”, exiting now” …

  • Michael

    Hey John,
    i’ve tried new version and find an issue at #region DNS Check $CompletedChallenge –> unknown parameter -Force.
    Otherwise, great work. Thanks a lot!

    Michael

  • Andrew

    Hi John,

    I have come across the following when using the script and wondered if you knew of the fix?

    Please create the following TXT records:
    ——————————————
    _acme-challenge.remote.domain.dot.dot -> Bn4GY_5_2DHhFL-cFx2xUoRsOLKecDKsLG_mes2kCvI
    ——————————————

    VERBOSE: Saving TXT record to display when Save-DnsTxtManual is called.
    VERBOSE: Saving changes for Manual plugin

    Please remove the following TXT records:
    ——————————————
    _acme-challenge.remote.domain.dot.dot -> Bn4GY_5_2DHhFL-cFx2xUoRsOLKecDKsLG_mes2kCvI
    ——————————————

    Read-Host : Windows PowerShell is in NonInteractive mode. Read and Prompt functionality is not available.
    At C:\Program Files\WindowsPowerShell\Modules\Posh-ACME\3.1.1\DnsPlugins\Manual.ps1:98 char:9
    + Read-Host -Prompt “Press any key to continue.” | Out-Null
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [Read-Host], PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.ReadHostCommand

    VERBOSE: POST https://acme-staging-v02.api.letsencrypt.org/acme/order/8383977/24545553 with -1-byte payload
    VERBOSE: received 382-byte response of content type application/json
    VERBOSE:
    VERBOSE: Create directory “C:\Certificates\CRT-SAN-20190228-095636-remote.domain.dot.dot” for storing the new
    certificates
    VERBOSE: Writing test/staging certificates
    VERBOSE: Intermediate: “Fake LE Intermediate X1-int.crt”
    Certificate file missing: C:\Users\Administrator\AppData\Local\Posh-ACME\acme-staging-v02.api.letsencrypt.org\8383977\r
    emote.domain.dot.dot\cert.cer
    At C:\Program Files\WindowsPowerShell\Modules\Posh-ACME\3.1.1\Public\Get-PACertificate.ps1:58 char:17
    + throw “Certificate file missing: $certFile”
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (Certificate fil….me.uk\cert.cer:String) [], RuntimeException
    + FullyQualifiedErrorId : Certificate file missing: C:\Users\Administrator\AppData\Local\Posh-ACME\acme-staging-v0
    2.api.letsencrypt.org\8383977\remote.domain.dot.dot\cert.cer

  • Michael

    Hey John,

    nice work. I’ve automated the renewal of the certificates and I run into a limitation. On the Let’s Encrypt website I found the following:
    “You can create a maximum of 10 Accounts per IP Address per 3 hours. You can create a maximum of 500 Accounts per IP Range within an IPv6 /48 per 3 hours.”
    Is it possible to run your powershell script with only one account? Kindly refer to https://letsencrypt.org/docs/integration-guide/ section “One Account or Many?”

    Thanks,
    Michael

  • Roger

    Hi John

    I’m setting up a test for automatic renewal of LE certs, and I run into the problem that the script cannot register a new account.
    My initial situation for the test setup is, that I don’t actually have a LE certificate issued. Maybe this is my first failure…

    Anyway, when running the script the error is:

    VERBOSE: received 563-byte response of content type application/json
    VERBOSE: Setting new registration to “MYEMAILADRESS”
    VERBOSE: POST https://acme-staging-v02.api.letsencrypt.org/acme/new-acct with -1-byte payload
    VERBOSE: received 563-byte response of content type application/json
    VERBOSE: Error New registration failed!
    VERBOSE: Error Details: You cannot call a method on a null-valued expression.

    What do I not understand in the procedure with LetsEncrypt?

    • John Billekens Post author

      Please send me the log by mail then I can verify it. You can enable logging by specifying the log parameter. Did you specify a valid mail address?

      • John Billekens Post author

        An updated version of the script is available in the dev section. It will solve this issue. I will push it to production version soon

  • Niklas Karg

    Hey i have made a regex command policy for netscaler for a user that have the least possible rights to run your Script:

    (^convert\s+ssl\s+pkcs12)|(^show\s+responder\s+action)|(^show\s+responder\s+policy)|(^(add|rm)\s+system\s+file.*-fileLocation.*nsconfig.*ssl.*)|(^show\s+ssl\s+certKey)|(^(add|link|unlink|update)\s+ssl\s+certKey\s+.*)|(^save\s+ns\s+config)|(^save\s+ns\s+config\s+.*)|(^show\s+ns\s+version)|(^(set|show|bind|unbind)\s+cs\s+vserver\s+csw_le_.*)|(^\S+\s+Service\s+svc_letsencrypt_.*)|(^\S+\s+lb\s+vserver\s+lb_letsencrypt.*)|(^\S+\s+responder\s+action\s+rsa_letsencrypt_.*)|(^\S+\s+responder\s+policy\s+rsp_letsencrypt_.*)|(^\S+\s+cs\s+policy\s+csp_letsencrypt_.*)

    To make this work, i added the powershell switch “-NSCspName “csp_letsencrypt_” so that the content switch policy always starts with “csp_letsencrypt” which is allowed by the regex. I also uncommented lines 1693-1695 of ur script because he does not always need to activate netscaler services and i dont want that user to have this right. It would be nice if there was a commandline switch to disable this behavior on every run. I hope this is useful for some of the people here.

    • John Billekens Post author

      Hi Niklas, thank you very much for your addition.
      Much appreciated!
      In my latest (dev) version I changed the features, it will now only enable them if they are disabled.

      • John Billekens Post author

        I liked the idea so much, I added it as an option to the script. You can now create the command policy and a user via the script.
        .\GenLeCertForNS.ps1 -CreateUserPermissions -CreateApiUser -NSCsVipName “CSVIPNAME” -ApiUsername “le-user” -ApiPassword “LEP@ssw0rd” -NSCPName “MinLePermissionGroup” -NSUsername nsroot -NSPassword “nsroot” -NSManagementURL https://citrixadc.domain.local
        This command will create a Command Policy with the minimum set of permissions, you need to run this once to create (or when you want to change something).
        Be sure to run the script next with the same parameters as specified when running this command, the same for -NSSvcName (Default “svc_letsencrypt_cert_dummy”), -NSLbName (Default: “lb_letsencrypt_cert”), -NSRspName (Default: “rsp_letsencrypt”), -NSRsaName (Default: “rsa_letsencrypt”), -NSCspName (Default: “csp_NSCertCsp”)
        Next time you want to generate certificates you can specify the new user -NSUsername le-user -NSPassword “LEP@ssw0rd”

  • Andrea

    Please help me!
    I am no more able to update my cert after several months.
    Here is the debug log:

    **********************
    LogFile: E:\nscert\GenLeCertForNS\GenLeCertForNS.txt
    Start time: 2020-12-30 14:19:54
    Username: PAMA\andrea.delutti
    RunAs Admin: True
    Machine: DELUTTINBK (Microsoft Windows NT 10.0.19041.0)
    PSCulture: it-IT
    PSVersion: 5.1.19041.1
    PSEdition: Desktop
    PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.19041.1
    BuildVersion: 10.0.19041.1
    PSCommandPath: E:\nscert\GenLeCertForNS\GenLeCertForNS.ps1
    LanguageMode: FullLanguage
    ScriptBase: E:\nscert\GenLeCertForNS
    Script Version: 2.8.1
    PoSH ACME Version: 3.17.0
    PSBoundParameters:

    Key Value
    — —–
    CN citrix.pama.it
    EmailAddress grp.ced@pama.it
    PfxPassword cleared
    CertDir E:\nscert\GenLeCertForNS\certs
    ManagementURL http://172.16.0.15
    CsVipName {cs_letsencrypt}
    Password nsroot
    Username nsroot
    CertKeyNameToUpdate citrix.pama.it
    DisableIPCheck True
    Production True
    LogLevel Debug

    **********************

    2020-12-30 14:19:54:7001 INFO [SCRIPTBASICS] Starting a new log
    2020-12-30 14:19:54:7308 INFO [SCRIPTVARIABLES] PfxPassword was specified via parameter.
    2020-12-30 14:19:54:7339 INFO [DOTNETCHECK] Checking if .NET Framework 4.7.1 or higher is installed.
    2020-12-30 14:19:54:7480 INFO [DOTNETCHECK] .NET Framework 4.7.1 or higher is installed.
    2020-12-30 14:19:54:7620 INFO [LOADMODULE] Try loading the Posh-ACME v3.17.0 Modules.
    2020-12-30 14:20:03:1360 INFO [LOADMODULE] v3.17.0 of Posh-ACME is installed, loading module.
    2020-12-30 14:20:03:1517 INFO [LOADMODULE] Posh-ACME loaded successfully.
    2020-12-30 14:20:03:1557 INFO [VERSIONINFO] Current script version: v2.8.1, checking if a new version is available.
    2020-12-30 14:20:03:1586 DEBUG [INVOKE-CHECKSCRIPTVERSIONS] Retrieving data for URI: https://drive.google.com/uc?export=download&id=1WOySj40yNHEza23b7eZ7wzWKymKv64JW
    2020-12-30 14:20:03:7808 DEBUG [INVOKE-CHECKSCRIPTVERSIONS] Successfully retrieved the requested data
    2020-12-30 14:20:03:7857 INFO [VERSIONINFO] No new Master version available
    2020-12-30 14:20:03:8029 INFO [VERSIONINFO] No new Development version available
    2020-12-30 14:20:03:8079 INFO [VERSIONINFO] Version check finished.
    2020-12-30 14:20:03:8165 INFO [ADC-CHECK] Trying to login into the Citrix ADC.
    2020-12-30 14:20:03:8381 INFO [CONNECT-ADC] Connecting to http://172.16.0.15
    2020-12-30 14:20:04:0353 DEBUG [CONNECT-ADC] Response: {“message”:”Done”,”severity”:”NONE”,”errorcode”:0}
    2020-12-30 14:20:04:0455 DEBUG [CONNECT-ADC] Trying to retrieve the ADC version
    2020-12-30 14:20:04:1165 DEBUG [CONNECT-ADC] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsversion”:{“version”:”NetScaler NS12.0: Build 63.13.nc, Date: Jan 16 2020, 05:08:11 “,”mode”:”1″}}
    2020-12-30 14:20:04:1241 INFO [CONNECT-ADC] Connected
    2020-12-30 14:20:04:1314 INFO [CONNECT-ADC] Connected to Citrix ADC http://172.16.0.15, as user nsroot, ADC Version NetScaler NS12.0: Build 63.13.nc
    2020-12-30 14:20:05:4146 INFO [SERVICES] By running this script you agree with the terms specified by Let’s Encrypt.
    2020-12-30 14:20:05:4492 INFO [SERVICES] Terms Of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
    2020-12-30 14:20:05:4675 INFO [SERVICES] Website: https://letsencrypt.org
    2020-12-30 14:20:05:4886 INFO [SERVICES] LE Certificate Usage: Production Certificates
    2020-12-30 14:20:05:5061 INFO [SERVICES] LE Account Storage: C:\Users\andrea.delutti\AppData\Local\Posh-ACME
    2020-12-30 14:20:05:5135 INFO [CERTLOOP] 1 required for all requests.
    2020-12-30 14:20:05:5181 INFO [CERTLOOP-01] **************************************** 01 ****************************************
    2020-12-30 14:20:05:5198 INFO [CERTLOOP] Round: 1 / 1
    2020-12-30 14:20:05:5349 DEBUG [CERTREQVARIABLES] Setting session DATE/TIME variable.
    2020-12-30 14:20:05:5406 DEBUG [CERTREQVARIABLES] Session DATE/TIME variable value: “20201230-142005”.
    2020-12-30 14:20:05:5416 DEBUG [CERTREQVARIABLES] Session ID value: “20201230-142005_citrix_pama_it”.
    2020-12-30 14:20:05:5548 INFO [ADC-CS-VALIDATION] Verifying Content Switch.
    2020-12-30 14:20:05:5570 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver/cs_letsencrypt”, METHOD: “GET”
    2020-12-30 14:20:05:6446 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”csvserver”:[{“name”:”CS_LetsEncrypt”,”insertvserveripport”:”OFF”,”ip”:”0.0.0.0″,”td”:”0″,”ipv46″:”172.16.0.18″,”ippattern”:”0.0.0.0″,”ipmask”:”*”,”port”:80,”range”:”1″,”servicetype”:”HTTP”,”type”:”CONTENT”,”curstate”:”UP”,”sc”:”OFF”,”stateupdate”:”DISABLED”,”status”:1,”cachetype”:”SERVER”,”precedence”:”RULE”,”authentication”:”OFF”,”authn401″:”OFF”,”casesensitive”:”ON”,”hits”:”0″,”pipolicyhits”:”0″,”weight”:”0″,”priority”:”0″,”clttimeout”:”180″,”listenpolicy”:”NONE”,”somethod”:”NONE”,”sopersistence”:”DISABLED”,”sopersistencetimeout”:”2″,”cacheable”:”NO”,”redirectportrewrite”:”DISABLED”,”downstateflush”:”ENABLED”,”disableprimaryondown”:”DISABLED”,”invoke”:false,”gt2gb”:”DISABLED”,”statechangetimesec”:”Thu Dec 24 19:02:38 2020″,”statechangetimemsec”:”513″,”tickssincelaststatechange”:”49784709″,”rtspnat”:”OFF”,”push”:”DISABLED”,”pushlabel”:”none”,”pushmulticlients”:”NO”,”l2conn”:”OFF”,”ruletype”:”2″,”appflowlog”:”ENABLED”,”icmpvsrresponse”:”PASSIVE”,”rhistate”:”PASSIVE”,”ttl”:0,”cookietimeout”:0,”sitedomainttl”:0,”dnsrecordtype”:”A”}]}
    2020-12-30 14:20:05:6562 INFO [ADC-CS-VALIDATION] Content Switch OK
    2020-12-30 14:20:05:6733 INFO [DNSPRECHECK] CN: citrix.pama.it is a valid record
    2020-12-30 14:20:05:6833 DEBUG [DNSPRECHECK] ValidationMethod is set to: “http”.
    2020-12-30 14:20:05:6859 DEBUG [DNSPRECHECK] DNS Data:
    2020-12-30 14:20:05:6885 DEBUG [DNSPRECHECK] {“DNSName”:”citrix.pama.it”,”SAN”:false}
    2020-12-30 14:20:05:6998 INFO [REGISTRATION] Try to retrieve the existing Registration.
    2020-12-30 14:20:06:0964 INFO [REGISTRATION] Existing registration found, no changes necessary.
    2020-12-30 14:20:06:1003 INFO [REGISTRATION] Account 107316800 set as default.
    2020-12-30 14:20:06:4452 DEBUG [REGISTRATION] Registration: {“id”:”107316800″,”status”:”valid”,”contact”:[“mailto:grp.ced@pama.it”],”location”:”https://acme-v02.api.letsencrypt.org/acme/acct/107316800″,”key”:{“d”:”BxN9ZgDaFrqZzwPS3F-3IPbxcr3rr6FF3CBmmTY1VnrJDeBK5GxpOsyXLhU2FkU7Dn5rHBFVRjhb99ywFWHw8xAFJdwBJyJUQzijsdXeyiMarXG0vVtmCUo8g8XNhJgaLB_-Lc_VEfqXmTf6FJUmdbdKVmOjc_9XVZ-SkrbMAm9Wobs8ZRgwROISAqDbJMemtaG40R7qXzTiPczYNHQX34MHL19W203jnoUMU8Vs6ILmsAXo0XjTtp4g5gW0h-HxPu5oYzjMJ9R1dCHHAU312P1mOxDgY0Ixa9YZ_FP3O2d2lk_lc40jvzHt0-fT9M1hbDhyS29RNf3va_b4tkArnQ”,”dp”:”3nbMgw0R7DHan0o3Le6XXINbN4u7TUjBccbxZbzUpI2DIt9mu6S6nJ0bqpnudXF1gfPsz2poEXb8gvq4jUW-NJbpy-DUW5dDx3IFFWNo9_dzS86I54DJtuiwMMoeFKVBuA81n3kB2S0oEICzf_6ueR4VP-3sxM2v97VJ3a604YU”,”dq”:”nmqDXXQ8P0LqMlvS5UaVU8FwMSMJNr1f6QwXf7w_nF_34LKGI8BhJdPAEBUBgGHzQUII8KpzZIp2u1yAJnqYAP9ETAmtUX0lRw2mNurxHMap3BBrd4yZ0dNHHNr_fxbeabA-4wEUSBo2FBaMZCIv1GRF7lepkTmgxjMdJnpYnHE”,”e”:”AQAB”,”kty”:”RSA”,”n”:”uUbtOz6ANntmv9Wk_lH5unV03uZfRsWMKSRh8SZpAcBV-wYc6lkmek4jQJO0q8GKwxdhhRumXAMWa94J02jeP7czOoSnpYiu2R_m42uOrXON6ibiWJYUuv2grbMD0yno6JhsmTZmQgldxNceo1xCKOKm4jwfdtM8i2T3vq7DecCPO5SVdOga72VuK1XXmnH99dv6a5z8FRr7x8xawCCaFV_nwk4bUTbbMAEqoBI6OWhNBkTjvSPqjUKdPMSOovYQFHISoZrwat-gwMZbJQMbLV3HPhTCxiWpnAUQfbtOEdznGjPgTs0rr12PPTIMGjUoBlk1SL1ozqJop37JPsED6Q”,”p”:”5CuZ9O7Et_TPNv64Rz2ZbtXkTbAHJsYmlWhc71F9zEtRnJJaBxTFJs4Cay9qcnhY_MrpEqSABwwlsy-_CE1q09y0jg-YAw8ynItwurMULoH_CRX3QhqnxSnxeINnqABIKxSTVWL4lLaJL24_anVZUUqyTugNeO45BkNUYNxUU8s”,”q”:”z-AGRhO7ibwPhvs6r2PSX1UbhzaMyE6E-WCnXWPDmfmf97AnztOIn1_HbnR3Bt2dWy7sC0DE58Enmb9vBLBRVUng-bc4r7kYLIwk7cIfSTxFj15PrKKi8xF5LFaV-CjUP-FfHAHCdMbzkQVKzv2Z2NHB2TIw17UiKDSrNTkd2Js”,”qi”:”xRmNRxCvdVY0MQcrf9rEuuZUpVNzLFsYcQ4vMaOSGo0p8pxzB4VyXHi-rdsk8Rfebit0dWIRLZgKKPNtSKe-XLRMS9EOtfKmt6TRIOQfF_DBy5CW3H8V35gzu-gMbRxf_Gxpo6GR96DS4iFAfjCIlTDBgabGw9hn5_0ZeZHtvUA”},”alg”:”RS256″,”KeyLength”:”2048″,”orders”:null}.
    2020-12-30 14:20:06:4474 INFO [REGISTRATION] Registration ID: 107316800, Status: valid.
    2020-12-30 14:20:06:4494 INFO [REGISTRATION] Setting Account as default for new order.
    2020-12-30 14:20:06:4554 INFO [ORDER] Trying to create a new order.
    2020-12-30 14:20:08:8359 DEBUG [ORDER] Order data:
    2020-12-30 14:20:08:8543 DEBUG [ORDER] {“MainDomain”:”citrix.pama.it”,”FriendlyName”:”citrix.pama.it”,”SANs”:[],”status”:”pending”,”expires”:”2021-01-06T12:12:57Z”,”KeyLength”:”2048″}
    2020-12-30 14:20:09:8413 DEBUG [ORDER] Challenge status:
    2020-12-30 14:20:09:8539 DEBUG [ORDER] {“DNSId”:”citrix.pama.it”,”status”:”pending”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}
    2020-12-30 14:20:09:8738 INFO [ORDER] Order created successfully.
    2020-12-30 14:20:10:0765 INFO [DNS-VALIDATION] Validate DNS record(s).
    2020-12-30 14:20:10:2233 INFO [DNS-VALIDATION] “NoIPCheck/(citrix.pama.it)” is the first entry, continuing.
    2020-12-30 14:20:10:2293 DEBUG [DNS-VALIDATION] SAN Objects:
    2020-12-30 14:20:10:2359 DEBUG [DNS-VALIDATION] {“DNSName”:”citrix.pama.it”,”IPAddress”:”NoIPCheck”,”Status”:true,”Match”:true}
    2020-12-30 14:20:10:2574 INFO [DNS-VALIDATION] Checking for invalid DNS Records.
    2020-12-30 14:20:10:2645 INFO [DNS-VALIDATION] None found, continuing
    2020-12-30 14:20:10:2676 INFO [DNS-VALIDATION] Checking non-matching DNS Records
    2020-12-30 14:20:10:2695 INFO [DNS-VALIDATION] IP Addresses checking was skipped.
    2020-12-30 14:20:10:2829 INFO [CHECKORDERVALIDATION] Checking if validation is required.
    2020-12-30 14:20:11:0219 DEBUG [CHECKORDERVALIDATION] validations required:
    2020-12-30 14:20:11:0343 DEBUG [CHECKORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”HTTP01Status”:”pending”,”expires”:”2021-01-06T12:12:57Z”}
    2020-12-30 14:20:11:0427 INFO [CHECKORDERVALIDATION] Validation IS required.
    2020-12-30 14:20:11:0511 DEBUG [CHECKORDERVALIDATION] ADC actions required: True.
    2020-12-30 14:20:11:0571 INFO [INVOKE-ADDINITIALADCCONFIG] Trying to login into the Citrix ADC.
    2020-12-30 14:20:11:0709 INFO [CONNECT-ADC] Connecting to http://172.16.0.15
    2020-12-30 14:20:11:1753 DEBUG [CONNECT-ADC] Response: {“message”:”Done”,”severity”:”NONE”,”errorcode”:0}
    2020-12-30 14:20:11:1847 DEBUG [CONNECT-ADC] Trying to retrieve the ADC version
    2020-12-30 14:20:11:2499 DEBUG [CONNECT-ADC] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsversion”:{“version”:”NetScaler NS12.0: Build 63.13.nc, Date: Jan 16 2020, 05:08:11 “,”mode”:”1″}}
    2020-12-30 14:20:11:2538 INFO [CONNECT-ADC] Connected
    2020-12-30 14:20:11:2564 INFO [CONNECT-ADC] Connected to Citrix ADC http://172.16.0.15, as user nsroot, ADC Version NetScaler NS12.0: Build 63.13.nc
    2020-12-30 14:20:11:2585 INFO [INVOKE-ADDINITIALADCCONFIG] Enabling required ADC Features: Load Balancer, Responder, Content Switch and SSL.
    2020-12-30 14:20:11:2662 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/nsfeature”, METHOD: “GET”
    2020-12-30 14:20:11:3379 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsfeature”:{“feature”:[“WL”,”LB”,”CS”,”SSL”,”SSLVPN”,”RESPONDER”,”CH”],”wl”:true,”sp”:false,”lb”:true,”cs”:true,”cr”:false,”sc”:false,”cmp”:false,”pq”:false,”ssl”:true,”gslb”:false,”hdosp”:false,”cf”:false,”ic”:false,”sslvpn”:true,”aaa”:false,”ospf”:false,”rip”:false,”bgp”:false,”rewrite”:false,”ipv6pt”:false,”appfw”:false,”responder”:true,”htmlinjection”:false,”push”:false,”appflow”:false,”cloudbridge”:false,”isis”:false,”ch”:true,”appqoe”:false,”contentaccelerator”:false,”rise”:false,”feo”:false,”lsn”:false,”rdpproxy”:false,”rep”:false,”urlfiltering”:false,”videooptimization”:false,”forwardproxy”:false,”sslinterception”:false,”adaptivetcp”:false,”cqa”:false,”ci”:false}}
    2020-12-30 14:20:11:3467 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “LB” already enabled.
    2020-12-30 14:20:11:3549 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “RESPONDER” already enabled.
    2020-12-30 14:20:11:3647 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “CS” already enabled.
    2020-12-30 14:20:11:3727 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “SSL” already enabled.
    2020-12-30 14:20:11:3791 INFO [INVOKE-ADDINITIALADCCONFIG] Features enabled, verifying Content Switch.
    2020-12-30 14:20:11:3847 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver/cs_letsencrypt”, METHOD: “GET”
    2020-12-30 14:20:11:4564 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”csvserver”:[{“name”:”CS_LetsEncrypt”,”insertvserveripport”:”OFF”,”ip”:”0.0.0.0″,”td”:”0″,”ipv46″:”172.16.0.18″,”ippattern”:”0.0.0.0″,”ipmask”:”*”,”port”:80,”range”:”1″,”servicetype”:”HTTP”,”type”:”CONTENT”,”curstate”:”UP”,”sc”:”OFF”,”stateupdate”:”DISABLED”,”status”:1,”cachetype”:”SERVER”,”precedence”:”RULE”,”authentication”:”OFF”,”authn401″:”OFF”,”casesensitive”:”ON”,”hits”:”0″,”pipolicyhits”:”0″,”weight”:”0″,”priority”:”0″,”clttimeout”:”180″,”listenpolicy”:”NONE”,”somethod”:”NONE”,”sopersistence”:”DISABLED”,”sopersistencetimeout”:”2″,”cacheable”:”NO”,”redirectportrewrite”:”DISABLED”,”downstateflush”:”ENABLED”,”disableprimaryondown”:”DISABLED”,”invoke”:false,”gt2gb”:”DISABLED”,”statechangetimesec”:”Thu Dec 24 19:02:38 2020″,”statechangetimemsec”:”638″,”tickssincelaststatechange”:”49785279″,”rtspnat”:”OFF”,”push”:”DISABLED”,”pushlabel”:”none”,”pushmulticlients”:”NO”,”l2conn”:”OFF”,”ruletype”:”2″,”appflowlog”:”ENABLED”,”icmpvsrresponse”:”PASSIVE”,”rhistate”:”PASSIVE”,”ttl”:0,”cookietimeout”:0,”sitedomainttl”:0,”dnsrecordtype”:”A”}]}
    2020-12-30 14:20:11:4690 INFO [INVOKE-ADDINITIALADCCONFIG] Content Switch is OK, check if Load Balancer Service exists.
    2020-12-30 14:20:11:4725 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service/svc_letsencrypt_cert_dummy”, METHOD: “GET”
    2020-12-30 14:20:11:5676 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
    2020-12-30 14:20:11:5708 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balancer Service does not exist, create Load Balance Service “svc_letsencrypt_cert_dummy”.
    2020-12-30 14:20:11:5798 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service?action=add”, METHOD: “POST”
    2020-12-30 14:20:11:5864 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”service\”:{\”port\”:\”80\”,\”ip\”:\”1.2.3.4\”,\”name\”:\”svc_letsencrypt_cert_dummy\”,\”servicetype\”:\”HTTP\”,\”healthmonitor\”:\”NO\”}}”
    2020-12-30 14:20:11:6792 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balance Service created.
    2020-12-30 14:20:11:6835 INFO [INVOKE-ADDINITIALADCCONFIG] Check if Load Balance VIP exists.
    2020-12-30 14:20:11:6864 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver/lb_letsencrypt_cert”, METHOD: “GET”
    2020-12-30 14:20:11:7732 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”lbvserver”:[{“name”:”lb_letsencrypt_cert”,”insertvserveripport”:”OFF”,”ipv46″:”0.0.0.0″,”ippattern”:”0.0.0.0″,”ipmask”:”*”,”listenpolicy”:”NONE”,”ipmapping”:”0.0.0.0″,”port”:0,”range”:”1″,”servicetype”:”HTTP”,”type”:”ADDRESS”,”curstate”:”DOWN”,”effectivestate”:”DOWN”,”status”:2,”lbrrreason”:4,”cachetype”:”SERVER”,”authentication”:”OFF”,”authn401″:”OFF”,”dynamicweight”:”0″,”priority”:”0″,”clttimeout”:”180″,”somethod”:”NONE”,”sopersistence”:”DISABLED”,”sopersistencetimeout”:”2″,”healththreshold”:”0″,”lbmethod”:”LEASTCONNECTION”,”backuplbmethod”:”ROUNDROBIN”,”dataoffset”:”0″,”health”:”0″,”datalength”:”0″,”ruletype”:”0″,”m”:”IP”,”persistencetype”:”NONE”,”timeout”:2,”persistmask”:”255.255.255.255″,”v6persistmasklen”:”128″,”persistencebackup”:”NONE”,”cacheable”:”NO”,”rtspnat”:”OFF”,”sessionless”:”DISABLED”,”trofspersistence”:”ENABLED”,”map”:”OFF”,”connfailover”:”DISABLED”,”redirectportrewrite”:”DISABLED”,”downstateflush”:”ENABLED”,”disableprimaryondown”:”DISABLED”,”gt2gb”:”DISABLED”,”consolidatedlconn”:”GLOBAL”,”consolidatedlconngbl”:”YES”,”thresholdvalue”:0,”invoke”:false,”version”:0,”totalservices”:”0″,”activeservices”:”0″,”statechangetimesec”:”Wed Dec 30 13:19:45 2020″,”statechangetimeseconds”:”1609334385″,”statechangetimemsec”:”233″,”tickssincelaststatechange”:”2650″,”hits”:”0″,”pipolicyhits”:”0″,”push”:”DISABLED”,”pushlabel”:”none”,”pushmulticlients”:”NO”,”policysubtype”:”0″,”l2conn”:”OFF”,”appflowlog”:”ENABLED”,”isgslb”:false,”icmpvsrresponse”:”PASSIVE”,”rhistate”:”PASSIVE”,”newservicerequestunit”:”PER_SECOND”,”vsvrbindsvcip”:”0.0.0.0″,”vsvrbindsvcport”:0,”skippersistency”:”None”,”td”:”0″,”minautoscalemembers”:”0″,”maxautoscalemembers”:”0″,”macmoderetainvlan”:”DISABLED”,”dns64″:”DISABLED”,”bypassaaaa”:”NO”,”processlocal”:”DISABLED”,”vsvrdynconnsothreshold”:”0″,”retainconnectionsoncluster”:”NO”}]}
    2020-12-30 14:20:11:7782 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balance VIP exists, continuing
    2020-12-30 14:20:11:7882 INFO [INVOKE-ADDINITIALADCCONFIG] Checking if LB Service “svc_letsencrypt_cert_dummy” is bound to Load Balance VIP “lb_letsencrypt_cert”.
    2020-12-30 14:20:11:8030 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_service_binding/lb_letsencrypt_cert”, METHOD: “GET”
    2020-12-30 14:20:11:8863 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
    2020-12-30 14:20:11:8947 INFO [INVOKE-ADDINITIALADCCONFIG] LB Service binding must be configured
    2020-12-30 14:20:11:9023 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_service_binding”, METHOD: “PUT”
    2020-12-30 14:20:11:9078 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”lbvserver_service_binding\”:{\”name\”:\”lb_letsencrypt_cert\”,\”servicename\”:\”svc_letsencrypt_cert_dummy\”}}”
    2020-12-30 14:20:12:1386 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
    2020-12-30 14:20:12:1446 INFO [INVOKE-ADDINITIALADCCONFIG] LB Service binding is OK
    2020-12-30 14:20:12:1593 INFO [INVOKE-ADDINITIALADCCONFIG] Checking if Responder Policies exists starting with “rsp_letsencrypt”
    2020-12-30 14:20:12:1731 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?filter=name:%2Frsp_letsencrypt%2F”, METHOD: “GET”
    2020-12-30 14:20:12:2518 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
    2020-12-30 14:20:12:2614 INFO [INVOKE-ADDINITIALADCCONFIG] No Responder Policies found.
    2020-12-30 14:20:12:2837 INFO [INVOKE-ADDINITIALADCCONFIG] Checking if Responder Actions exists starting with “rsa_letsencrypt”.
    2020-12-30 14:20:12:3177 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?filter=name:%2Frsa_letsencrypt%2F”, METHOD: “GET”
    2020-12-30 14:20:12:3865 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
    2020-12-30 14:20:12:3875 INFO [INVOKE-ADDINITIALADCCONFIG] No Responder Actions found.
    2020-12-30 14:20:12:3935 DEBUG [INVOKE-ADDINITIALADCCONFIG] Creating a test Responder Action.
    2020-12-30 14:20:12:3952 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?action=add”, METHOD: “POST”
    2020-12-30 14:20:12:4022 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderaction\”:{\”name\”:\”rsa_letsencrypt_test\”,\”target\”:\”\\\”HTTP/1.0 200 OK\\\” +\\\”\\\\r\\\\n\\\\r\\\\n\\\” + \\\”XXXX\\\”\”,\”type\”:\”respondwith\”}}”
    2020-12-30 14:20:12:5027 DEBUG [INVOKE-ADDINITIALADCCONFIG] Responder Action created, creating a test Responder Policy.
    2020-12-30 14:20:12:5055 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?action=add”, METHOD: “POST”
    2020-12-30 14:20:12:5124 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderpolicy\”:{\”rule\”:\”HTTP.REQ.URL.CONTAINS(\\\”.well-known/acme-challenge/XXXX\\\”)\”,\”name\”:\”rsp_letsencrypt_test\”,\”action\”:\”rsa_letsencrypt_test\”}}”
    2020-12-30 14:20:12:6166 DEBUG [INVOKE-ADDINITIALADCCONFIG] Responder Policy created, binding Responder Policy “rsp_letsencrypt_test” to Load Balance VIP: “lb_letsencrypt_cert”.
    2020-12-30 14:20:12:6195 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_responderpolicy_binding/lb_letsencrypt_cert”, METHOD: “PUT”
    2020-12-30 14:20:12:6234 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”lbvserver_responderpolicy_binding\”:{\”priority\”:5,\”policyname\”:\”rsp_letsencrypt_test\”,\”name\”:\”lb_letsencrypt_cert\”},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
    2020-12-30 14:20:12:8125 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
    2020-12-30 14:20:12:8201 INFO [INVOKE-ADDINITIALADCCONFIG] Responder Policy bound successfully, check if Content Switch Policy exists.
    2020-12-30 14:20:12:8295 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy/csp_letsencrypt”, METHOD: “GET”
    2020-12-30 14:20:12:8972 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
    2020-12-30 14:20:12:9053 INFO [INVOKE-ADDINITIALADCCONFIG] Create Content Switch Policy.
    2020-12-30 14:20:12:9126 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy?action=add”, METHOD: “POST”
    2020-12-30 14:20:12:9239 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”cspolicy\”:{\”rule\”:\”HTTP.REQ.URL.CONTAINS(\\\”well-known/acme-challenge/\\\”)\”,\”policyname\”:\”csp_letsencrypt\”}}”
    2020-12-30 14:20:13:0283 INFO [INVOKE-ADDINITIALADCCONFIG] Content Switch Policy created successfully, bind Load Balancer “lb_letsencrypt_cert” to Content Switch “cs_letsencrypt” with prio: 11
    2020-12-30 14:20:13:0353 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver_cspolicy_binding”, METHOD: “PUT”
    2020-12-30 14:20:13:0481 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”csvserver_cspolicy_binding\”:{\”priority\”:\”11\”,\”policyname\”:\”csp_letsencrypt\”,\”name\”:\”cs_letsencrypt\”,\”targetlbvserver\”:\”lb_letsencrypt_cert\”,\”gotopriorityexpression\”:\”END\”},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
    2020-12-30 14:20:13:4329 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (409) Conflict.
    2020-12-30 14:20:13:4559 ERROR [INVOKE-ADDINITIALADCCONFIG] Could not configure the ADC. Exception Message: The remote server returned an error: (409) Conflict.
    2020-12-30 14:20:13:8300 INFO [FINAL] Could not configure the ADC!
    2020-12-30 14:20:13:8331 INFO [FINAL] Script Terminated, ExitCode: 1

    • John Billekens Post author

      Hi, sorry to hear it’s not running well.

      Looks like you already have a Content Switch Policy binding with same binding point 11?
      You can try to run the script with the extra parameter -CsVipBinding 8 (use binding point 8 instead of 11) or check if something is already bound to the HTTP content switch “csp_letsencrypt” and change that binding.
      Please let me know if this helps or further help is required.

      • Andrea

        Thank you lots, but unfortunately it still does not work.

        Here is again the log:

        **********************
        LogFile: E:\nscert\GenLeCertForNS\GenLeCertForNS.txt
        Start time: 2020-12-31 18:22:43
        Username: PAMA\andrea.delutti
        RunAs Admin: True
        Machine: DELUTTINBK (Microsoft Windows NT 10.0.19041.0)
        PSCulture: it-IT
        PSVersion: 5.1.19041.1
        PSEdition: Desktop
        PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.19041.1
        BuildVersion: 10.0.19041.1
        PSCommandPath: E:\nscert\GenLeCertForNS\GenLeCertForNS.ps1
        LanguageMode: FullLanguage
        ScriptBase: E:\nscert\GenLeCertForNS
        Script Version: 2.8.1
        PoSH ACME Version: 3.17.0
        PSBoundParameters:

        Key Value
        — —–
        CN citrix.pama.it
        EmailAddress grp.ced@pama.it
        PfxPassword cleared
        CertDir E:\nscert\GenLeCertForNS\certs
        ManagementURL http://172.16.0.15
        CsVipName {cs_letsencrypt}
        Password nsroot
        Username nsroot
        CsVipBinding 8
        CertKeyNameToUpdate citrix.pama.it
        DisableIPCheck True
        Production True
        LogLevel Debug

        **********************

        2020-12-31 18:22:43:1736 INFO [SCRIPTBASICS] Starting a new log
        2020-12-31 18:22:43:2032 INFO [SCRIPTVARIABLES] PfxPassword was specified via parameter.
        2020-12-31 18:22:43:2229 INFO [DOTNETCHECK] Checking if .NET Framework 4.7.1 or higher is installed.
        2020-12-31 18:22:43:2509 INFO [DOTNETCHECK] .NET Framework 4.7.1 or higher is installed.
        2020-12-31 18:22:43:2958 INFO [LOADMODULE] Try loading the Posh-ACME v3.17.0 Modules.
        2020-12-31 18:22:50:0158 INFO [LOADMODULE] v3.17.0 of Posh-ACME is installed, loading module.
        2020-12-31 18:22:50:0548 INFO [LOADMODULE] Posh-ACME loaded successfully.
        2020-12-31 18:22:50:1128 INFO [VERSIONINFO] Current script version: v2.8.1, checking if a new version is available.
        2020-12-31 18:22:50:1336 DEBUG [INVOKE-CHECKSCRIPTVERSIONS] Retrieving data for URI: https://drive.google.com/uc?export=download&id=1WOySj40yNHEza23b7eZ7wzWKymKv64JW
        2020-12-31 18:22:51:3015 DEBUG [INVOKE-CHECKSCRIPTVERSIONS] Successfully retrieved the requested data
        2020-12-31 18:22:51:3828 INFO [VERSIONINFO] No new Master version available
        2020-12-31 18:22:51:4603 INFO [VERSIONINFO] No new Development version available
        2020-12-31 18:22:51:4897 INFO [VERSIONINFO] Version check finished.
        2020-12-31 18:22:51:5236 INFO [ADC-CHECK] Trying to login into the Citrix ADC.
        2020-12-31 18:22:51:5739 INFO [CONNECT-ADC] Connecting to http://172.16.0.15
        2020-12-31 18:22:51:7564 DEBUG [CONNECT-ADC] Response: {“message”:”Done”,”severity”:”NONE”,”errorcode”:0}
        2020-12-31 18:22:51:7911 DEBUG [CONNECT-ADC] Trying to retrieve the ADC version
        2020-12-31 18:22:51:8742 DEBUG [CONNECT-ADC] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsversion”:{“version”:”NetScaler NS12.0: Build 63.13.nc, Date: Jan 16 2020, 05:08:11 “,”mode”:”1″}}
        2020-12-31 18:22:51:9015 INFO [CONNECT-ADC] Connected
        2020-12-31 18:22:51:9190 INFO [CONNECT-ADC] Connected to Citrix ADC http://172.16.0.15, as user nsroot, ADC Version NetScaler NS12.0: Build 63.13.nc
        2020-12-31 18:22:53:4350 INFO [SERVICES] By running this script you agree with the terms specified by Let’s Encrypt.
        2020-12-31 18:22:53:4670 INFO [SERVICES] Terms Of Service: https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
        2020-12-31 18:22:53:5103 INFO [SERVICES] Website: https://letsencrypt.org
        2020-12-31 18:22:53:5482 INFO [SERVICES] LE Certificate Usage: Production Certificates
        2020-12-31 18:22:53:5820 INFO [SERVICES] LE Account Storage: C:\Users\andrea.delutti\AppData\Local\Posh-ACME
        2020-12-31 18:22:53:6073 INFO [CERTLOOP] 1 required for all requests.
        2020-12-31 18:22:53:6329 INFO [CERTLOOP-01] **************************************** 01 ****************************************
        2020-12-31 18:22:53:6630 INFO [CERTLOOP] Round: 1 / 1
        2020-12-31 18:22:53:6793 DEBUG [CERTREQVARIABLES] Setting session DATE/TIME variable.
        2020-12-31 18:22:53:7037 DEBUG [CERTREQVARIABLES] Session DATE/TIME variable value: “20201231-182253”.
        2020-12-31 18:22:53:7359 DEBUG [CERTREQVARIABLES] Session ID value: “20201231-182253_citrix_pama_it”.
        2020-12-31 18:22:53:7845 INFO [ADC-CS-VALIDATION] Verifying Content Switch.
        2020-12-31 18:22:53:8359 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver/cs_letsencrypt”, METHOD: “GET”
        2020-12-31 18:22:54:0045 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”csvserver”:[{“name”:”CS_LetsEncrypt”,”insertvserveripport”:”OFF”,”ip”:”0.0.0.0″,”td”:”0″,”ipv46″:”172.16.0.18″,”ippattern”:”0.0.0.0″,”ipmask”:”*”,”port”:80,”range”:”1″,”servicetype”:”HTTP”,”type”:”CONTENT”,”curstate”:”UP”,”sc”:”OFF”,”stateupdate”:”DISABLED”,”status”:1,”cachetype”:”SERVER”,”precedence”:”RULE”,”authentication”:”OFF”,”authn401″:”OFF”,”casesensitive”:”ON”,”hits”:”0″,”pipolicyhits”:”0″,”weight”:”0″,”priority”:”0″,”clttimeout”:”180″,”listenpolicy”:”NONE”,”somethod”:”NONE”,”sopersistence”:”DISABLED”,”sopersistencetimeout”:”2″,”cacheable”:”NO”,”redirectportrewrite”:”DISABLED”,”downstateflush”:”ENABLED”,”disableprimaryondown”:”DISABLED”,”invoke”:false,”gt2gb”:”DISABLED”,”statechangetimesec”:”Thu Dec 31 17:21:05 2020″,”statechangetimemsec”:”130″,”tickssincelaststatechange”:”10912″,”rtspnat”:”OFF”,”push”:”DISABLED”,”pushlabel”:”none”,”pushmulticlients”:”NO”,”l2conn”:”OFF”,”ruletype”:”0″,”appflowlog”:”ENABLED”,”icmpvsrresponse”:”PASSIVE”,”rhistate”:”PASSIVE”,”ttl”:0,”cookietimeout”:0,”sitedomainttl”:0,”dnsrecordtype”:”A”}]}
        2020-12-31 18:22:54:0843 INFO [ADC-CS-VALIDATION] Content Switch OK
        2020-12-31 18:22:54:2299 INFO [DNSPRECHECK] CN: citrix.pama.it is a valid record
        2020-12-31 18:22:54:3218 DEBUG [DNSPRECHECK] ValidationMethod is set to: “http”.
        2020-12-31 18:22:54:3497 DEBUG [DNSPRECHECK] DNS Data:
        2020-12-31 18:22:54:3892 DEBUG [DNSPRECHECK] {“DNSName”:”citrix.pama.it”,”SAN”:false}
        2020-12-31 18:22:54:4231 INFO [REGISTRATION] Try to retrieve the existing Registration.
        2020-12-31 18:22:54:7505 INFO [REGISTRATION] Existing registration found, no changes necessary.
        2020-12-31 18:22:54:7802 INFO [REGISTRATION] Account 107316800 set as default.
        2020-12-31 18:22:55:2078 DEBUG [REGISTRATION] Registration: {“id”:”107316800″,”status”:”valid”,”contact”:[“mailto:grp.ced@pama.it”],”location”:”https://acme-v02.api.letsencrypt.org/acme/acct/107316800″,”key”:{“d”:”BxN9ZgDaFrqZzwPS3F-3IPbxcr3rr6FF3CBmmTY1VnrJDeBK5GxpOsyXLhU2FkU7Dn5rHBFVRjhb99ywFWHw8xAFJdwBJyJUQzijsdXeyiMarXG0vVtmCUo8g8XNhJgaLB_-Lc_VEfqXmTf6FJUmdbdKVmOjc_9XVZ-SkrbMAm9Wobs8ZRgwROISAqDbJMemtaG40R7qXzTiPczYNHQX34MHL19W203jnoUMU8Vs6ILmsAXo0XjTtp4g5gW0h-HxPu5oYzjMJ9R1dCHHAU312P1mOxDgY0Ixa9YZ_FP3O2d2lk_lc40jvzHt0-fT9M1hbDhyS29RNf3va_b4tkArnQ”,”dp”:”3nbMgw0R7DHan0o3Le6XXINbN4u7TUjBccbxZbzUpI2DIt9mu6S6nJ0bqpnudXF1gfPsz2poEXb8gvq4jUW-NJbpy-DUW5dDx3IFFWNo9_dzS86I54DJtuiwMMoeFKVBuA81n3kB2S0oEICzf_6ueR4VP-3sxM2v97VJ3a604YU”,”dq”:”nmqDXXQ8P0LqMlvS5UaVU8FwMSMJNr1f6QwXf7w_nF_34LKGI8BhJdPAEBUBgGHzQUII8KpzZIp2u1yAJnqYAP9ETAmtUX0lRw2mNurxHMap3BBrd4yZ0dNHHNr_fxbeabA-4wEUSBo2FBaMZCIv1GRF7lepkTmgxjMdJnpYnHE”,”e”:”AQAB”,”kty”:”RSA”,”n”:”uUbtOz6ANntmv9Wk_lH5unV03uZfRsWMKSRh8SZpAcBV-wYc6lkmek4jQJO0q8GKwxdhhRumXAMWa94J02jeP7czOoSnpYiu2R_m42uOrXON6ibiWJYUuv2grbMD0yno6JhsmTZmQgldxNceo1xCKOKm4jwfdtM8i2T3vq7DecCPO5SVdOga72VuK1XXmnH99dv6a5z8FRr7x8xawCCaFV_nwk4bUTbbMAEqoBI6OWhNBkTjvSPqjUKdPMSOovYQFHISoZrwat-gwMZbJQMbLV3HPhTCxiWpnAUQfbtOEdznGjPgTs0rr12PPTIMGjUoBlk1SL1ozqJop37JPsED6Q”,”p”:”5CuZ9O7Et_TPNv64Rz2ZbtXkTbAHJsYmlWhc71F9zEtRnJJaBxTFJs4Cay9qcnhY_MrpEqSABwwlsy-_CE1q09y0jg-YAw8ynItwurMULoH_CRX3QhqnxSnxeINnqABIKxSTVWL4lLaJL24_anVZUUqyTugNeO45BkNUYNxUU8s”,”q”:”z-AGRhO7ibwPhvs6r2PSX1UbhzaMyE6E-WCnXWPDmfmf97AnztOIn1_HbnR3Bt2dWy7sC0DE58Enmb9vBLBRVUng-bc4r7kYLIwk7cIfSTxFj15PrKKi8xF5LFaV-CjUP-FfHAHCdMbzkQVKzv2Z2NHB2TIw17UiKDSrNTkd2Js”,”qi”:”xRmNRxCvdVY0MQcrf9rEuuZUpVNzLFsYcQ4vMaOSGo0p8pxzB4VyXHi-rdsk8Rfebit0dWIRLZgKKPNtSKe-XLRMS9EOtfKmt6TRIOQfF_DBy5CW3H8V35gzu-gMbRxf_Gxpo6GR96DS4iFAfjCIlTDBgabGw9hn5_0ZeZHtvUA”},”alg”:”RS256″,”KeyLength”:”2048″,”orders”:null}.
        2020-12-31 18:22:55:2174 INFO [REGISTRATION] Registration ID: 107316800, Status: valid.
        2020-12-31 18:22:55:2476 INFO [REGISTRATION] Setting Account as default for new order.
        2020-12-31 18:22:55:2835 INFO [ORDER] Trying to create a new order.
        2020-12-31 18:22:57:2831 DEBUG [ORDER] Order data:
        2020-12-31 18:22:57:3205 DEBUG [ORDER] {“MainDomain”:”citrix.pama.it”,”FriendlyName”:”citrix.pama.it”,”SANs”:[],”status”:”pending”,”expires”:”2021-01-07T17:22:56.370481994Z”,”KeyLength”:”2048″}
        2020-12-31 18:22:58:0184 DEBUG [ORDER] Challenge status:
        2020-12-31 18:22:58:0450 DEBUG [ORDER] {“DNSId”:”citrix.pama.it”,”status”:”pending”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}
        2020-12-31 18:22:58:0633 INFO [ORDER] Order created successfully.
        2020-12-31 18:22:58:0979 INFO [DNS-VALIDATION] Validate DNS record(s).
        2020-12-31 18:22:58:1288 INFO [DNS-VALIDATION] “NoIPCheck/(citrix.pama.it)” is the first entry, continuing.
        2020-12-31 18:22:58:1563 DEBUG [DNS-VALIDATION] SAN Objects:
        2020-12-31 18:22:58:1795 DEBUG [DNS-VALIDATION] {“DNSName”:”citrix.pama.it”,”IPAddress”:”NoIPCheck”,”Status”:true,”Match”:true}
        2020-12-31 18:22:58:2096 INFO [DNS-VALIDATION] Checking for invalid DNS Records.
        2020-12-31 18:22:58:2342 INFO [DNS-VALIDATION] None found, continuing
        2020-12-31 18:22:58:2556 INFO [DNS-VALIDATION] Checking non-matching DNS Records
        2020-12-31 18:22:58:2744 INFO [DNS-VALIDATION] IP Addresses checking was skipped.
        2020-12-31 18:22:58:3000 INFO [CHECKORDERVALIDATION] Checking if validation is required.
        2020-12-31 18:22:58:8910 DEBUG [CHECKORDERVALIDATION] validations required:
        2020-12-31 18:22:58:9089 DEBUG [CHECKORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”HTTP01Status”:”pending”,”expires”:”2021-01-07T17:22:56Z”}
        2020-12-31 18:22:58:9250 INFO [CHECKORDERVALIDATION] Validation IS required.
        2020-12-31 18:22:58:9386 DEBUG [CHECKORDERVALIDATION] ADC actions required: True.
        2020-12-31 18:22:58:9479 INFO [INVOKE-ADDINITIALADCCONFIG] Trying to login into the Citrix ADC.
        2020-12-31 18:22:58:9678 INFO [CONNECT-ADC] Connecting to http://172.16.0.15
        2020-12-31 18:22:59:0818 DEBUG [CONNECT-ADC] Response: {“message”:”Done”,”severity”:”NONE”,”errorcode”:0}
        2020-12-31 18:22:59:0981 DEBUG [CONNECT-ADC] Trying to retrieve the ADC version
        2020-12-31 18:22:59:1651 DEBUG [CONNECT-ADC] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsversion”:{“version”:”NetScaler NS12.0: Build 63.13.nc, Date: Jan 16 2020, 05:08:11 “,”mode”:”1″}}
        2020-12-31 18:22:59:1834 INFO [CONNECT-ADC] Connected
        2020-12-31 18:22:59:2005 INFO [CONNECT-ADC] Connected to Citrix ADC http://172.16.0.15, as user nsroot, ADC Version NetScaler NS12.0: Build 63.13.nc
        2020-12-31 18:22:59:2254 INFO [INVOKE-ADDINITIALADCCONFIG] Enabling required ADC Features: Load Balancer, Responder, Content Switch and SSL.
        2020-12-31 18:22:59:2581 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/nsfeature”, METHOD: “GET”
        2020-12-31 18:22:59:3469 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsfeature”:{“feature”:[“WL”,”LB”,”CS”,”SSL”,”SSLVPN”,”RESPONDER”,”CH”],”wl”:true,”sp”:false,”lb”:true,”cs”:true,”cr”:false,”sc”:false,”cmp”:false,”pq”:false,”ssl”:true,”gslb”:false,”hdosp”:false,”cf”:false,”ic”:false,”sslvpn”:true,”aaa”:false,”ospf”:false,”rip”:false,”bgp”:false,”rewrite”:false,”ipv6pt”:false,”appfw”:false,”responder”:true,”htmlinjection”:false,”push”:false,”appflow”:false,”cloudbridge”:false,”isis”:false,”ch”:true,”appqoe”:false,”contentaccelerator”:false,”rise”:false,”feo”:false,”lsn”:false,”rdpproxy”:false,”rep”:false,”urlfiltering”:false,”videooptimization”:false,”forwardproxy”:false,”sslinterception”:false,”adaptivetcp”:false,”cqa”:false,”ci”:false}}
        2020-12-31 18:22:59:3882 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “LB” already enabled.
        2020-12-31 18:22:59:4442 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “RESPONDER” already enabled.
        2020-12-31 18:22:59:4823 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “CS” already enabled.
        2020-12-31 18:22:59:5118 DEBUG [INVOKE-ADDINITIALADCCONFIG] Feature “SSL” already enabled.
        2020-12-31 18:22:59:5646 INFO [INVOKE-ADDINITIALADCCONFIG] Features enabled, verifying Content Switch.
        2020-12-31 18:22:59:6116 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver/cs_letsencrypt”, METHOD: “GET”
        2020-12-31 18:22:59:7276 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”csvserver”:[{“name”:”CS_LetsEncrypt”,”insertvserveripport”:”OFF”,”ip”:”0.0.0.0″,”td”:”0″,”ipv46″:”172.16.0.18″,”ippattern”:”0.0.0.0″,”ipmask”:”*”,”port”:80,”range”:”1″,”servicetype”:”HTTP”,”type”:”CONTENT”,”curstate”:”UP”,”sc”:”OFF”,”stateupdate”:”DISABLED”,”status”:1,”cachetype”:”SERVER”,”precedence”:”RULE”,”authentication”:”OFF”,”authn401″:”OFF”,”casesensitive”:”ON”,”hits”:”0″,”pipolicyhits”:”0″,”weight”:”0″,”priority”:”0″,”clttimeout”:”180″,”listenpolicy”:”NONE”,”somethod”:”NONE”,”sopersistence”:”DISABLED”,”sopersistencetimeout”:”2″,”cacheable”:”NO”,”redirectportrewrite”:”DISABLED”,”downstateflush”:”ENABLED”,”disableprimaryondown”:”DISABLED”,”invoke”:false,”gt2gb”:”DISABLED”,”statechangetimesec”:”Thu Dec 31 17:21:05 2020″,”statechangetimemsec”:”182″,”tickssincelaststatechange”:”11476″,”rtspnat”:”OFF”,”push”:”DISABLED”,”pushlabel”:”none”,”pushmulticlients”:”NO”,”l2conn”:”OFF”,”ruletype”:”0″,”appflowlog”:”ENABLED”,”icmpvsrresponse”:”PASSIVE”,”rhistate”:”PASSIVE”,”ttl”:0,”cookietimeout”:0,”sitedomainttl”:0,”dnsrecordtype”:”A”}]}
        2020-12-31 18:22:59:7836 INFO [INVOKE-ADDINITIALADCCONFIG] Content Switch is OK, check if Load Balancer Service exists.
        2020-12-31 18:22:59:8295 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service/svc_letsencrypt_cert_dummy”, METHOD: “GET”
        2020-12-31 18:22:59:9448 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:22:59:9811 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balancer Service does not exist, create Load Balance Service “svc_letsencrypt_cert_dummy”.
        2020-12-31 18:23:00:0283 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service?action=add”, METHOD: “POST”
        2020-12-31 18:23:00:0657 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”service\”:{\”port\”:\”80\”,\”ip\”:\”1.2.3.4\”,\”name\”:\”svc_letsencrypt_cert_dummy\”,\”servicetype\”:\”HTTP\”,\”healthmonitor\”:\”NO\”}}”
        2020-12-31 18:23:00:2153 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balance Service created.
        2020-12-31 18:23:00:2632 INFO [INVOKE-ADDINITIALADCCONFIG] Check if Load Balance VIP exists.
        2020-12-31 18:23:00:3029 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver/lb_letsencrypt_cert”, METHOD: “GET”
        2020-12-31 18:23:00:4136 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:23:00:4637 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balance VIP does not exist, create Load Balance VIP “lb_letsencrypt_cert”.
        2020-12-31 18:23:00:5050 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver?action=add”, METHOD: “POST”
        2020-12-31 18:23:00:5479 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”lbvserver\”:{\”Port\”:\”0\”,\”ipv46\”:\”0.0.0.0\”,\”name\”:\”lb_letsencrypt_cert\”,\”servicetype\”:\”HTTP\”},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:23:00:6869 INFO [INVOKE-ADDINITIALADCCONFIG] Load Balance VIP Created.
        2020-12-31 18:23:00:7372 INFO [INVOKE-ADDINITIALADCCONFIG] Checking if LB Service “svc_letsencrypt_cert_dummy” is bound to Load Balance VIP “lb_letsencrypt_cert”.
        2020-12-31 18:23:00:8028 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_service_binding/lb_letsencrypt_cert”, METHOD: “GET”
        2020-12-31 18:23:01:0667 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:01:1075 INFO [INVOKE-ADDINITIALADCCONFIG] LB Service binding must be configured
        2020-12-31 18:23:01:1501 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_service_binding”, METHOD: “PUT”
        2020-12-31 18:23:01:1853 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”lbvserver_service_binding\”:{\”name\”:\”lb_letsencrypt_cert\”,\”servicename\”:\”svc_letsencrypt_cert_dummy\”}}”
        2020-12-31 18:23:01:4028 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:01:4282 INFO [INVOKE-ADDINITIALADCCONFIG] LB Service binding is OK
        2020-12-31 18:23:01:4541 INFO [INVOKE-ADDINITIALADCCONFIG] Checking if Responder Policies exists starting with “rsp_letsencrypt”
        2020-12-31 18:23:01:4996 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?filter=name:%2Frsp_letsencrypt%2F”, METHOD: “GET”
        2020-12-31 18:23:01:5784 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:01:6093 INFO [INVOKE-ADDINITIALADCCONFIG] No Responder Policies found.
        2020-12-31 18:23:01:6395 INFO [INVOKE-ADDINITIALADCCONFIG] Checking if Responder Actions exists starting with “rsa_letsencrypt”.
        2020-12-31 18:23:01:6920 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?filter=name:%2Frsa_letsencrypt%2F”, METHOD: “GET”
        2020-12-31 18:23:01:7949 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:01:8363 INFO [INVOKE-ADDINITIALADCCONFIG] No Responder Actions found.
        2020-12-31 18:23:01:8643 DEBUG [INVOKE-ADDINITIALADCCONFIG] Creating a test Responder Action.
        2020-12-31 18:23:01:8894 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?action=add”, METHOD: “POST”
        2020-12-31 18:23:01:9298 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderaction\”:{\”name\”:\”rsa_letsencrypt_test\”,\”target\”:\”\\\”HTTP/1.0 200 OK\\\” +\\\”\\\\r\\\\n\\\\r\\\\n\\\” + \\\”XXXX\\\”\”,\”type\”:\”respondwith\”}}”
        2020-12-31 18:23:02:1053 DEBUG [INVOKE-ADDINITIALADCCONFIG] Responder Action created, creating a test Responder Policy.
        2020-12-31 18:23:02:1352 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?action=add”, METHOD: “POST”
        2020-12-31 18:23:02:1819 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderpolicy\”:{\”rule\”:\”HTTP.REQ.URL.CONTAINS(\\\”.well-known/acme-challenge/XXXX\\\”)\”,\”name\”:\”rsp_letsencrypt_test\”,\”action\”:\”rsa_letsencrypt_test\”}}”
        2020-12-31 18:23:02:2922 DEBUG [INVOKE-ADDINITIALADCCONFIG] Responder Policy created, binding Responder Policy “rsp_letsencrypt_test” to Load Balance VIP: “lb_letsencrypt_cert”.
        2020-12-31 18:23:02:3018 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_responderpolicy_binding/lb_letsencrypt_cert”, METHOD: “PUT”
        2020-12-31 18:23:02:3359 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”lbvserver_responderpolicy_binding\”:{\”priority\”:5,\”policyname\”:\”rsp_letsencrypt_test\”,\”name\”:\”lb_letsencrypt_cert\”},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:23:02:5353 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:02:5664 INFO [INVOKE-ADDINITIALADCCONFIG] Responder Policy bound successfully, check if Content Switch Policy exists.
        2020-12-31 18:23:02:6022 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy/csp_letsencrypt”, METHOD: “GET”
        2020-12-31 18:23:02:6872 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:23:02:7168 INFO [INVOKE-ADDINITIALADCCONFIG] Create Content Switch Policy.
        2020-12-31 18:23:02:7424 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy?action=add”, METHOD: “POST”
        2020-12-31 18:23:02:7712 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”cspolicy\”:{\”rule\”:\”HTTP.REQ.URL.CONTAINS(\\\”well-known/acme-challenge/\\\”)\”,\”policyname\”:\”csp_letsencrypt\”}}”
        2020-12-31 18:23:02:8872 INFO [INVOKE-ADDINITIALADCCONFIG] Content Switch Policy created successfully, bind Load Balancer “lb_letsencrypt_cert” to Content Switch “cs_letsencrypt” with prio: 8
        2020-12-31 18:23:02:9311 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver_cspolicy_binding”, METHOD: “PUT”
        2020-12-31 18:23:02:9629 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”csvserver_cspolicy_binding\”:{\”priority\”:\”8\”,\”policyname\”:\”csp_letsencrypt\”,\”name\”:\”cs_letsencrypt\”,\”targetlbvserver\”:\”lb_letsencrypt_cert\”,\”gotopriorityexpression\”:\”END\”},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:23:03:1729 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:03:1982 INFO [INVOKE-ADDINITIALADCCONFIG] Binding created successfully! Finished configuring the ADC
        2020-12-31 18:23:05:2724 INFO [INVOKE-CHECKDNS] DNS Validation & Verifying ADC config.
        2020-12-31 18:23:05:3152 INFO [INVOKE-CHECKDNS] Testing if the Citrix ADC (Content Switch) is configured successfully by accessing URL: “http://citrix.pama.it/.well-known/acme-challenge/XXXX” (via internal DNS).
        2020-12-31 18:23:05:3460 DEBUG [INVOKE-CHECKDNS] Retrieving data
        2020-12-31 18:23:06:0268 INFO [INVOKE-CHECKDNS] Retrieved successfully.
        2020-12-31 18:23:06:0530 DEBUG [INVOKE-CHECKDNS] output: {“StatusCode”:200,”StatusDescription”:”OK”,”RawContent”:”HTTP/1.0 200 OK\r\n\r\nXXXX”}
        2020-12-31 18:23:06:0855 INFO [INVOKE-CHECKDNS] Test (Int. DNS): OK
        2020-12-31 18:23:06:1097 INFO [INVOKE-CHECKDNS] Checking if Public IP is available for external DNS testing.
        2020-12-31 18:23:06:2296 INFO [INVOKE-CHECKDNS] Public IP is not available for external DNS testing
        2020-12-31 18:23:06:6615 INFO [INVOKE-CHECKDNS] Finished the tests, script will continue.
        2020-12-31 18:23:06:8036 INFO [ORDERVALIDATION] Configuring the ADC Responder Policies/Actions required for the validation.
        2020-12-31 18:23:06:9843 DEBUG [ORDERVALIDATION] PAOrderItems:
        2020-12-31 18:23:07:1151 DEBUG [ORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”expires”:”2021-01-07T17:22:56Z”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}
        2020-12-31 18:23:07:1676 INFO [ORDERVALIDATION] New validation required for “citrix.pama.it”, Start configuring the ADC.
        2020-12-31 18:23:07:4095 INFO [ORDERVALIDATION] Add Responder Action “rsa_letsencrypt_10” to return “HTTP/1.0 200 OK\r\n\r\nPobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4.rJ3IdgLH44D7UR9aa3zyphyMBUB3ezc0yezmv5_lbR8”.
        2020-12-31 18:23:07:4451 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?action=add”, METHOD: “POST”
        2020-12-31 18:23:07:4725 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderaction\”:{\”name\”:\”rsa_letsencrypt_10\”,\”target\”:\”\\\”HTTP/1.0 200 OK\\\\r\\\\n\\\\r\\\\nPobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4.rJ3IdgLH44D7UR9aa3zyphyMBUB3ezc0yezmv5_lbR8\\\”\”,\”type\”:\”respondwith\”}}”
        2020-12-31 18:23:07:5789 INFO [ORDERVALIDATION] Responder Action added successfully.
        2020-12-31 18:23:07:7407 INFO [ORDERVALIDATION] Add Responder Policy “rsp_letsencrypt_10” to: “HTTP.REQ.URL.CONTAINS(“.well-known/acme-challenge/Pobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4″)”
        2020-12-31 18:23:07:7703 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?action=add”, METHOD: “POST”
        2020-12-31 18:23:07:7934 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderpolicy\”:{\”rule\”:\”HTTP.REQ.URL.CONTAINS(\\\”.well-known/acme-challenge/Pobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4\\\”)\”,\”name\”:\”rsp_letsencrypt_10\”,\”action\”:\”rsa_letsencrypt_10\”}}”
        2020-12-31 18:23:07:9128 INFO [ORDERVALIDATION] Responder Policy added successfully.
        2020-12-31 18:23:08:3716 INFO [ORDERVALIDATION] Trying to bind the Responder Policy “rsp_letsencrypt_10” to LoadBalance VIP: “lb_letsencrypt_cert”
        2020-12-31 18:23:08:5573 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver_responderpolicy_binding/lb_letsencrypt_cert”, METHOD: “PUT”
        2020-12-31 18:23:08:5946 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”lbvserver_responderpolicy_binding\”:{\”priority\”:\”10\”,\”policyname\”:\”rsp_letsencrypt_10\”,\”name\”:\”lb_letsencrypt_cert\”},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:23:08:9064 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:23:08:9421 INFO [ORDERVALIDATION] Responder Policy successfully bound to Load Balance VIP.
        2020-12-31 18:23:08:9743 INFO [ORDERVALIDATION] Sending acknowledgment to Let’s Encrypt.
        2020-12-31 18:23:09:3679 INFO [ORDERVALIDATION] Successfully send.
        2020-12-31 18:23:09:4123 INFO [ORDERVALIDATION] Retrieving validation status.
        2020-12-31 18:23:10:5447 DEBUG [ORDERVALIDATION] Listing PAOrderItems
        2020-12-31 18:23:10:5877 DEBUG [ORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”expires”:”2021-01-07T17:22:56Z”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}
        2020-12-31 18:23:10:6526 DEBUG [ORDERVALIDATION] Items still pending: False
        2020-12-31 18:23:16:3080 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:22:0700 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:27:7480 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:33:4245 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:39:0653 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:44:8357 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:50:4772 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:23:56:1262 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:24:01:8569 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:24:07:6873 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:24:13:4575 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
        2020-12-31 18:24:13:4827 DEBUG [ORDERVALIDATION] Loop ended, max reties reached!
        2020-12-31 18:24:14:2398 ERROR [ORDERVALIDATION] Unfortunately there are invalid items. Failed Records:
        2020-12-31 18:24:14:2772 DEBUG [ORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”expires”:”2021-01-07T17:22:56Z”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}
        2020-12-31 18:24:14:3489 ERROR [INVOKE-REGISTERERROR] [1]
        2020-12-31 18:24:14:3789 ERROR [INVOKE-REGISTERERROR] Registering error only, continuing to cleanup.
        2020-12-31 18:24:14:4090 INFO [INVOKE-ADCCLEANUP] Cleaning the Citrix ADC Configuration.
        2020-12-31 18:24:14:4515 INFO [INVOKE-ADCCLEANUP] Trying to login into the Citrix ADC.
        2020-12-31 18:24:14:5165 INFO [CONNECT-ADC] Connecting to http://172.16.0.15
        2020-12-31 18:24:14:7729 DEBUG [CONNECT-ADC] Response: {“message”:”Done”,”severity”:”NONE”,”errorcode”:0}
        2020-12-31 18:24:14:7964 DEBUG [CONNECT-ADC] Trying to retrieve the ADC version
        2020-12-31 18:24:14:9581 DEBUG [CONNECT-ADC] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsversion”:{“version”:”NetScaler NS12.0: Build 63.13.nc, Date: Jan 16 2020, 05:08:11 “,”mode”:”1″}}
        2020-12-31 18:24:15:0261 INFO [CONNECT-ADC] Connected
        2020-12-31 18:24:15:1071 INFO [CONNECT-ADC] Connected to Citrix ADC http://172.16.0.15, as user nsroot, ADC Version NetScaler NS12.0: Build 63.13.nc
        2020-12-31 18:24:15:2542 INFO [INVOKE-ADCCLEANUP] Checking if a binding exists for “csp_letsencrypt”.
        2020-12-31 18:24:15:3662 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver_cspolicy_binding/cs_letsencrypt?filter=policyname:csp_letsencrypt”, METHOD: “GET”
        2020-12-31 18:24:15:6111 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”csvserver_cspolicy_binding”:[{“name”:”CS_LetsEncrypt”,”policyname”:”csp_letsencrypt”,”stateflag”:”536937473″,”targetlbvserver”:”lb_letsencrypt_cert”,”priority”:”8″,”gotopriorityexpression”:””,”bindpoint”:””,”invoke”:false,”labeltype”:””,”labelname”:””,”hits”:”1″,”pipolicyhits”:”1″,”rule”:””}]}
        2020-12-31 18:24:15:6646 INFO [INVOKE-ADCCLEANUP] Binding exists, removing Content Switch LoadBalance Binding.
        2020-12-31 18:24:15:7144 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver_cspolicy_binding?args=priority:8,policyname:csp_letsencrypt,name:cs_letsencrypt”, METHOD: “DELETE”
        2020-12-31 18:24:15:8130 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”csvserver_cspolicy_binding\”:{},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:24:16:7462 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:16:9295 INFO [INVOKE-ADCCLEANUP] Checking if Content Switch Policy “csp_letsencrypt” exists.
        2020-12-31 18:24:16:9687 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy/csp_letsencrypt”, METHOD: “GET”
        2020-12-31 18:24:17:2653 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”cspolicy”:[{“policyname”:”csp_letsencrypt”,”rule”:”HTTP.REQ.URL.CONTAINS(\”well-known/acme-challenge/\”)”,”vstype”:”2″,”hits”:”1″,”pihits”:”1″,”bindhits”:”1″,”pipolicyhits”:”1″,”priority”:”0″,”activepolicy”:false,”cspolicytype”:”Advanced Policy”}]}
        2020-12-31 18:24:17:3656 INFO [INVOKE-ADCCLEANUP] Content Switch Policy exist, removing Content Switch Policy.
        2020-12-31 18:24:17:3920 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy/csp_letsencrypt”, METHOD: “DELETE”
        2020-12-31 18:24:17:4268 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”cspolicy\”:{}}”
        2020-12-31 18:24:17:7524 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:17:7777 INFO [INVOKE-ADCCLEANUP] Removed Content Switch Policy successfully.
        2020-12-31 18:24:17:8181 INFO [INVOKE-ADCCLEANUP] Checking if Load Balance VIP “lb_letsencrypt_cert” exists.
        2020-12-31 18:24:17:8556 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver/lb_letsencrypt_cert”, METHOD: “GET”
        2020-12-31 18:24:17:9475 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”lbvserver”:[{“name”:”lb_letsencrypt_cert”,”insertvserveripport”:”OFF”,”ipv46″:”0.0.0.0″,”ippattern”:”0.0.0.0″,”ipmask”:”*”,”listenpolicy”:”NONE”,”ipmapping”:”0.0.0.0″,”port”:0,”range”:”1″,”servicetype”:”HTTP”,”type”:”ADDRESS”,”curstate”:”UP”,”effectivestate”:”UP”,”status”:2,”lbrrreason”:4,”cachetype”:”SERVER”,”authentication”:”OFF”,”authn401″:”OFF”,”dynamicweight”:”0″,”priority”:”0″,”clttimeout”:”180″,”somethod”:”NONE”,”sopersistence”:”DISABLED”,”sopersistencetimeout”:”2″,”healththreshold”:”0″,”lbmethod”:”LEASTCONNECTION”,”backuplbmethod”:”ROUNDROBIN”,”dataoffset”:”0″,”health”:”100″,”datalength”:”0″,”ruletype”:”0″,”m”:”IP”,”persistencetype”:”NONE”,”timeout”:2,”persistmask”:”255.255.255.255″,”v6persistmasklen”:”128″,”persistencebackup”:”NONE”,”cacheable”:”NO”,”rtspnat”:”OFF”,”sessionless”:”DISABLED”,”trofspersistence”:”ENABLED”,”map”:”OFF”,”connfailover”:”DISABLED”,”redirectportrewrite”:”DISABLED”,”downstateflush”:”ENABLED”,”disableprimaryondown”:”DISABLED”,”gt2gb”:”DISABLED”,”consolidatedlconn”:”GLOBAL”,”consolidatedlconngbl”:”YES”,”thresholdvalue”:0,”invoke”:false,”version”:0,”totalservices”:”1″,”activeservices”:”1″,”statechangetimesec”:”Thu Dec 31 17:23:02 2020″,”statechangetimeseconds”:”1609435382″,”statechangetimemsec”:”569″,”tickssincelaststatechange”:”7538″,”hits”:”0″,”pipolicyhits”:”0″,”push”:”DISABLED”,”pushlabel”:”none”,”pushmulticlients”:”NO”,”policysubtype”:”0″,”l2conn”:”OFF”,”appflowlog”:”ENABLED”,”isgslb”:false,”icmpvsrresponse”:”PASSIVE”,”rhistate”:”PASSIVE”,”newservicerequestunit”:”PER_SECOND”,”vsvrbindsvcip”:”0.0.0.0″,”vsvrbindsvcport”:0,”skippersistency”:”None”,”td”:”0″,”minautoscalemembers”:”0″,”maxautoscalemembers”:”0″,”macmoderetainvlan”:”DISABLED”,”dns64″:”DISABLED”,”bypassaaaa”:”NO”,”processlocal”:”DISABLED”,”vsvrdynconnsothreshold”:”0″,”retainconnectionsoncluster”:”NO”}]}
        2020-12-31 18:24:17:9792 INFO [INVOKE-ADCCLEANUP] Load Balance VIP exist, removing the Load Balance VIP.
        2020-12-31 18:24:18:0070 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver/lb_letsencrypt_cert”, METHOD: “DELETE”
        2020-12-31 18:24:18:0316 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”lbvserver\”:{},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:24:18:2095 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:18:2452 INFO [INVOKE-ADCCLEANUP] Checking if Load Balance Service “svc_letsencrypt_cert_dummy” exists.
        2020-12-31 18:24:18:2850 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service/svc_letsencrypt_cert_dummy”, METHOD: “GET”
        2020-12-31 18:24:18:4495 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”service”:[{“name”:”svc_letsencrypt_cert_dummy”,”numofconnections”:0,”servername”:”1.2.3.4″,”policyname”:”1.2.3.4″,”servicetype”:”HTTP”,”serviceconftype2″:”Configured”,”port”:80,”gslb”:”NONE”,”cachetype”:”SERVER”,”maxclient”:”0″,”maxreq”:”0″,”cacheable”:”NO”,”cip”:”DISABLED”,”usip”:”NO”,”pathmonitor”:”NO”,”pathmonitorindv”:”NO”,”useproxyport”:”YES”,”dup_weight”:”0″,”sp”:”OFF”,”rtspsessionidremap”:”OFF”,”failedprobes”:”0″,”clttimeout”:180,”totalprobes”:”180″,”svrtimeout”:360,”totalfailedprobes”:”360″,”publicip”:”0.0.0.0″,”publicport”:80,”customserverid”:”None”,”cka”:”NO”,”tcpb”:”NO”,”processlocal”:”DISABLED”,”cmp”:”NO”,”maxbandwidth”:”0″,”accessdown”:”NO”,”svrstate”:”UP”,”delay”:0,”ipaddress”:”1.2.3.4″,”monthreshold”:”0″,”monitor_state”:”Unknown”,”monstatcode”:0,”lastresponse”:”Probing ownership is with some other node in cluster.”,”responsetime”:”0″,”riseapbrstatsmsgcode”:0,”riseapbrstatsmsgcode2″:1,”monstatparam1″:0,”monstatparam2″:0,”monstatparam3″:0,”downstateflush”:”ENABLED”,”statechangetimesec”:”Thu Dec 31 17:23:01 2020″,”statechangetimemsec”:”372″,”tickssincelaststatechange”:”7707″,”stateupdatereason”:”0″,”clmonview”:”0″,”graceful”:”NO”,”monitortotalprobes”:”0″,”monitortotalfailedprobes”:”0″,”monitorcurrentfailedprobes”:”0″,”healthmonitor”:”NO”,”appflowlog”:”ENABLED”,”serviceipstr”:”1.2.3.4″,”td”:”0″,”passive”:false,”monconnectionclose”:”NONE”}]}
        2020-12-31 18:24:18:4969 INFO [INVOKE-ADCCLEANUP] Load Balance Service exist, removing Service “svc_letsencrypt_cert_dummy”.
        2020-12-31 18:24:18:5354 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service/svc_letsencrypt_cert_dummy”, METHOD: “DELETE”
        2020-12-31 18:24:18:5789 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”service\”:{}}”
        2020-12-31 18:24:18:7690 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:18:8091 INFO [INVOKE-ADCCLEANUP] Checking if Load Balance Server “1.2.3.4” exists.
        2020-12-31 18:24:18:8563 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/server/1.2.3.4”, METHOD: “GET”
        2020-12-31 18:24:18:9430 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”server”:[{“name”:”1.2.3.4″,”ipaddress”:”1.2.3.4″,”state”:”ENABLED”,”translationip”:”0.0.0.0″,”translationmask”:”0.0.0.0″,”svctype”:”HTTP”,”port”:0,”svrstate”:”Unknown”,”statechangetimesec”:”Thu Jan 1 00:00:00 1970″,”tickssincelaststatechange”:”0″,”ipv6address”:”NO”,”dup_port”:0,”dup_svctype”:”HTTP”,”svrcfgflags”:”0″,”td”:”0″,”maxreq”:”0″,”maxbandwidth”:”0″,”usip”:”NO”,”cka”:”NO”,”tcpb”:”NO”,”cmp”:”NO”,”clttimeout”:0,”svrtimeout”:0,”cip”:”DISABLED”,”cacheable”:”NO”,”sp”:”OFF”,”downstateflush”:”DISABLED”,”appflowlog”:”DISABLED”,”boundtd”:”0″}]}
        2020-12-31 18:24:19:0065 INFO [INVOKE-ADCCLEANUP] Load Balance Server exist, removing Load Balance Server “1.2.3.4”.
        2020-12-31 18:24:19:0343 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/server/1.2.3.4”, METHOD: “DELETE”
        2020-12-31 18:24:19:0576 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”server\”:{},\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”}}”
        2020-12-31 18:24:19:2381 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:19:2604 INFO [INVOKE-ADCCLEANUP] Checking if there are Responder Policies starting with the name “rsp_letsencrypt”.
        2020-12-31 18:24:19:2891 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?filter=name:%2Frsp_letsencrypt%2F”, METHOD: “GET”
        2020-12-31 18:24:19:3977 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”responderpolicy”:[{“name”:”rsp_letsencrypt_test”,”rule”:”HTTP.REQ.URL.CONTAINS(\”.well-known/acme-challenge/XXXX\”)”,”action”:”rsa_letsencrypt_test”,”hits”:”1″,”undefhits”:”0″,”activepolicy”:0,”priority”:”0″},{“name”:”rsp_letsencrypt_10″,”rule”:”HTTP.REQ.URL.CONTAINS(\”.well-known/acme-challenge/Pobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4\”)”,”action”:”rsa_letsencrypt_10″,”hits”:”0″,”undefhits”:”0″,”activepolicy”:0,”priority”:”0″}]}
        2020-12-31 18:24:19:5051 DEBUG [INVOKE-ADCCLEANUP] Responder Policies found:
        2020-12-31 18:24:19:5462 DEBUG [INVOKE-ADCCLEANUP] {“name”:”rsp_letsencrypt_test”,”action”:”rsa_letsencrypt_test”,”rule”:”HTTP.REQ.URL.CONTAINS(\”.well-known/acme-challenge/XXXX\”)”}
        2020-12-31 18:24:19:5791 DEBUG [INVOKE-ADCCLEANUP] {“name”:”rsp_letsencrypt_10″,”action”:”rsa_letsencrypt_10″,”rule”:”HTTP.REQ.URL.CONTAINS(\”.well-known/acme-challenge/Pobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4\”)”}
        2020-12-31 18:24:19:6158 INFO [INVOKE-ADCCLEANUP] Checking if policy “rsp_letsencrypt_test” is bound to Load Balance VIP.
        2020-12-31 18:24:19:6435 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy_binding/rsp_letsencrypt_test”, METHOD: “GET”
        2020-12-31 18:24:19:7236 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”responderpolicy_binding”:[{“name”:”rsp_letsencrypt_test”}]}
        2020-12-31 18:24:19:7594 INFO [INVOKE-ADCCLEANUP] Responder Policy not bound.
        2020-12-31 18:24:19:8582 INFO [INVOKE-ADCCLEANUP] Trying to remove the Responder Policy “rsp_letsencrypt_test”.
        2020-12-31 18:24:19:9211 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy/rsp_letsencrypt_test”, METHOD: “DELETE”
        2020-12-31 18:24:19:9755 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderpolicy\”:{}}”
        2020-12-31 18:24:20:1753 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:20:2038 INFO [INVOKE-ADCCLEANUP] Responder Policy removed successfully.
        2020-12-31 18:24:20:2443 INFO [INVOKE-ADCCLEANUP] Checking if policy “rsp_letsencrypt_10” is bound to Load Balance VIP.
        2020-12-31 18:24:20:2743 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy_binding/rsp_letsencrypt_10”, METHOD: “GET”
        2020-12-31 18:24:20:3517 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”responderpolicy_binding”:[{“name”:”rsp_letsencrypt_10″}]}
        2020-12-31 18:24:20:3787 INFO [INVOKE-ADCCLEANUP] Responder Policy not bound.
        2020-12-31 18:24:20:4842 INFO [INVOKE-ADCCLEANUP] Trying to remove the Responder Policy “rsp_letsencrypt_10”.
        2020-12-31 18:24:20:5519 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy/rsp_letsencrypt_10”, METHOD: “DELETE”
        2020-12-31 18:24:20:5824 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderpolicy\”:{}}”
        2020-12-31 18:24:20:7841 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:20:8041 INFO [INVOKE-ADCCLEANUP] Responder Policy removed successfully.
        2020-12-31 18:24:20:8251 INFO [INVOKE-ADCCLEANUP] Checking if there are Responder Actions starting with the name “rsa_letsencrypt”.
        2020-12-31 18:24:20:8539 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?filter=name:%2Frsa_letsencrypt%2F”, METHOD: “GET”
        2020-12-31 18:24:20:9286 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”responderaction”:[{“name”:”rsa_letsencrypt_test”,”type”:”respondwith”,”target”:”\”HTTP/1.0 200 OK\” +\”\\r\\n\\r\\n\” + \”XXXX\””,”hits”:”1″,”referencecount”:”0″,”undefhits”:”0″},{“name”:”rsa_letsencrypt_10″,”type”:”respondwith”,”target”:”\”HTTP/1.0 200 OK\\r\\n\\r\\nPobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4.rJ3IdgLH44D7UR9aa3zyphyMBUB3ezc0yezmv5_lbR8\””,”hits”:”0″,”referencecount”:”0″,”undefhits”:”0″}]}
        2020-12-31 18:24:20:9915 DEBUG [INVOKE-ADCCLEANUP] Responder Actions found:
        2020-12-31 18:24:21:0941 DEBUG [INVOKE-ADCCLEANUP] {“name”:”rsa_letsencrypt_test”,”target”:”\”HTTP/1.0 200 OK\” +\”\\r\\n\\r\\n\” + \”XXXX\””}
        2020-12-31 18:24:21:2418 DEBUG [INVOKE-ADCCLEANUP] {“name”:”rsa_letsencrypt_10″,”target”:”\”HTTP/1.0 200 OK\\r\\n\\r\\nPobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4.rJ3IdgLH44D7UR9aa3zyphyMBUB3ezc0yezmv5_lbR8\””}
        2020-12-31 18:24:21:3471 INFO [INVOKE-ADCCLEANUP] Trying to remove the Responder Action “rsa_letsencrypt_test”
        2020-12-31 18:24:21:4310 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction/rsa_letsencrypt_test”, METHOD: “DELETE”
        2020-12-31 18:24:21:5502 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderaction\”:{}}”
        2020-12-31 18:24:21:7657 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:21:7857 INFO [INVOKE-ADCCLEANUP] Responder Action removed successfully.
        2020-12-31 18:24:21:8116 INFO [INVOKE-ADCCLEANUP] Trying to remove the Responder Action “rsa_letsencrypt_10”
        2020-12-31 18:24:21:8325 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction/rsa_letsencrypt_10”, METHOD: “DELETE”
        2020-12-31 18:24:21:8536 DEBUG [INVOKE-ADCRESTAPI] JSON Payload: “{\”params\”:{\”onerror\”:\”EXIT\”,\”warning\”:\”NO\”},\”responderaction\”:{}}”
        2020-12-31 18:24:22:1060 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:22:1321 INFO [INVOKE-ADCCLEANUP] Responder Action removed successfully.
        2020-12-31 18:24:22:1864 INFO [INVOKE-ADCCLEANUP] Finished cleaning up.
        2020-12-31 18:24:22:2190 INFO [INVOKE-ADCCLEANUP] Cleaning the Citrix ADC Configuration.
        2020-12-31 18:24:22:2571 INFO [INVOKE-ADCCLEANUP] Trying to login into the Citrix ADC.
        2020-12-31 18:24:22:2880 INFO [CONNECT-ADC] Connecting to http://172.16.0.15
        2020-12-31 18:24:22:3912 DEBUG [CONNECT-ADC] Response: {“message”:”Done”,”severity”:”NONE”,”errorcode”:0}
        2020-12-31 18:24:22:4222 DEBUG [CONNECT-ADC] Trying to retrieve the ADC version
        2020-12-31 18:24:22:4997 DEBUG [CONNECT-ADC] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”,”nsversion”:{“version”:”NetScaler NS12.0: Build 63.13.nc, Date: Jan 16 2020, 05:08:11 “,”mode”:”1″}}
        2020-12-31 18:24:22:5313 INFO [CONNECT-ADC] Connected
        2020-12-31 18:24:22:5557 INFO [CONNECT-ADC] Connected to Citrix ADC http://172.16.0.15, as user nsroot, ADC Version NetScaler NS12.0: Build 63.13.nc
        2020-12-31 18:24:22:5840 INFO [INVOKE-ADCCLEANUP] Checking if a binding exists for “csp_letsencrypt”.
        2020-12-31 18:24:22:6158 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/csvserver_cspolicy_binding/cs_letsencrypt?filter=policyname:csp_letsencrypt”, METHOD: “GET”
        2020-12-31 18:24:22:7027 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:22:7552 INFO [INVOKE-ADCCLEANUP] No binding found.
        2020-12-31 18:24:22:7928 INFO [INVOKE-ADCCLEANUP] Checking if Content Switch Policy “csp_letsencrypt” exists.
        2020-12-31 18:24:22:8388 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/cspolicy/csp_letsencrypt”, METHOD: “GET”
        2020-12-31 18:24:23:0086 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:24:23:0395 INFO [INVOKE-ADCCLEANUP] Content Switch Policy not found.
        2020-12-31 18:24:23:0756 INFO [INVOKE-ADCCLEANUP] Checking if Load Balance VIP “lb_letsencrypt_cert” exists.
        2020-12-31 18:24:23:1077 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/lbvserver/lb_letsencrypt_cert”, METHOD: “GET”
        2020-12-31 18:24:23:2049 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:24:23:2338 INFO [INVOKE-ADCCLEANUP] Load Balance VIP not found.
        2020-12-31 18:24:23:2628 INFO [INVOKE-ADCCLEANUP] Checking if Load Balance Service “svc_letsencrypt_cert_dummy” exists.
        2020-12-31 18:24:23:2886 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/service/svc_letsencrypt_cert_dummy”, METHOD: “GET”
        2020-12-31 18:24:23:3799 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:24:23:5586 INFO [INVOKE-ADCCLEANUP] Load Balance Service not found.
        2020-12-31 18:24:23:6012 INFO [INVOKE-ADCCLEANUP] Checking if Load Balance Server “1.2.3.4” exists.
        2020-12-31 18:24:23:6153 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/server/1.2.3.4”, METHOD: “GET”
        2020-12-31 18:24:23:7055 ERROR [INVOKE-ADCRESTAPI] Caught an error. Exception Message: The remote server returned an error: (404) Not Found.
        2020-12-31 18:24:23:7406 INFO [INVOKE-ADCCLEANUP] Load Balance Server not found.
        2020-12-31 18:24:23:7887 INFO [INVOKE-ADCCLEANUP] Checking if there are Responder Policies starting with the name “rsp_letsencrypt”.
        2020-12-31 18:24:23:8303 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderpolicy?filter=name:%2Frsp_letsencrypt%2F”, METHOD: “GET”
        2020-12-31 18:24:23:9114 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:23:9556 INFO [INVOKE-ADCCLEANUP] No Responder Policies found.
        2020-12-31 18:24:24:0034 INFO [INVOKE-ADCCLEANUP] Checking if there are Responder Actions starting with the name “rsa_letsencrypt”.
        2020-12-31 18:24:24:0352 DEBUG [INVOKE-ADCRESTAPI] URI: “http://172.16.0.15/nitro/v1/config/responderaction?filter=name:%2Frsa_letsencrypt%2F”, METHOD: “GET”
        2020-12-31 18:24:24:1168 DEBUG [INVOKE-ADCRESTAPI] Response: {“errorcode”:0,”message”:”Done”,”severity”:”NONE”}
        2020-12-31 18:24:24:1548 INFO [INVOKE-ADCCLEANUP] No Responder Actions found.
        2020-12-31 18:24:24:2083 INFO [INVOKE-ADCCLEANUP] Finished cleaning up.
        2020-12-31 18:24:24:2609 DEBUG [FINAL-ACTIONS] There were unsaved changes, but no ConfigFile was defined.
        2020-12-31 18:24:24:3755 ERROR [FINAL-ACTIONS] There were 1 errors during the request for CN: “citrix.pama.it”!
        2020-12-31 18:24:24:4227 INFO [FINAL] There were one or more errors, please check the log or rerun with the “-LogLevel Debug” option!
        2020-12-31 18:24:24:4633 INFO [FINAL] Script Terminated, ExitCode: 1

        Thank you lotsm,
        Andrea

        • John Billekens Post author

          Hi Andrea,

          The script managed now to continued to run successfully, but the validation failed.

          2020-12-31 18:23:10:5877 DEBUG [ORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”expires”:”2021-01-07T17:22:56Z”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}
          2020-12-31 18:23:10:6526 DEBUG [ORDERVALIDATION] Items still pending: False
          2020-12-31 18:23:16:3080 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
          2020-12-31 18:23:22:0700 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
          ..
          2020-12-31 18:24:07:6873 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
          2020-12-31 18:24:13:4575 INFO [ORDERVALIDATION] Still 1 “pending” items left. Waiting an extra 5 seconds.
          2020-12-31 18:24:13:4827 DEBUG [ORDERVALIDATION] Loop ended, max reties reached!
          2020-12-31 18:24:14:2398 ERROR [ORDERVALIDATION] Unfortunately there are invalid items. Failed Records:
          2020-12-31 18:24:14:2772 DEBUG [ORDERVALIDATION] {“fqdn”:”citrix.pama.it”,”status”:”pending”,”expires”:”2021-01-07T17:22:56Z”,”HTTP01Status”:”pending”,”DNS01Status”:”pending”}

          This means Let’s Encrypt could not reach the Content Switch on port 80. LE wanted to validate the dns record “citrix.pama.it” by querying the url: citrix.pama.it/.well-known/acme-challenge/Pobg6eLzNXvMJ9QuChmJmunHNUxopm0CMYBTrusEE_4
          But Looks like this could not be validated. possibly port 80 or the http content switch was not reachable from the internet (at that time)?

          So the http Content Switch “cs_letsencrypt” with ip “172.16.0.18” must be reachable from the internet on port 80.

          The rest looks ok as far as I can see.

  • Harm Peter Millaard

    Hi John!

    Great script! This must have taken a long time to develop and I appreciate the work you have done! I can learn a lot from it!
    I even saw that with the latest dev version also supports the wildcard certificates.

    There is only one question I want to ask and maybe I’m just missing it, but where is the option to bind the new certificate to a LB or CS vServer?

    Kind regards,
    Harm Peter Millaard

    • John Billekens Post author

      Thats up to you. The script will add it as a ssl certificate in the NetScaler. You can configure it on any (ssl) vip you like.

      • Alexandre Yamada

        Hi,
        Im not an expert in powershell, but I added this session below on this script to create the DNS TXT Records on ADC (if you have your DNS configured on it).

        foreach ($Record in $TXTRecords) {
        Write-DisplayText -Blank
        Write-DisplayText -Line “DNS Hostname”
        Write-DisplayText -ForeGroundColor Cyan “$($Record.fqdn)”
        Write-DisplayText -Line “TXT Record Name.”
        Write-DisplayText -ForeGroundColor Yellow “$($Record.TXTName)”
        Write-DisplayText -Line “TXT Record Value”
        Write-DisplayText -ForeGroundColor Yellow “$($Record.TXTValue)”
        Write-ToLogFile -I -C DNSChallenge -M “DNS Hostname: `”$($Record.fqdn)`” => TXT Record Name: `”$($Record.TXTName)`”, Value: `”$($Record.TXTValue)`”.”

        #### ADDED THIS SESSION BELOW ####
        Write-DisplayText -Blank
        Write-DisplayText -ForeGroundColor Magenta “*** Creating TXT Record ***”
        Write-ToLogFile -I -C Invoke-AddInitialADCConfig -M “Creating TXT Record `”$($Record.TXTName)`”, Value: `”$($Record.TXTValue)`”.”
        $payload = @{“domain” = “$($Record.TXTName)”; “string” = “$($Record.TXTValue)”; “ttl” = “100”; }
        $payloaddel = @{“domain” = “$($Record.TXTName)”; “string” = “$($Record.TXTValue)”; }
        $response = Invoke-ADCRestApi -Session $ADCSession -Method DELETE -Type dnstxtrec -Resource $ApiUsername -Arguments $payloaddel -ErrorAction SilentlyContinue
        $response = Invoke-ADCRestApi -Session $ADCSession -Method POST -Type dnstxtrec -Payload $payload -Action add
        Write-DisplayText -ForeGroundColor Green “TXT Record Created”
        Write-ToLogFile -I -C Invoke-AddInitialADCConfig -M “TXT Record created `”$($Record.TXTName)`”, Value: `”$($Record.TXTValue)`”.”
        }

        I hope this helps anyone that have DNS on ADC.
        Thanks.