jb1981

GenLeCertForNS v0.9.1.beta1

Nov 13th, 2017
667
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. .SYNOPSIS
  3.     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
  4. .DESCRIPTION
  5.     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.
  6. .PARAMETER Help
  7.     Display the detailed information about this script
  8. .PARAMETER CleanNS
  9.     Cleanup the NetScaler configuration made within this script, for when somewhere it gone wrong
  10. .PARAMETER RemoveTestCertificates
  11.     Tries to remove all the Test certificates signed by the "Fake LE Intermediate X1" staging intermediate
  12. .PARAMETER NSManagementURL
  13.     Management URL, used to connect to the NetScaler
  14. .PARAMETER NSUserName
  15.     NetScaler username with enough access to configure it
  16. .PARAMETER NSPassword
  17.     NetScaler username password
  18. .PARAMETER NSCredential
  19.     Use a PSCredential object instead of a username or password. Use "Get-Credential" to generate a credential object
  20.     C:\PS> $Credential = Get-Credential
  21. .PARAMETER NSCsVipName
  22.     Name of the HTTP NetScaler Content Switch used for the domain validation
  23. .PARAMETER NSCsVipBinding
  24.     NetScaler Content Switch binding used for the validation
  25. .PARAMETER NSSvcName
  26.     NetScaler Load Balance service name
  27. .PARAMETER NSSvcDestination
  28.     IP Address used for the NetScaler Service (leave default 1.2.3.4), only change when already used
  29. .PARAMETER NSLbName
  30.     NetScaler Load Balance VIP name
  31. .PARAMETER NSRspName
  32.     NetScaler Responder Policy name
  33. .PARAMETER NSRsaName
  34.     NetScaler Responder Action name
  35. .PARAMETER NSCspName
  36.     NetScaler Content Switch Policy name
  37. .PARAMETER NSCertNameToUpdate
  38.     NetScaler SSL Certkey name currently in use, that needs to be renewd
  39. .PARAMETER CertDir
  40.     Directory where to store the certificates
  41. .PARAMETER PfxPassword
  42.     Password for the PFX certificate, generated at the end
  43. .PARAMETER EmailAddress
  44.     The email address used to request the certificates and receive a notification when the certificates (almost) expires
  45. .PARAMETER cn
  46.     (Common Name) The Primary (first) dns record for the certificaten
  47. .PARAMETER san
  48.     (Subject Alternate Name) every following domain listed in this certificate. sepatated via an comma , and between quotes "".
  49.     E.g.: "sts.domain.com","www.domain.com","vpn.domain.com"
  50. .PARAMETER Production
  51.     Use the production Let's encryt server
  52. .PARAMETER DisableIPCheck
  53.     If you want to skip the IP Address verification, specify this parameter
  54. .PARAMETER CleanVault
  55.     Force initialization of the vault before use
  56. .PARAMETER SaveNSConfig
  57.     Save the NetScaler config after all the changes.
  58. .PARAMETER ns10x
  59.     When using v10x, some nitro functions will not work propperly, run the script with this parameter.
  60. .EXAMPLE
  61.     .\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 "nsroot" -NSUserName "P@ssw0rd" -NSCertNameToUpdate "san_domain_com" -Production -CleanVault -Verbose
  62.     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.
  63. .EXAMPLE
  64.     .\GenLeCertForNS.ps1 -CleanNS -NSManagementURL "http://192.168.100.1" -NSCsVipName "cs_domain.com_http" -NSPassword "nsroot" -NSUserName "P@ssw0rd" -Verbose
  65.     Cleaning left over configuration from this schript when something went wrong during a previous attempt to generate new certificates and generating Verbose output.
  66. .EXAMPLE
  67.     .\GenLeCertForNS.ps1 -RemoveTestCertificates -NSManagementURL "http://192.168.100.1" -NSPassword "nsroot" -NSUserName "P@ssw0rd" -Verbose
  68.     Remob=ving ALL the test certificates from your NetScaler.
  69. .NOTES
  70.     File Name : GenLeCertForNS.ps1
  71.     Version   : v0.9.1.beta1
  72.     Author    : John Billekens
  73.     Requires  : PowerShell v3 and up
  74.                 NetScaler 11.x and up
  75.                 Run As Administrator
  76.                 ACMESharp 0.9.1.326 (can be installed via this script)
  77. .LINK
  78.     https://blog.j81.nl
  79. #>
  80.  
  81. [cmdletbinding(DefaultParametersetName="ConfigNetScaler")]
  82. param(
  83.         [Parameter(ParameterSetName="Help",Mandatory=$false)]
  84.         [alias("h")]
  85.         [switch]$Help,
  86.        
  87.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$true)]
  88.         [switch]$CleanNS,
  89.  
  90.         [Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
  91.         [alias("RemTestCert")]
  92.         [switch]$RemoveTestCertificates,
  93.        
  94.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
  95.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$true)]
  96.         [Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$true)]
  97.         [ValidateNotNullOrEmpty()]
  98.         [alias("URL")]
  99.         [string]$NSManagementURL,
  100.        
  101.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  102.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  103.         [Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
  104.         [alias("User", "Username")]
  105.         [string]$NSUserName,
  106.        
  107.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  108.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  109.         [Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
  110.         [alias("Password")]
  111.         [string]$NSPassword,
  112.  
  113.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  114.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  115.         [Parameter(ParameterSetName="CleanTestCertificate",Mandatory=$false)]
  116.         [ValidateScript({
  117.             if ($_ -is [System.Management.Automation.PSCredential]) {
  118.                 $true
  119.             } elseif ($_ -is [string]) {
  120.                 $Script:Credential=Get-Credential -Credential $_
  121.                 $true
  122.             } else {
  123.                 Write-Error "You passed an unexpected object type for the credential (-NSCredential)"
  124.             }
  125.         })][alias("Credential")]
  126.         [object]$NSCredential,
  127.        
  128.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
  129.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$true)]
  130.         [ValidateNotNullOrEmpty()]
  131.         [string]$NSCsVipName,
  132.        
  133.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  134.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  135.         [string]$NSCsVipBinding = 11,
  136.        
  137.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  138.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  139.         [string]$NSSvcName = "svc_letsencrypt_cert_dummy",
  140.        
  141.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  142.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  143.         [string]$NSSvcDestination = "1.2.3.4",
  144.        
  145.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  146.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  147.         [string]$NSLbName = "lb_letsencrypt_cert",
  148.        
  149.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  150.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  151.         [string]$NSRspName = "rsp_letsencrypt",
  152.        
  153.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  154.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  155.         [string]$NSRsaName = "rsa_letsencrypt",
  156.        
  157.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  158.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  159.         [string]$NSCspName = "csp_NSCertCsp",
  160.        
  161.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  162.         [string]$NSCertNameToUpdate,
  163.        
  164.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
  165.         [ValidateNotNullOrEmpty()]
  166.         [string]$CertDir,
  167.        
  168.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  169.         [string]$PfxPassword = $null,
  170.        
  171.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
  172.         [ValidateNotNullOrEmpty()]
  173.         [string]$CN,
  174.        
  175.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$true)]
  176.         [string]$EmailAddress,
  177.        
  178.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  179.         [string[]]$SAN=@(),
  180.        
  181.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  182.         [switch]$Production,
  183.        
  184.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  185.         [switch]$DisableIPCheck,
  186.  
  187.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  188.         [switch]$CleanVault,
  189.        
  190.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  191.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  192.         [switch]$SaveNSConfig,
  193.        
  194.         [Parameter(ParameterSetName="ConfigNetScaler",Mandatory=$false)]
  195.         [Parameter(ParameterSetName="CleanNetScaler",Mandatory=$false)]
  196.         [switch]$ns10x
  197. )
  198.  
  199. #requires -version 3.0
  200. #requires -runasadministrator
  201.  
  202. #region Functions
  203.  
  204. function InvokeNSRestApi {
  205.     [CmdletBinding()]
  206.     param (
  207.         [Parameter(Mandatory=$true)]
  208.         [PSObject]$Session,
  209.  
  210.         [Parameter(Mandatory=$true)]
  211.         [ValidateSet('DELETE', 'GET', 'POST', 'PUT')]
  212.         [string]$Method,
  213.  
  214.         [Parameter(Mandatory=$true)]
  215.         [string]$Type,
  216.  
  217.         [string]$Resource,
  218.  
  219.         [string]$Action,
  220.  
  221.         [hashtable]$Arguments = @{},
  222.  
  223.         [switch]$Stat = $false,
  224.  
  225.         [ValidateScript({$Method -eq 'GET'})]
  226.         [hashtable]$Filters = @{},
  227.  
  228.         [ValidateScript({$Method -ne 'GET'})]
  229.         [hashtable]$Payload = @{},
  230.  
  231.         [switch]$GetWarning = $false,
  232.  
  233.         [ValidateSet('EXIT', 'CONTINUE', 'ROLLBACK')]
  234.         [string]$OnErrorAction = 'EXIT'
  235.     )
  236.     # https://github.com/devblackops/NetScaler
  237.     if ([string]::IsNullOrEmpty($($Session.ManagementURL))) {
  238.         throw "ERROR. Probably not logged into the NetScaler"
  239.     }
  240.     if ($Stat) {
  241.         $uri = "$($Session.ManagementURL)/nitro/v1/stat/$Type"
  242.     } else {
  243.         $uri = "$($Session.ManagementURL)/nitro/v1/config/$Type"
  244.     }
  245.     if (-not ([string]::IsNullOrEmpty($Resource))) {
  246.         $uri += "/$Resource"
  247.     }
  248.     if ($Method -ne 'GET') {
  249.         if (-not ([string]::IsNullOrEmpty($Action))) {
  250.             $uri += "?action=$Action"
  251.         }
  252.  
  253.         if ($Arguments.Count -gt 0) {
  254.             $queryPresent = $true
  255.             if ($uri -like '*?action*') {
  256.                 $uri += '&args='
  257.             } else {
  258.                 $uri += '?args='
  259.             }
  260.             $argsList = @()
  261.             foreach ($arg in $Arguments.GetEnumerator()) {
  262.                 $argsList += "$($arg.Name):$([System.Uri]::EscapeDataString($arg.Value))"
  263.             }
  264.             $uri += $argsList -join ','
  265.         }
  266.     } else {
  267.         $queryPresent = $false
  268.         if ($Arguments.Count -gt 0) {
  269.             $queryPresent = $true
  270.             $uri += '?args='
  271.             $argsList = @()
  272.             foreach ($arg in $Arguments.GetEnumerator()) {
  273.                 $argsList += "$($arg.Name):$([System.Uri]::EscapeDataString($arg.Value))"
  274.             }
  275.             $uri += $argsList -join ','
  276.         }
  277.         if ($Filters.Count -gt 0) {
  278.             $uri += if ($queryPresent) { '&filter=' } else { '?filter=' }
  279.             $filterList = @()
  280.             foreach ($filter in $Filters.GetEnumerator()) {
  281.                 $filterList += "$($filter.Name):$([System.Uri]::EscapeDataString($filter.Value))"
  282.             }
  283.             $uri += $filterList -join ','
  284.         }
  285.     }
  286.     Write-Verbose -Message "URI: $uri"
  287.  
  288.     $jsonPayload = $null
  289.     if ($Method -ne 'GET') {
  290.         $warning = if ($GetWarning) { 'YES' } else { 'NO' }
  291.         $hashtablePayload = @{}
  292.         $hashtablePayload.'params' = @{'warning' = $warning; 'onerror' = $OnErrorAction; <#"action"=$Action#>}
  293.         $hashtablePayload.$Type = $Payload
  294.         $jsonPayload = ConvertTo-Json -InputObject $hashtablePayload -Depth 100
  295.         Write-Verbose -Message "JSON Payload:`n$jsonPayload"
  296.     }
  297.  
  298.     $response = $null
  299.     $restError = $null
  300.     try {
  301.         $restError = @()
  302.         $restParams = @{
  303.             Uri = $uri
  304.             ContentType = 'application/json'
  305.             Method = $Method
  306.             WebSession = $Session.WebSession
  307.             ErrorVariable = 'restError'
  308.             Verbose = $false
  309.         }
  310.  
  311.         if ($Method -ne 'GET') {
  312.             $restParams.Add('Body', $jsonPayload)
  313.         }
  314.  
  315.         $response = Invoke-RestMethod @restParams
  316.  
  317.         if ($response) {
  318.             if ($response.severity -eq 'ERROR') {
  319.                 throw "Error. See response: `n$($response | Format-List -Property * | Out-String)"
  320.             } else {
  321.                 Write-Verbose -Message "Response:`n$(ConvertTo-Json -InputObject $response | Out-String)"
  322.                 if ($Method -eq "GET") { return $response }
  323.             }
  324.         }
  325.     }
  326.     catch [Exception] {
  327.         if ($Type -eq 'reboot' -and $restError[0].Message -eq 'The underlying connection was closed: The connection was closed unexpectedly.') {
  328.             Write-Verbose -Message 'Connection closed due to reboot'
  329.         } else {
  330.             throw $_
  331.         }
  332.     }
  333. }
  334.  
  335. function Connect-NetScaler {
  336.     [cmdletbinding()]
  337.     param(
  338.         [parameter(Mandatory)]
  339.         [string]$ManagementURL,
  340.  
  341.         [parameter(Mandatory)]
  342.         [pscredential]$Credential = (Get-Credential -Message 'NetScaler credential'),
  343.  
  344.         [int]$Timeout = 3600,
  345.  
  346.         [switch]$PassThru
  347.     )
  348.     # https://github.com/devblackops/NetScaler
  349.     Write-Verbose -Message "Connecting to $ManagementURL..."
  350.     try {
  351.         if ($script:ns10x) {
  352.             $login = @{
  353.                 login = @{
  354.                     username = $Credential.UserName;
  355.                     password = $Credential.GetNetworkCredential().Password
  356.                 }
  357.             }
  358.         } else {
  359.             $login = @{
  360.                 login = @{
  361.                     username = $Credential.UserName;
  362.                     password = $Credential.GetNetworkCredential().Password
  363.                     timeout = $Timeout
  364.                 }
  365.             }
  366.         }
  367.         $loginJson = ConvertTo-Json -InputObject $login
  368.         Write-Verbose "JSON Data:`n$($loginJson | Out-String)"
  369.         $saveSession = @{}
  370.         $params = @{
  371.             Uri = "$ManagementURL/nitro/v1/config/login"
  372.             Method = 'POST'
  373.             Body = $loginJson
  374.             SessionVariable = 'saveSession'
  375.             ContentType = 'application/json'
  376.             ErrorVariable = 'restError'
  377.             Verbose = $false
  378.         }
  379.         $response = Invoke-RestMethod @params
  380.  
  381.         if ($response.severity -eq 'ERROR') {
  382.             throw "Error. See response: `n$($response | Format-List -Property * | Out-String)"
  383.         } else {
  384.             Write-Verbose -Message "Response:`n$(ConvertTo-Json -InputObject $response | Out-String)"
  385.         }
  386.     } catch [Exception] {
  387.         throw $_
  388.     }
  389.     $session = [PSObject]@{
  390.         ManagementURL=[string]$ManagementURL;
  391.         WebSession=[Microsoft.PowerShell.Commands.WebRequestSession]$saveSession;
  392.         Username=$Credential.UserName;
  393.         Version="UNKNOWN";
  394.     }
  395.  
  396.     try {
  397.         Write-Verbose -Message "Trying to retreive the NetScaler version"
  398.         $params = @{
  399.             Uri = "$ManagementURL/nitro/v1/config/nsversion"
  400.             Method = 'GET'
  401.             WebSession = $Session.WebSession
  402.             ContentType = 'application/json'
  403.             ErrorVariable = 'restError'
  404.             Verbose = $false
  405.         }
  406.         $response = Invoke-RestMethod @params
  407.         Write-Verbose -Message "Response:`n$(ConvertTo-Json -InputObject $response | Out-String)"
  408.         $version = $response.nsversion.version.Split(",")[0]
  409.         if (-not ([string]::IsNullOrWhiteSpace($version))) {
  410.             $session.version = $version
  411.         }
  412.     } catch {
  413.         Write-Verbose -Message "Error. See response: `n$($response | Format-List -Property * | Out-String)"
  414.     }
  415.     $Script:NSSession = $session
  416.    
  417.     if($PassThru){
  418.         return $session
  419.     }
  420. }
  421.  
  422. #endregion Functions
  423.  
  424. #region Help
  425.  
  426. if($Help){
  427.     Write-Verbose "Generating help for `"$ScriptFilename`""
  428.     Get-Help "$ScriptFilename" -Full
  429.     Exit(0)
  430. }
  431.  
  432. #endregion Help
  433.  
  434. #region Script variables
  435.  
  436. $ScriptVersion = "v0.9.1.beta1"
  437. Write-Verbose "Script version: $ScriptVersion"
  438. if ($ns10x){
  439.     Write-Verbose "ns10x parameter used, some options are now disabled."
  440. }
  441. Write-Verbose "Setting session DATE/TIME variable"
  442. [datetime]$ScriptDateTime = Get-Date
  443. [string]$SessionDateTime = $ScriptDateTime.ToString("yyyyMMdd-HHmmss")
  444. Write-Verbose "Session DATE/TIME variable value: `"$SessionDateTime`""
  445.  
  446. if (-not([string]::IsNullOrWhiteSpace($NSCredential))) {
  447.     Write-Verbose "Using NSCredential"
  448. } elseif ((-not([string]::IsNullOrWhiteSpace($NSUserName))) -and (-not([string]::IsNullOrWhiteSpace($NSPassword)))){
  449.     Write-Verbose "Using NSUsername / NSPassword"
  450.     [pscredential]$NSCredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $NSUserName, $(ConvertTo-SecureString -String $NSPassword -AsPlainText -Force)
  451. } else {
  452.     Write-Verbose "No valid username/password or credential specified. Enter a username and password, e.g. `"nsroot`""
  453.     [pscredential]$NSCredential = Get-Credential -Message "NetScaler username and password:"
  454. }
  455. Write-Verbose "Starting new session"
  456. if(-not ([string]::IsNullOrWhiteSpace($SAN))){
  457.     [string[]]$SAN = @($SAN.Split(","))
  458. }
  459.  
  460. #endregion Script variables
  461.  
  462. #region Load Module
  463.  
  464. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  465.     Write-Verbose "Load ACMESharp Modules"
  466.     if (-not(Get-Module ACMESharp)){
  467.         try {
  468.             $ACMEVersions = (get-Module -Name ACMESharp -ListAvailable).Version
  469.             $ACMEUpdateRequired = $false
  470.             ForEach ($ACMEVersion in $ACMEVersions) {
  471.                 if (($ACMEVersion.Minor -eq 9) -and ($ACMEVersion.Build -eq 1) -and (-not $ACMEUpdateRequired)) {
  472.                     Write-Verbose "v0.9.1 of ACMESharp is installed, continuing"
  473.                 } else {
  474.                     Write-Verbose "v0.9.1 of ACMESharp is NOT installed, update/downgrade required"
  475.                     $ACMEUpdateRequired = $true
  476.                 }
  477.             }
  478.             if ($ACMEUpdateRequired) {
  479.                 Write-Verbose "Trying to update the ACMESharp modules"
  480.                 Install-Module -Name ACMESharp -Scope AllUsers -RequiredVersion 0.9.1 -Force -ErrorAction SilentlyContinue
  481.             }
  482.             Write-Verbose "Try loading module ACMESharp"
  483.             Import-Module ACMESharp -ErrorAction Stop
  484.         } catch [System.IO.FileNotFoundException] {
  485.             Write-Verbose "Checking for PackageManagement"
  486.             if ([string]::IsNullOrWhiteSpace($(Get-Module -ListAvailable -Name PackageManagement))) {
  487.                 Write-Warning "PackageManagement is not available please install this first or manually install ACMESharp"
  488.                 Write-Warning "Visit `"https://docs.microsoft.com/en-us/powershell/gallery/psget/get_psget_module`" to download Package Management"
  489.                 Write-Warning "ACMESharp: https://github.com/ebekker/ACMESharp"
  490.                 Start "https://www.microsoft.com/en-us/download/details.aspx?id=49186"
  491.                 Exit (1)
  492.             } else {
  493.                 try {
  494.                     if (-not ((Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue).Version -ge [System.Version]"2.8.5.208")) {
  495.                         Write-Verbose "Installing Nuget"
  496.                         Get-PackageProvider -Name NuGet -Force -ErrorAction SilentlyContinue | Out-Null
  497.                     }
  498.                     $installationPolicy = (Get-PSRepository -Name PSGallery).InstallationPolicy
  499.                     if (-not ($installationPolicy.ToLower() -eq "trusted")){
  500.                         Write-Verbose "Defining PSGallery PSRepository as trusted"
  501.                         Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
  502.                     }
  503.                     Write-Verbose "Installing ACMESharp"
  504.                     try {
  505.                         Install-Module -Name ACMESharp -Scope AllUsers -RequiredVersion 0.9.1.326 -Force -AllowClobber
  506.                     } catch {
  507.                         Write-Verbose "Installing ACMESharp again but without the -AllowClobber option"
  508.                         Install-Module -Name ACMESharp -Scope AllUsers -RequiredVersion 0.9.1.326 -Force
  509.                     }
  510.                     if (-not ((Get-PSRepository -Name PSGallery).InstallationPolicy -eq $installationPolicy)){
  511.                         Write-Verbose "Returning the PSGallery PSRepository InstallationPolicy to previous value"
  512.                         Set-PSRepository -Name "PSGallery" -InstallationPolicy $installationPolicy | Out-Null
  513.                     }
  514.                     Write-Verbose "Try loading module ACMESharp"
  515.                     Import-Module ACMESharp -ErrorAction Stop
  516.                 } catch {
  517.                     Write-Verbose "Error Details: $($_.Exception.Message)"
  518.                     Write-Error "Error while loading and/or installing module"
  519.                     Write-Warning "PackageManagement is not available please install this first or manually install ACMESharp"
  520.                     Write-Warning "Visit `"https://docs.microsoft.com/en-us/powershell/gallery/psget/get_psget_module`" to download Package Management"
  521.                     Write-Warning "ACMESharp: https://github.com/ebekker/ACMESharp"
  522.                     Start "https://www.microsoft.com/en-us/download/details.aspx?id=49186"
  523.                     Exit (1)
  524.                 }
  525.             }
  526.         }
  527.     }
  528. }
  529.  
  530. #endregion Load Module
  531.  
  532. #region NetScaler Check
  533.  
  534. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  535.     Write-Verbose "Login to NetScaler and save session to global variable"
  536.     Write-Host -ForeGroundColor White "`r`nNetScaler:"
  537.     $NSSession = Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential -PassThru
  538.     Write-Host -ForeGroundColor White -NoNewLine "- URL: "
  539.     Write-Host -ForeGroundColor Green "$NSManagementURL"
  540.     Write-Host -ForeGroundColor White -NoNewLine "- Username: "
  541.     Write-Host -ForeGroundColor Green "$($NSSession.Username)"
  542.     Write-Host -ForeGroundColor White -NoNewLine "- Version: "
  543.     Write-Host -ForeGroundColor Green "$($NSSession.Version)"
  544.     try {
  545.         Write-Verbose "Verifying Content Switch"
  546.         $response = InvokeNSRestApi -Session $NSSession -Method GET -Type csvserver -Resource $NSCsVipName
  547.     } catch {
  548.         $ExcepMessage = $_.Exception.Message
  549.         Write-Verbose "Error Details: $ExcepMessage"
  550.     } finally {
  551.         if (($response.errorcode -eq "0") -and `
  552.                 ($response.csvserver.type -eq "CONTENT") -and `
  553.                 ($response.csvserver.curstate -eq "UP") -and `
  554.                 ($response.csvserver.servicetype -eq "HTTP") -and `
  555.                 ($response.csvserver.port -eq "80") ) {
  556.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
  557.             Write-Host -ForeGroundColor Green "`"$NSCsVipName`" -> Found"
  558.             Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
  559.             Write-Host -ForeGroundColor Green "OK`r`n"
  560.         } elseif ($ExcepMessage -like "*(404) Not Found*") {
  561.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
  562.             Write-Host -ForeGroundColor Red "ERROR: The Content Switch `"$NSCsVipName`" does NOT exists!`r`n"
  563.             Write-Host -ForeGroundColor White -NoNewLine "- Error message: "
  564.             Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
  565.             Write-Host -ForeGroundColor Yellow "  IMPORTANT: Please make sure a HTTP Content Switch is available`r`n"
  566.             Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
  567.             Write-Host -ForeGroundColor Red "FAILED!`r`n"
  568.             Write-Host -ForeGroundColor Red "  Exiting now`r`n"
  569.             Exit (1)
  570.         }  elseif ($ExcepMessage -like "*The remote server returned an error*") {
  571.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
  572.             Write-Host -ForeGroundColor Red "ERROR: Unknown error found while checking the Content Switch"
  573.             Write-Host -ForeGroundColor White -NoNewLine "- Error message: "
  574.             Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
  575.             Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
  576.             Write-Host -ForeGroundColor Red "FAILED!`r`n"
  577.             Write-Host -ForeGroundColor Red "  Exiting now`r`n"
  578.             Exit (1)
  579.         } elseif (($response.errorcode -eq "0") -and (-not ($response.csvserver.servicetype -eq "HTTP"))) {
  580.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
  581.             Write-Host -ForeGroundColor Red "ERROR: Content Switch is $($response.csvserver.servicetype) and NOT HTTP`r`n"
  582.             if (-not ([string]::IsNullOrWhiteSpace($ExcepMessage))){
  583.                 Write-Host -ForeGroundColor White -NoNewLine "- Error message: "
  584.                 Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
  585.             }
  586.             Write-Host -ForeGroundColor Yellow "  IMPORTANT: Please use a HTTP (Port 80) Content Switch!`r`n  This is required for the validation.`r`n"
  587.             Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
  588.             Write-Host -ForeGroundColor Red "FAILED!`r`n"
  589.             Write-Host -ForeGroundColor Red "  Exiting now`r`n"
  590.             Exit (1)
  591.         } else {
  592.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch: "
  593.             Write-Host -ForeGroundColor Green "Found"
  594.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch state: "
  595.             if ($response.csvserver.curstate -eq "UP") {
  596.                 Write-Host -ForeGroundColor Green "UP"
  597.             } else {
  598.                 Write-Host -ForeGroundColor RED "$($response.csvserver.curstate)"
  599.             }
  600.             Write-Host -ForeGroundColor White -NoNewLine "- Content Switch type: "
  601.             if ($response.csvserver.type -eq "CONTENT") {
  602.                 Write-Host -ForeGroundColor Green "CONTENT"
  603.             } else {
  604.                 Write-Host -ForeGroundColor RED "$($response.csvserver.type)"
  605.             }
  606.             if (-not ([string]::IsNullOrWhiteSpace($ExcepMessage))){
  607.                 Write-Host -ForeGroundColor White -NoNewLine "`r`n- Error message: "
  608.                 Write-Host -ForeGroundColor Red "`"$ExcepMessage`"`r`n"
  609.             }
  610.             Write-Host -ForeGroundColor White -NoNewLine "- Data: "
  611.             $response.csvserver  | Format-List -Property * | Out-String
  612.             Write-Host -ForeGroundColor White -NoNewLine "- Connection: "
  613.             Write-Host -ForeGroundColor Red "FAILED!`r`n"
  614.             Write-Host -ForeGroundColor Red "  Exiting now`r`n"
  615.             Exit (1)
  616.         }
  617.     }
  618. }
  619.  
  620. #endregion NetScaler Check
  621.  
  622. #region Vault
  623.  
  624. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  625.     if ($Production) {
  626.         $VaultName = ":sys"
  627.         $BaseService = "LetsEncrypt"
  628.         Write-Verbose "Using the vault `"$VaultName`" for production certificates"
  629.     } else {
  630.         $VaultName = ":user"   
  631.         $BaseService = "LetsEncrypt-STAGING"
  632.         Write-Verbose "Using the vault `"$VaultName`" for test/staging purposes"
  633.     }
  634.     try {
  635.         Write-Verbose "Get ACMEVault `"$VaultName`""
  636.         $VaultData = ACMESharp\Get-ACMEVault -VaultProfile $VaultName
  637.     } catch {
  638.         Write-Verbose "`"$VaultName`" Vault not available, initialize"
  639.         $CleanVault = $true
  640.     }
  641.     if ($CleanVault) {
  642.         Write-Verbose "Initializing Vault"
  643.         ACMESharp\Initialize-ACMEVault -VaultProfile $VaultName -Force
  644.         Write-Verbose "Finished initializing"
  645.         $VaultData = ACMESharp\Get-ACMEVault -VaultProfile $VaultName
  646.     }
  647.     Write-Verbose "Configure vault `"$VaultName`" for `"$BaseService`""
  648.     ACMESharp\Set-ACMEVault -VaultProfile $VaultName -BaseService $BaseService
  649. }
  650.  
  651. #endregion Vault
  652.  
  653. #region Registration
  654.  
  655. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  656.     Write-Host -NoNewLine -ForeGroundColor Yellow "`n`nIMPORTANT: "
  657.     Write-Host -ForeGroundColor White "By running this script you agree with the terms specified by Let's Encrypt."
  658.     try {
  659.         Write-Verbose "Retreive existing Registration"
  660.         $Registration = ACMESharp\Get-ACMERegistration -VaultProfile $VaultName
  661.         if ($Registration.Contacts -contains "mailto:$($EmailAddress)"){
  662.             Write-Verbose "Existing registration found, no changes necessary"
  663.         } else {
  664.             Write-Verbose "Current registration `"$($Registration.Contacts)`" is not equal to `"$EmailAddress`", setting new registration"
  665.             $Registration = ACMESharp\New-ACMERegistration -VaultProfile $VaultName -Contacts "mailto:$($EmailAddress)" -AcceptTos
  666.         }
  667.     } catch {
  668.         Write-Verbose "Setting new registration to `"$EmailAddress`""
  669.        
  670.         $Registration = ACMESharp\New-ACMERegistration -VaultProfile $VaultName -Contacts "mailto:$($EmailAddress)" -AcceptTos
  671.     }
  672.     Write-Host -ForeGroundColor Yellow "`n`n`nTerms of Agreement:`n$($Registration.TosLinkUri)`n`n`n"
  673. }
  674.  
  675. #endregion Registration
  676.  
  677. #region DNS
  678.  
  679. #region Primary DNS
  680.  
  681. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  682.     Write-Verbose "Validating DNS record(s)"
  683.     $DNSObjects = @()
  684.    
  685.     Write-Verbose "Checking `"$CN`""
  686.     try {
  687.         if ($DisableIPCheck){
  688.             Write-Warning "Skipping IP check, validation might fail"
  689.             $PrimaryIP = "NoIPCheck"
  690.         } else {
  691.             $PublicDnsServer = "208.67.222.222"
  692.             Write-Verbose "Using public DNS server (OpenDNS, 208.67.222.222) to verify dns records"
  693.             Write-Verbose "Trying to get IP Address"
  694.             $PrimaryIP = (Resolve-DnsName -Server $PublicDnsServer -Name $CN -DnsOnly -Type A -ErrorAction SilentlyContinue).IPAddress
  695.             if ([string]::IsNullOrWhiteSpace($PrimaryIP)) {
  696.                 throw "ERROR: No valid entry found for DNSName:`"$CN`""
  697.             }
  698.             if ($PrimaryIP -is [system.array]){
  699.                 Write-Warning "More than one ip address found`n$($PrimaryIP | Format-Table | Out-String)"
  700.                 $PrimaryIP = $PrimaryIP[0]
  701.                 Write-Warning "using the first one`"$PrimaryIP`""
  702.             }
  703.         }
  704.     } catch {
  705.         Write-Verbose "Error Details: $($_.Exception.Message)"
  706.         Write-Host -ForeGroundColor Red "`nError while retreiving IP Address,"
  707.         Write-Host -ForeGroundColor Red "you can try to re-run the script with the -DisableIPCheck parameter.`n"
  708.         throw "Error while retreiving IP Address, does not exists?"
  709.     }
  710.    
  711.     try {
  712.         Write-Verbose "Find pre-existing registration for `"$CN`""
  713.         $IdentifierAlias = "DNS-$($CN)"
  714.         $Identifier = ACMESharp\Get-ACMEIdentifier -IdentifierRef $IdentifierAlias -VaultProfile $VaultName
  715.     } catch {
  716.         try {
  717.             Write-Verbose "Registration does not exist, registering `"$CN`""
  718.             $Identifier = ACMESharp\New-ACMEIdentifier -Dns $CN -Alias $IdentifierAlias -VaultProfile $VaultName
  719.         } catch {
  720.             Write-Verbose "Registration is invalid"
  721.             $Identifier = [PSCustomObject]@{
  722.                 Status = "invalid"
  723.                 Expires = $null
  724.             }
  725.         }
  726.     }
  727.    
  728.     try {
  729.         if ($Identifier.Uri) {
  730.             Write-Verbose "Extracting data, checking validation"
  731.             $response = Invoke-RestMethod -Uri $Identifier.Uri -Method Get
  732.             #$result = $response  | Select-Object status,expires
  733.             if ((-not([string]::IsNullOrWhiteSpace($response.status))) -and (-not([string]::IsNullOrWhiteSpace($response.expires)))) {
  734.                 $httpIdentifier = ($response | select -expand Challenges | Where-Object {$_.type -eq "http-01"})
  735.             }
  736.         } else {
  737.             Write-Verbose "No URI available to check..."
  738.         }
  739.     }catch{
  740.         Write-Verbose "Someting went wrong with the validation:`n$($response | Format-Table | Out-String)"
  741.     }
  742.  
  743.     Write-Verbose "Checking if current validation is still valid"
  744.     if (($response.status -eq "valid") -and ($([datetime]$response.Expires - $(Get-Date)).TotalDays -gt 1)) {
  745.         Write-Verbose "Registration for `"$CN`" is still valid"
  746.         $Validation = $true
  747.         Write-Verbose "Validation response:`n$($($response | Select-Object Identifier,Status,Expires) | Format-Table | Out-String)"
  748.     } else {
  749.         Write-Verbose "Registration for `"$CN`" is NOT valid, validation required"
  750.         $Validation = $false
  751.         Write-Verbose "Validation response:`n$($($Identifier | Select-Object Identifier,Status,Expires) | Format-Table | Out-String)"
  752.     }
  753.     Write-Verbose "Storing values for reference"
  754.     $DNSObjects += [PSCustomObject]@{
  755.         DNSName = $CN
  756.         IPAddress = $PrimaryIP
  757.         Status = $(if ([string]::IsNullOrWhiteSpace($PrimaryIP)) {$false} else {$true})
  758.         Match = $null
  759.         SAN = $false
  760.         DNSValid = $Validation
  761.         Alias = $IdentifierAlias
  762.     }
  763.     Write-Verbose "SAN Objects:`n$($DNSObjects | Format-Table | Out-String)"
  764. }
  765.  
  766. #endregion Primary DNS
  767.  
  768. #region SAN
  769.  
  770. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  771.     Write-Verbose "Checking if SAN entries are available"
  772.     if ([string]::IsNullOrWhiteSpace($SAN)) {
  773.         Write-Verbose "No SAN entries found"
  774.     } elseif (($($SAN.Count) -eq 1) -and ($SAN[0] -eq $CN)) {
  775.         Write-Verbose "Skipping SAN, CN:`"$CN`" is equal to SAN:`"$($SAN[0])`""
  776.     } else {
  777.         Write-Verbose "$($SAN.Count) found, checking each one"
  778.         foreach ($DNSRecord in $SAN) {
  779.             try {
  780.                 if ($DisableIPCheck) {
  781.                     Write-Verbose "Skipping IP check"
  782.                     $SANIP = "NoIPCheck"
  783.                 } else {
  784.                     Write-Verbose "Start basic IP Check for `"$DNSRecord`", trying to get IP Address"
  785.                     $SANIP = (Resolve-DnsName -Server $PublicDnsServer -Name $DNSRecord -DnsOnly -Type A -ErrorAction SilentlyContinue).IPAddress
  786.                     if ($SANIP -is [system.array]){
  787.                         Write-Warning "More than one ip address found`n$($SANIP | Format-Table | Out-String)"
  788.                         $SANIP = $SANIP[0]
  789.                         Write-Warning "using the first one`"$SANIP`""
  790.                     }
  791.                     Write-Verbose "Finished, Result: $SANIP"
  792.                 }
  793.                
  794.             } catch {
  795.                 Write-Verbose "Error Details: $($_.Exception.Message)"
  796.                 Write-Host -ForeGroundColor Red "`nError while retreiving IP Address,"
  797.                 Write-Host -ForeGroundColor Red "you can try to re-run the script with the -DisableIPCheck parameter."
  798.                 Write-Host -ForeGroundColor Red "The script will continue but `"$DNSRecord`" will be skipped`n"
  799.                 $SANIP = "Skipped"
  800.             }
  801.             if ([string]::IsNullOrWhiteSpace($SANIP)) {
  802.                 Write-Verbose "No valid entry found for DNSName:`"$DNSRecord`""
  803.                 $SANMatch = $false
  804.                 $SANStatus = $false
  805.             } else {
  806.                 Write-Verbose "Valid entry found"
  807.                 $SANStatus = $true
  808.                 if ($SANIP -eq "NoIPCheck") {
  809.                     Write-Verbose "IP address checking was disabled"
  810.                     $SANMatch = $true
  811.                 } elseif ($SANIP -eq "Skipped") {
  812.                     Write-Verbose "IP address checking failed, `"$DNSRecord`" will be skipped"
  813.                     $SANMatch = $true
  814.                 } else {
  815.                     Write-Verbose "All IP Adressess must match, checking"
  816.                     if ($SANIP -match $($DNSObjects[0].IPAddress)) {
  817.                         Write-Verbose "`"$SANIP ($DNSRecord)`" matches to `"$($DNSObjects[0].IPAddress) ($($DNSObjects[0].DNSName))`""
  818.                         $SANMatch = $true
  819.                     } else {
  820.                         Write-Verbose "`"$SANIP`" ($DNSRecord) NOT matches to `"$($DNSObjects[0].IPAddress)`" ($($DNSObjects[0].DNSName))"
  821.                         $SANMatch = $false
  822.                     }
  823.                 }
  824.             }
  825.             if (-not($SANIP -eq "Skipped")) {
  826.                 try {
  827.                     Write-Verbose "Find pre-existing registration for `"$DNSRecord`""
  828.                     $IdentifierAlias = "DNS-$($DNSRecord)"
  829.                     $Identifier = ACMESharp\Get-ACMEIdentifier -IdentifierRef $IdentifierAlias -VaultProfile $VaultName
  830.                 } catch {
  831.                     try {
  832.                         Write-Verbose "Registration does not exist, registering `"$DNSRecord`""
  833.                         $Identifier = ACMESharp\New-ACMEIdentifier -Dns $DNSRecord -Alias $IdentifierAlias -VaultProfile $VaultName
  834.                     } catch {
  835.                         Write-Verbose "Registration is invalid"
  836.                         $Identifier = [PSCustomObject]@{
  837.                             Status = "invalid"
  838.                             Expires = $null
  839.                         }
  840.                     }
  841.                 }
  842.                 try {
  843.                     if ($Identifier.Uri) {
  844.                         Write-Verbose "Extracting data, checking validation"
  845.                         $response = Invoke-RestMethod -Uri $Identifier.Uri -Method Get
  846.                         #$result = $response  | Select-Object status,expires
  847.                         if ((-not([string]::IsNullOrWhiteSpace($response.status))) -and (-not([string]::IsNullOrWhiteSpace($response.expires)))) {
  848.                             $httpIdentifier = ($response | select -expand Challenges | Where-Object {$_.type -eq "http-01"})
  849.                         }
  850.                     } else {
  851.                         Write-Verbose "No URI available to check..."
  852.                     }
  853.                 }catch{
  854.                     Write-Verbose "Someting went wrong with the validation: $($response | Format-Table | Out-String)"
  855.                 }
  856.                 if (($response.status -eq "valid") -and ($([datetime]$response.Expires - $(Get-Date)).TotalDays -gt 1)) {
  857.                     Write-Verbose "Registration for `"$DNSRecord`" is still valid"
  858.                     $Validation = $true
  859.                     Write-Verbose "Validation response:`n$($($response | Select-Object Identifier,Status,Expires) | Format-Table | Out-String)"
  860.                 } else {
  861.                     Write-Verbose "Registration for `"$DNSRecord`" is NOT valid, validation required"
  862.                     $Validation = $false
  863.                     Write-Verbose "Validation response:`n$($($Identifier | Select-Object Identifier,Status,Expires) | Format-Table | Out-String)"
  864.                 }
  865.                 Write-Verbose "Storing values for reference"
  866.                 $DNSObjects += [PSCustomObject]@{
  867.                     DNSName = $DNSRecord
  868.                     IPAddress = $SANIP
  869.                     Status = $SANStatus
  870.                     Match = $SANMatch
  871.                     SAN = $true
  872.                     DNSValid = $Validation
  873.                     Alias = $IdentifierAlias
  874.                 }
  875.             }
  876.         }
  877.     }
  878.     Write-Verbose "SAN Objects:`n$($DNSObjects | Format-Table | Out-String)"
  879. }
  880.  
  881. #endregion SAN
  882.  
  883. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  884.     Write-Verbose "Checking for invalid DNS Records"
  885.     $InvalidDNS = $DNSObjects | Where-Object {$_.Status -eq $false}
  886.     $SkippedDNS = $DNSObjects | Where-Object {$_.IPAddress -eq "Skipped"}
  887.     if ($InvalidDNS) {
  888.         Write-Verbose "Invalid DNS object(s):`n$($InvalidDNS | Select-Object DNSName,Status | Format-Table | Out-String)"
  889.         $DNSObjects[0] | Select-Object DNSName,IPAddress | Format-Table | Out-String | Foreach {Write-Host -ForeGroundColor Green "$_"}
  890.         $InvalidDNS | Select-Object DNSName,IPAddress | Format-Table | Out-String | Foreach {Write-Host -ForeGroundColor Red "$_"}
  891.         throw "ERROR, invalid (not registered?) DNS Record(s) found!"
  892.     } else {
  893.         Write-Verbose "None found, continuing"
  894.     }
  895.     if ($SkippedDNS) {
  896.         Write-Warning "The following DNS object(s) will be skipped:`n$($SkippedDNS | Select-Object DNSName | Format-Table | Out-String)"
  897.     }
  898.     Write-Verbose "Checking non matching DNS Records"
  899.     $DNSNoMatch = $DNSObjects | Where-Object {$_.Match -eq $false}
  900.     if ($DNSNoMatch -and (-not $DisableIPCheck)) {
  901.         Write-Verbose "$($DNSNoMatch | Select-Object DNSName,Match | Format-Table | Out-String)"
  902.         $DNSObjects[0] | Select-Object DNSName,IPAddress | Format-Table | Out-String | Foreach {Write-Host -ForeGroundColor Green "$_"}
  903.         $DNSNoMatch | Select-Object DNSName,IPAddress | Format-Table | Out-String | Foreach {Write-Host -ForeGroundColor Red "$_"}
  904.         throw "ERROR: Non-matching records found, must match to `"$($DNSObjects[0].DNSName)`" ($($DNSObjects[0].IPAddress))"
  905.     } elseif ($DisableIPCheck) {
  906.         Write-Verbose "IP Adressess checking was skipped"
  907.     } else {
  908.         Write-Verbose "All IP Adressess match"
  909.     }
  910. }
  911.  
  912.  
  913. #region ACME DNS Verification
  914.  
  915. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  916.     Write-Verbose "Checking if validation is required"
  917.     $DNSValidationRequired = $DNSObjects | Where-Object {$_.DNSValid -eq $false}
  918.     if ($DNSValidationRequired) {
  919.         Write-Verbose "Validation NOT required"
  920.         $NetScalerActionsRequired = $true
  921.     } else {
  922.         Write-Verbose "Validation required for the following objects:`n$($DNSValidationRequired | Select-Object DNSName | Format-Table | Out-String)"
  923.         $NetScalerActionsRequired = $false
  924.    
  925.     }
  926. }
  927.  
  928. #region NetScaler pre dns
  929.    
  930. if ((-not ($CleanNS)) -and ($NetScalerActionsRequired) -and (-not ($RemoveTestCertificates))) {
  931.     try {
  932.         Write-Verbose "Login to NetScaler and save session to global variable"
  933.         $NSSession = Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential -PassThru
  934.         Write-Verbose "Enable required NetScaler Features, Load Balancer, Responder, Content Switch and SSL"
  935.         $payload = @{"feature"="LB RESPONDER CS SSL"}
  936.         $response = InvokeNSRestApi -Session $NSSession -Method POST -Type nsfeature -Payload $payload -Action enable
  937.         try {
  938.             Write-Verbose "Verifying Content Switch"
  939.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type csvserver -Resource $NSCsVipName
  940.         } catch {
  941.             $ExcepMessage = $_.Exception.Message
  942.             Write-Verbose "Error Details: $ExcepMessage"
  943.             throw "Could not find/read out the content switch `"$NSCsVipName`" not available?"
  944.         } finally {
  945.             if ($ExcepMessage -like "*(404) Not Found*") {
  946.                 Write-Host -ForeGroundColor Red "`nThe Content Switch `"$NSCsVipName`" does NOT exists!"
  947.                 Exit (1)
  948.             } elseif ($ExcepMessage -like "*The remote server returned an error*") {
  949.                 Write-Host -ForeGroundColor Red "`nUnknown error found while checking the Content Switch: `"$NSCsVipName`""
  950.                 Write-Host -ForeGroundColor Red "Error message: `"$ExcepMessage`""
  951.                 Exit (1)
  952.             } elseif (($response.errorcode -eq "0") -and (-not ($response.csvserver.servicetype -eq "HTTP"))) {
  953.                 Write-Host -ForeGroundColor Red "`nThe Content Switch is $($response.csvserver.servicetype) and NOT HTTP"
  954.                 Write-Host -ForeGroundColor Red "Please use a HTTP (Port 80) Content Switch this is required for the validation. Exiting now`n"
  955.                 Exit (1)
  956.             }
  957.         }
  958.         try {
  959.             Write-Verbose "Configuring NetScaler: Check if Load Balancer Service exists"
  960.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type service -Resource $NSSvcName
  961.             Write-Verbose "Yep it exists, continuing"
  962.         } catch {
  963.             Write-Verbose "It does not exist, continuing"
  964.             Write-Verbose "Configuring NetScaler: Create Load Balance Service `"$NSSvcName`""
  965.             $payload = @{"name"="$NSSvcName";"ip"="$NSSvcDestination";"servicetype"="HTTP";"port"="80";"healthmonitor"="NO";}
  966.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type service -Payload $payload -Action add
  967.         }
  968.         try {
  969.             Write-Verbose "Configuring NetScaler: Check if Load Balancer exists"
  970.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type lbvserver -Resource $NSLbName
  971.             Write-Verbose "Yep it exists, continuing"
  972.         } catch {
  973.             Write-Verbose "Nope, continuing"
  974.             Write-Verbose "Configuring NetScaler: Create Load Balance Vip `"$NSLbName`""
  975.             $payload = @{"name"="$NSLbName";"servicetype"="HTTP";"ipv46"="0.0.0.0";"Port"="0";}
  976.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type lbvserver -Payload $payload -Action add
  977.         } finally {
  978.             Write-Verbose "Configuring NetScaler: Bind Service `"$NSSvcName`" to Load Balance Vip `"$NSLbName`""
  979.             Write-Verbose "Checking LB Service binding"
  980.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type lbvserver_service_binding -Resource $NSLbName
  981.             if ($response.lbvserver_service_binding.servicename -eq $NSSvcName) {
  982.                 Write-Verbose "LB Service binding is ok"
  983.                 $SvcConfigure = $True
  984.             } else {
  985.                 $payload = @{"name"="$NSLbName";"servicename"="$NSSvcName";}
  986.                 $response = InvokeNSRestApi -Session $NSSession -Method PUT -Type lbvserver_service_binding -Payload $payload
  987.             }
  988.         }
  989.         try {
  990.             Write-Verbose "Configuring NetScaler: Check if Responder Policy exists"
  991.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderpolicy -Resource $NSRspName
  992.             try {
  993.                 Write-Verbose "Yep it exists, continuing"
  994.                 Write-Verbose "Configuring NetScaler: Change Responder Policy to default values"
  995.                 $payload = @{"name"="$NSRspName";"action"="rsa_letsencrypt";"rule"='HTTP.REQ.URL.CONTAINS(".well-known/acme-challenge/XXXX")';}
  996.                 $response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderpolicy -Payload $payload -Action set
  997.             } catch {
  998.                 throw "Something went wrong with reconfiguring the existing policy `"$NSRspName`", exiting now..."
  999.             }  
  1000.         } catch {
  1001.             $payload = @{"name"="$NSRsaName";"type"="respondwith";"target"='"HTTP/1.0 200 OK" +"\r\n\r\n" + "XXXX"';}
  1002.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderaction -Payload $payload -Action add
  1003.             $payload = @{"name"="$NSRspName";"action"="$NSRsaName";"rule"='HTTP.REQ.URL.CONTAINS(".well-known/acme-challenge/XXXX")';}
  1004.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderpolicy -Payload $payload -Action add
  1005.         } finally {
  1006.             $payload = @{"name"="$NSLbName";"policyname"="$NSRspName";"priority"=100;}
  1007.             $response = InvokeNSRestApi -Session $NSSession -Method PUT -Type lbvserver_responderpolicy_binding -Payload $payload -Resource $NSLbName
  1008.         }
  1009.         try {
  1010.             Write-Verbose "Configuring NetScaler: Check if Content Switch Policy exists"
  1011.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type cspolicy -Resource $NSCspName
  1012.             Write-Verbose "It does, continuing"
  1013.             if (-not($response.cspolicy.rule -eq "HTTP.REQ.URL.CONTAINS(`"well-known/acme-challenge/`")")) {
  1014.                 $payload = @{"policyname"="$NSCspName";"rule"="HTTP.REQ.URL.CONTAINS(`"well-known/acme-challenge/`")";}
  1015.                 $response = InvokeNSRestApi -Session $NSSession -Method PUT -Type cspolicy -Payload $payload
  1016.             }
  1017.         } catch {
  1018.             Write-Verbose "Configuring NetScaler: Create Content Switch Policy"
  1019.             $payload = @{"policyname"="$NSCspName";"rule"='HTTP.REQ.URL.CONTAINS("well-known/acme-challenge/")';}
  1020.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type cspolicy -Payload $payload -Action add
  1021.            
  1022.            
  1023.         }
  1024.         Write-Verbose "Configuring NetScaler: Bind Load Balancer `"$NSLbName`" to Content Switch `"$NSCsVipName`" with prio: $NSCsVipBinding"
  1025.         $payload = @{"name"="$NSCsVipName";"policyname"="$NSCspName";"priority"="$NSCsVipBinding";"targetlbvserver"="$NSLbName";"gotopriorityexpression"="END";}
  1026.         $response = InvokeNSRestApi -Session $NSSession -Method PUT -Type csvserver_cspolicy_binding -Payload $payload
  1027.         Write-Verbose "Finished configuring the NetScaler"
  1028.     } catch {
  1029.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1030.         throw "ERROR: Could not configure the NetScaler, exiting now"
  1031.     }
  1032.     Start-Sleep -Seconds 2
  1033. }
  1034.  
  1035. #endregion NetScaler pre dns
  1036.  
  1037. #region Test NS CS
  1038.  
  1039. if ((-not ($CleanNS)) -and ($NetScalerActionsRequired) -and (-not ($RemoveTestCertificates))) {
  1040.     Write-Host -ForeGroundColor White "Executing some tests, can take a couple of seconds/minutes..."
  1041.     Write-Host -ForeGroundColor Yellow "`r`nPlease note that if a test fails, the script still tries to continue!`r`n"
  1042.     ForEach ($DNSObject in $DNSObjects ) {
  1043.         Write-Host -ForeGroundColor White -NoNewLine " -Checking: => "
  1044.         Write-Host -ForeGroundColor Yellow "`"$($DNSObject.DNSName)`" ($($DNSObject.IPAddress))"
  1045.         $TestURL = "http://$($DNSObject.DNSName)/.well-known/acme-challenge/XXXX"
  1046.         Write-Verbose "Testing if the Content Switch is available on `"$TestURL`" (via internal DNS)"
  1047.         try {
  1048.             Write-Verbose "Retreiving data"
  1049.             $Result = Invoke-WebRequest -URI $TestURL -TimeoutSec 2
  1050.             Write-Verbose "Success, output: $($Result| Out-String)"
  1051.         } catch {
  1052.             $Result = $null
  1053.             Write-Verbose "Internal check failed, error Details: $($_.Exception.Message)"
  1054.         }
  1055.         if ($Result.RawContent -eq "HTTP/1.0 200 OK" + "`r`n`r`n" + "XXXX") {
  1056.             Write-Host -ForeGroundColor White -NoNewLine " -Test (Int. DNS): "
  1057.             Write-Host -ForeGroundColor Green "OK"
  1058.         } else {
  1059.             Write-Host -ForeGroundColor White -NoNewLine " -Test (Int. DNS): "
  1060.             Write-Host -ForeGroundColor Yellow "Not successfull, maybe not resolvable internally?"
  1061.             Write-Verbose "Output: $($Result| Out-String)"
  1062.         }
  1063.        
  1064.         try {
  1065.             Write-Verbose "Checking if Public IP is available for external DNS testing"
  1066.             [ref]$ValidIP = [ipaddress]::None
  1067.             if (([ipaddress]::TryParse("$($DNSObject.IPAddress)",$ValidIP)) -and (-not ($DisableIPCheck))) {
  1068.                 Write-Verbose "Testing if the Content Switch is available on `"$TestURL`" (via external DNS)"
  1069.                 $TestURL = "http://$($DNSObject.IPAddress)/.well-known/acme-challenge/XXXX"
  1070.                 $Headers = @{"Host"="$($DNSObject.DNSName)"}
  1071.                 Write-Verbose "Retreiving data"
  1072.                 $Result = Invoke-WebRequest -URI $TestURL -Headers $Headers -TimeoutSec 2
  1073.                 Write-Verbose "Success, output: $($Result| Out-String)"
  1074.             } else {
  1075.                 Write-Verbose "Public IP is not available for external DNS testing"
  1076.             }
  1077.         } catch {
  1078.             $Result = $null
  1079.             Write-Verbose "External check failed, error Details: $($_.Exception.Message)"
  1080.         }
  1081.         [ref]$ValidIP = [ipaddress]::None
  1082.         if (([ipaddress]::TryParse("$($DNSObject.IPAddress)",$ValidIP)) -and (-not ($DisableIPCheck))) {
  1083.             if ($Result.RawContent -eq "HTTP/1.0 200 OK" + "`r`n`r`n" + "XXXX") {
  1084.                 Write-Host -ForeGroundColor White -NoNewLine " -Test (Ext. DNS): "
  1085.                 Write-Host -ForeGroundColor Green "OK"
  1086.             } else {
  1087.                 Write-Host -ForeGroundColor White -NoNewLine " -Test (Ext. DNS): "
  1088.                 Write-Host -ForeGroundColor Yellow "Not successfull, maybe not resolvable externally?"
  1089.                 Write-Verbose "Output: $($Result| Out-String)"
  1090.             }
  1091.         }
  1092.     }
  1093.     Write-Host -ForeGroundColor White "`r`nFinished the tests, script will continue again."
  1094. }
  1095.  
  1096. #endregion Test NS CS
  1097.  
  1098. #region DNS Check
  1099.  
  1100. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  1101.     Write-Verbose "Check if DNS Records need to be validated"
  1102.     Write-Host -ForeGroundColor White "Verification:"
  1103.     foreach ($DNSObject in $DNSObjects) {
  1104.         $DNSRecord = $DNSObject.DNSName
  1105.         Write-Verbose "Checking validation for `"$DNSRecord`""
  1106.         if ($DNSObject.DNSValid){
  1107.             Write-Host -ForeGroundColor White -NoNewLine " -DNS: "
  1108.             Write-Host -ForeGroundColor Green "`"$DNSRecord`""
  1109.             Write-Host -ForeGroundColor White -NoNewLine " -Status: "
  1110.             Write-Host -ForeGroundColor Green "=> Still valid"
  1111.         } else {
  1112.             Write-Verbose "New validation required, Start verifying"
  1113.             $IdentifierAlias = $DNSObject.Alias
  1114.             try {
  1115.                 try {
  1116.                     $Challenge = ((ACMESharp\Complete-ACMEChallenge -IdentifierRef $IdentifierAlias -ChallengeType http-01 -Handler manual -VaultProfile $VaultName).Challenges | Where-Object { $_.Type -eq "http-01" }).Challenge
  1117.                 } catch {
  1118.                     Write-Verbose "Error Details: $($_.Exception.Message)"
  1119.                     throw "Error while creating the Challenge"
  1120.                 }
  1121.                 Write-Verbose "Configuring NetScaler: Change Responder Policy `"$NSRspName`" to: `"HTTP.REQ.URL.CONTAINS(`"$($Challenge.FilePath)`")`""
  1122.                 $payload = @{"name"="$NSRspName";"action"="$NSRsaName";"rule"="HTTP.REQ.URL.CONTAINS(`"$($Challenge.FilePath)`")";}
  1123.                 $response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderpolicy -Payload $payload -Action set
  1124.                
  1125.                 Write-Verbose "Configuring NetScaler: Change Responder Action `"$NSRsaName`" to return "
  1126.                 Write-Verbose "`"HTTP/1.0 200 OK\r\n\r\n$($Challenge.FileContent)`""
  1127.                 $payload = @{"name"="$NSRsaName";"target"="`"HTTP/1.0 200 OK\r\n\r\n$($Challenge.FileContent)`"";}
  1128.                 $response = InvokeNSRestApi -Session $NSSession -Method POST -Type responderaction -Payload $payload -Action set
  1129.                
  1130.                 Write-Verbose "Wait 1 second"
  1131.                 Start-Sleep -Seconds 1
  1132.                 Write-Verbose "Start Submitting Challenge"
  1133.                 try {
  1134.                     $SubmittedChallenge = ACMESharp\Submit-ACMEChallenge -IdentifierRef $IdentifierAlias -ChallengeType http-01 -VaultProfile $VaultName
  1135.                 } catch {
  1136.                     Write-Verbose "Error Details: $($_.Exception.Message)"
  1137.                     throw "Error while submitting the Challenge"
  1138.                 }
  1139.                 Write-Verbose "Retreiving validation status"
  1140.                 try {
  1141.                     $UpdateIdentifier = (ACMESharp\Update-ACMEIdentifier -IdentifierRef $IdentifierAlias -ChallengeType http-01 -VaultProfile $VaultName).Challenges | Where-Object {$_.Type -eq "http-01"}
  1142.                 } catch {
  1143.                     Write-Verbose "Error Details: $($_.Exception.Message)"
  1144.                     throw "Error while retreiving validation status"
  1145.                 }
  1146.                 $i = 0
  1147.                 Write-Host -ForeGroundColor White -NoNewLine " -DNS: "
  1148.                 Write-Host -ForeGroundColor Green "`"$DNSRecord`""
  1149.                 Write-Host -ForeGroundColor White -NoNewLine " -Status: "
  1150.                 while(-NOT ($UpdateIdentifier.Status.ToLower() -eq "valid")) {
  1151.                     Write-Host -ForeGroundColor Yellow -NoNewLine "="
  1152.                     $i++
  1153.                     Write-Verbose "($($i.ToString())) $DNSRecord is not (yet) validated, Wait 2 second"
  1154.                     Start-Sleep -Seconds 2
  1155.                     Write-Verbose "Retreiving validation status"
  1156.                     try {
  1157.                         $UpdateIdentifier = (ACMESharp\Update-ACMEIdentifier -IdentifierRef $IdentifierAlias -ChallengeType http-01 -VaultProfile $VaultName).Challenges | Where-Object {$_.Type -eq "http-01"}
  1158.                     } catch {
  1159.                         Write-Verbose "Error Details: $($_.Exception.Message)"
  1160.                         throw "Error while retreiving validation status"
  1161.                     }
  1162.                     if (($i -ge 60) -or ($UpdateIdentifier.Status.ToLower() -eq "invalid")) {break}
  1163.                 }
  1164.                 switch ($UpdateIdentifier.Status.ToLower()) {
  1165.                     "pending" {
  1166.                         Write-Host -ForeGroundColor Red "ERROR"
  1167.                         throw "It took to long for the validation ($DNSRecord) to complete, exiting now."
  1168.                     }
  1169.                     "invalid" {
  1170.                         Write-Host -ForeGroundColor Red "ERROR"
  1171.                         throw "Validation for `"$DNSRecord`" is invalid! Exiting now."
  1172.                     }
  1173.                     "valid" {
  1174.                         Write-Host -ForeGroundColor Green "> validated successfully"
  1175.                     }
  1176.                     default {
  1177.                         Write-Host -ForeGroundColor Red "ERROR"
  1178.                         throw "Unexpected status for `"$DNSRecord`" is `"$($UpdateIdentifier.Status)`", exiting now."
  1179.                     }
  1180.                 }
  1181.             } catch {
  1182.                 Write-Verbose "Error Details: $($_.Exception.Message)"
  1183.                 throw "Error while verifying `"$DNSRecord`", exiting now"
  1184.             }
  1185.         }
  1186.     }
  1187.     "`r`n"
  1188. }
  1189.  
  1190. #endregion DNS Check
  1191.  
  1192. #region NetScaler post DNS
  1193.  
  1194. if (($NetScalerActionsRequired) -or ($CleanNS) -and (-not ($RemoveTestCertificates))) {
  1195.     Write-Verbose "Login to NetScaler and save session to global variable"
  1196.     Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential
  1197.     try {
  1198.         Write-Verbose "Checking if a binding exists for `"$NSCspName`""
  1199.         $Filters = @{"policyname"="$NSCspName"}
  1200.         $response = InvokeNSRestApi -Session $NSSession -Method GET -Type csvserver_cspolicy_binding -Resource "$NSCsVipName" -Filters $Filters
  1201.         if ($response.csvserver_cspolicy_binding.policyname -eq $NSCspName) {
  1202.             Write-Verbose "Removing Content Switch Loadbalance Binding"
  1203.             $Arguments = @{"name"="$NSCsVipName";"policyname"="$NSCspName";"priority"="$NSCsVipBinding";}
  1204.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type csvserver_cspolicy_binding -Arguments $Arguments
  1205.         } else {
  1206.             Write-Verbose "No binding found"
  1207.         }
  1208.     } catch {
  1209.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1210.         Write-Warning "Not able to remove the Content Switch Loadbalance Binding"
  1211.     }
  1212.     try {
  1213.         Write-Verbose "Checking if Content Switch Policy `"$NSCspName`" exists"
  1214.         try {
  1215.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type cspolicy -Resource "$NSCspName"
  1216.         } catch{}
  1217.         if ($response.cspolicy.policyname -eq $NSCspName) {
  1218.             Write-Verbose "Removing Content Switch Policy"
  1219.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type cspolicy -Resource "$NSCspName"
  1220.         } else {
  1221.             Write-Verbose "Content Switch Policy not found"
  1222.         }
  1223.     } catch {
  1224.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1225.         Write-Warning "Not able to remove the Content Switch Policy"
  1226.     }
  1227.     try {
  1228.         Write-Verbose "Checking if Load Balance vServer `"$NSLbName`" exists"
  1229.         try {
  1230.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type lbvserver -Resource "$NSLbName"
  1231.         } catch{}
  1232.         if ($response.lbvserver.name -eq $NSLbName) {
  1233.             Write-Verbose "Removing the Load Balance vServer"
  1234.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type lbvserver -Resource "$NSLbName"
  1235.         } else {
  1236.             Write-Verbose "Load Balance vServer not found"
  1237.         }
  1238.     } catch {
  1239.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1240.         Write-Warning "Not able to remove the Load Balance vserver"
  1241.     }
  1242.     try {
  1243.         Write-Verbose "Checking if Service `"$NSSvcName`" exists"
  1244.         try {
  1245.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type service -Resource "$NSSvcName"
  1246.         } catch{}
  1247.         if ($response.service.name -eq $NSSvcName) {
  1248.             Write-Verbose "Removing Service `"$NSSvcName`""
  1249.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type service -Resource "$NSSvcName"
  1250.         } else {
  1251.             Write-Verbose "Service not found"
  1252.         }
  1253.     } catch {
  1254.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1255.         Write-Warning "Not able to remove the Service"
  1256.     }
  1257.     try {
  1258.         Write-Verbose "Checking if server `"$NSSvcDestination`" exists"
  1259.         try {
  1260.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type server -Resource "$NSSvcDestination"
  1261.         } catch{}
  1262.         if ($response.server.name -eq $NSSvcDestination) {
  1263.             Write-Verbose "Removing Server `"$NSSvcDestination`""
  1264.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type server -Resource "$NSSvcDestination"
  1265.         } else {
  1266.             Write-Verbose "Server not found"
  1267.         }
  1268.     } catch {
  1269.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1270.         Write-Warning "Not able to remove the Server"
  1271.     }
  1272.     try {
  1273.         Write-Verbose "Checking if Responder Policy `"$NSRspName`" exists"
  1274.         try {
  1275.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderpolicy -Resource "$NSRspName"
  1276.         } catch{}
  1277.         if ($response.responderpolicy.name -eq $NSRspName) {
  1278.             Write-Verbose "Removing Responder Policy `"$NSRspName`""
  1279.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type responderpolicy -Resource "$NSRspName"
  1280.         } else {
  1281.             Write-Verbose "Responder Policy not found"
  1282.         }
  1283.     } catch {
  1284.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1285.         Write-Warning "Not able to remove the Responder Policy"
  1286.     }
  1287.     try {
  1288.         Write-Verbose "Checking if Responder Action `"$NSRsaName`" exists"
  1289.         try {
  1290.             $response = InvokeNSRestApi -Session $NSSession -Method GET -Type responderaction -Resource "$NSRsaName"
  1291.         } catch{}
  1292.         if ($response.responderaction.name -eq $NSRsaName) {
  1293.             Write-Verbose "Removing Responder Action `"$NSRsaName`""
  1294.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type responderaction -Resource $NSRsaName
  1295.         } else {
  1296.             Write-Verbose "Responder Action not found"
  1297.         }
  1298.     } catch {
  1299.         Write-Verbose "Error Details: $($_.Exception.Message)"
  1300.         Write-Warning "Not able to remove the Responder Action"
  1301.     }
  1302. }  
  1303.  
  1304. #endregion NetScaler Post DNS
  1305.  
  1306. #endregion ACME DNS Verification
  1307.  
  1308. #endregion DNS
  1309.  
  1310. #region Certificates
  1311.    
  1312. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  1313.     $SANs = $DNSObjects | Where-Object {$_.SAN -eq $true}
  1314.     $IdentifierAlias = $DNSObjects[0].Alias
  1315.     try {
  1316.         $CertificateAlias = "CRT-SAN-$SessionDateTime-$CN"
  1317.         if ($SANs) {
  1318.             Write-Verbose "Get certificate with SANs"
  1319.             Write-Verbose "Domain:`n$($DNSObjects[0] | Select-Object DNSName,Alias | Format-Table | Out-String)"
  1320.             Write-Verbose "Subject Alternative Names:`n$(@($SANs) | Select-Object DNSName,Alias | Format-Table | Out-String)"
  1321.             $NewCertificate = ACMESharp\New-ACMECertificate $IdentifierAlias `
  1322.                 -AlternativeIdentifierRefs @($SANs.Alias) `
  1323.                 -Alias $CertificateAlias `
  1324.                 -Generate `
  1325.                 -VaultProfile $VaultName
  1326.         } else {
  1327.             Write-Verbose "Get single DNS Name certificate"
  1328.             Write-Verbose "Domain:`n$($($DNSObjects[0].DNSName) | fl * | Out-String)"
  1329.             $NewCertificate = ACMESharp\New-ACMECertificate $IdentifierAlias `
  1330.                 -Alias $CertificateAlias `
  1331.                 -Generate `
  1332.                 -VaultProfile $VaultName
  1333.         }
  1334.         Write-Verbose "Submit Certificate request"
  1335.         $SubmittedCertificate = ACMESharp\Submit-ACMECertificate $CertificateAlias -VaultProfile $VaultName
  1336.     } catch {
  1337.         throw "ERROR. Certificate completion failed, details: $($_.Exception.Message | Out-String)"
  1338.     }
  1339.     $i = 0
  1340.     while (-not (ACMESharp\Update-ACMECertificate $CertificateAlias -VaultProfile $VaultName | select IssuerSerialNumber)) {
  1341.         $i++
  1342.         $imax = 120
  1343.         if ($i -ge $imax) {
  1344.             throw "Error: Retreiving certificate failed, took to long to complete"
  1345.         }
  1346.         Write-Host "Will continue $(($imax-$i)*2) more seconds for the certificate to come available..."
  1347.         Start-Sleep -seconds 2
  1348.     }
  1349.    
  1350.     $CertificateDirectory = Join-Path -Path $CertDir -ChildPath $CertificateAlias
  1351.     Write-Verbose "Create directory `"$CertificateDirectory`" for storing the new certificates"
  1352.     $output = New-Item $CertificateDirectory -ItemType directory -force
  1353.     if (Test-Path $CertificateDirectory){
  1354.         if ($Production){
  1355.             $CertificateName = "$($ScriptDateTime.ToString("yyyyMMdd"))-$cn"
  1356.             Write-Verbose "Writing production certificates"
  1357.             $IntermediateCACertKeyName = "Lets Encrypt Authority X3-int"
  1358.             $IntermediateCAFileName = "$($IntermediateCACertKeyName).crt"
  1359.             $IntermediateCAFullPath = Join-Path -Path $CertificateDirectory -ChildPath $IntermediateCAFileName
  1360.             $IntermediateCASerial = "0a0141420000015385736a0b85eca708"
  1361.         } else {
  1362.             $CertificateName = "$($ScriptDateTime.ToString("yyyyMMddHHmm"))-$cn"
  1363.             Write-Verbose "Writing test/staging certificates"
  1364.             $IntermediateCACertKeyName = "Fake LE Intermediate X1-int"
  1365.             $IntermediateCAFileName = "$($IntermediateCACertKeyName).crt"
  1366.             $IntermediateCAFullPath = Join-Path -Path $CertificateDirectory -ChildPath $IntermediateCAFileName
  1367.             $IntermediateCASerial = "8be12a0e5944ed3c546431f097614fe5"
  1368.         }
  1369.         Write-Verbose "Intermediate: `"$IntermediateCAFileName`""
  1370.         ACMESharp\Get-ACMECertificate $CertificateAlias -ExportIssuerPEM $IntermediateCAFullPath -VaultProfile $VaultName | Out-Null
  1371.        
  1372.         if ($Production){
  1373.             $CertificateName = "$CertificateName"
  1374.             $CertificateFileName = "$CertificateAlias.crt"
  1375.             $CertificateKeyFileName = "$CertificateAlias.crt.key"
  1376.             $CertificatePfxFileName = "$CertificateAlias.pfx"
  1377.         } else {
  1378.             $CertificateName = "TST-$CertificateName"
  1379.             $CertificateFileName = "TST-$CertificateAlias.crt"
  1380.             $CertificateKeyFileName = "TST-$CertificateAlias.crt.key"
  1381.             $CertificatePfxFileName = "TST-$CertificateAlias.pfx"
  1382.         }
  1383.         $CertificateFullPath = Join-Path -Path $CertificateDirectory -ChildPath $CertificateFileName
  1384.         Write-Verbose "Certificate: `"$CertificateFileName`""
  1385.         ACMESharp\Get-ACMECertificate $CertificateAlias -ExportCertificatePEM $CertificateFullPath -VaultProfile $VaultName | Out-Null
  1386.         $CertificateKeyFullPath = Join-Path -Path $CertificateDirectory -ChildPath $CertificateKeyFileName
  1387.         Write-Verbose "Key: `"$CertificateKeyFileName`""
  1388.         ACMESharp\Get-ACMECertificate $CertificateAlias -ExportKeyPEM $CertificateKeyFullPath -VaultProfile $VaultName | Out-Null
  1389.         $CertificatePfxFullPath = Join-Path -Path $CertificateDirectory -ChildPath $CertificatePfxFileName
  1390.         if ($PfxPassword){
  1391.             Write-Verbose "PFX: `"$CertificatePfxFileName`""
  1392.             ACMESharp\Get-ACMECertificate $CertificateAlias -ExportPkcs12 "$CertificatePfxFullPath" -CertificatePassword "$PfxPassword" -VaultProfile $VaultName | Out-Null
  1393.         } else {
  1394.             try {
  1395.                 $length=15
  1396.                 $Assembly = Add-Type -AssemblyName System.Web
  1397.                 $PfxPassword = [System.Web.Security.Membership]::GeneratePassword($length,2)
  1398.                 Write-Warning "No Password was specified, so a random password was generated!"
  1399.                
  1400.                 Write-Host -ForeGroundColor Yellow "`n***********************"
  1401.                 Write-Host -ForeGroundColor Yellow "*   PFX Password:     *"
  1402.                 Write-Host -ForeGroundColor Yellow "*                     *"
  1403.                 Write-Host -ForeGroundColor Yellow "*   $PfxPassword   *"
  1404.                 Write-Host -ForeGroundColor Yellow "*                     *"
  1405.                 Write-Host -ForeGroundColor Yellow "***********************`n"
  1406.                 ACMESharp\Get-ACMECertificate $CertificateAlias -ExportPkcs12 "$CertificatePfxFullPath" -CertificatePassword "$PfxPassword" -VaultProfile $VaultName | Out-Null
  1407.             } catch {
  1408.                 Write-Verbose "An error occured while generating a Password."
  1409.             }
  1410.         }
  1411.     }
  1412. }
  1413.  
  1414. #endregion Certificates
  1415.  
  1416. #region Upload certificates to NetScaler
  1417.  
  1418. if ((-not ($CleanNS)) -and (-not ($RemoveTestCertificates))) {
  1419.     try {
  1420.         Write-Verbose "Retreiving existing certificates"
  1421.         $CertDetails = InvokeNSRestApi -Session $NSSession -Method GET -Type sslcertkey
  1422.         Write-Verbose "Checking if IntermediateCA `"$IntermediateCACertKeyName`" already exists"
  1423.         if ($ns10x) {
  1424.             $IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.cert -match $IntermediateCAFileName}
  1425.         } else {
  1426.             $IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.serial -eq $IntermediateCASerial}
  1427.         }
  1428.         if (-not ($IntermediateCADetails)) {
  1429.             Write-Verbose "Uploading `"$IntermediateCAFileName`" to the NetScaler"
  1430.             $IntermediateCABase64 = [System.Convert]::ToBase64String($(Get-Content $IntermediateCAFullPath -Encoding "Byte"))
  1431.             $payload = @{"filename"="$IntermediateCAFileName";"filecontent"="$IntermediateCABase64";"filelocation"="/nsconfig/ssl/";"fileencoding"="BASE64";}
  1432.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type systemfile -Payload $payload
  1433.             Write-Verbose "Succeeded"
  1434.             Write-Verbose "Add the certificate to the NetScaler config"
  1435.             $payload = @{"certkey"="$IntermediateCACertKeyName";"cert"="/nsconfig/ssl/$($IntermediateCAFileName)";}
  1436.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload
  1437.             Write-Verbose "Succeeded"
  1438.         } else {
  1439.             $IntermediateCACertKeyName = $IntermediateCADetails.certkey
  1440.             Write-Verbose "Saving existing name `"$IntermediateCACertKeyName`" for later use"
  1441.         }
  1442.         $ExistingCertificateDetails = $CertDetails.sslcertkey | Where-Object {$_.certkey -eq $NSCertNameToUpdate}
  1443.         if (($NSCertNameToUpdate) -and ($ExistingCertificateDetails)) {
  1444.             $CertificateCertKeyName = $($ExistingCertificateDetails.certkey)
  1445.             Write-Verbose "Existing certificate `"$($ExistingCertificateDetails.certkey)`" found on the netscaler, start updating"
  1446.             try {
  1447.                 Write-Verbose "Unlinking certificate"
  1448.                 $payload = @{"certkey"="$($ExistingCertificateDetails.certkey)";}
  1449.                 $response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action unlink
  1450.                
  1451.             } catch {
  1452.                 Write-Verbose "Certificate was not linked"
  1453.             }
  1454.             $NSUpdating = $true
  1455.         } else {
  1456.             Write-Verbose " `"$CertificateName`" is $($CertificateName.Length) long"
  1457.             if ($CertificateName.Length -gt 31) {
  1458.                 Write-Verbose "Name is to long, only using the first 31 characters"
  1459.                 $CertificateCertKeyName = $CertificateName.subString(0,31)
  1460.             } else {
  1461.                 Write-Verbose "CertkeyName is not too long, continuing"
  1462.                 $CertificateCertKeyName = $CertificateName
  1463.             }
  1464.             $ExistingCertificateDetails = $CertDetails.sslcertkey | Where-Object {$_.certkey -eq $CertificateCertKeyName}
  1465.             if ($ExistingCertificateDetails) {
  1466.                 Write-Warning "Certificate `"$CertificateCertKeyName`" already exists, please update manually"
  1467.                 exit(1)
  1468.             }
  1469.             $NSUpdating = $false
  1470.         }
  1471.         $CertificateCrtBase64 = [System.Convert]::ToBase64String($(Get-Content $CertificateFullPath -Encoding "Byte"))
  1472.         $CertificateKeyBase64 = [System.Convert]::ToBase64String($(Get-Content $CertificateKeyFullPath -Encoding "Byte"))
  1473.         Write-Verbose "Uploading the certificate"
  1474.         $payload = @{"filename"="$CertificateFileName";"filecontent"="$CertificateCrtBase64";"filelocation"="/nsconfig/ssl/";"fileencoding"="BASE64";}
  1475.         $response = InvokeNSRestApi -Session $NSSession -Method POST -Type systemfile -Payload $payload
  1476.        
  1477.         Write-Verbose "Uploading the certificate key"
  1478.         $payload = @{"filename"="$CertificateKeyFileName";"filecontent"="$CertificateKeyBase64";"filelocation"="/nsconfig/ssl/";"fileencoding"="BASE64";}
  1479.         $response = InvokeNSRestApi -Session $NSSession -Method POST -Type systemfile -Payload $payload
  1480.         Write-Verbose "Finished uploading"
  1481.         if ($NSUpdating) {
  1482.             Write-Verbose "Update the certificate and key to the NetScaler config"
  1483.             $payload = @{"certkey"="$CertificateCertKeyName";"cert"="/nsconfig/ssl/$($CertificateFileName)";"key"="/nsconfig/ssl/$($CertificateKeyFileName)"}
  1484.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action update
  1485.             Write-Verbose "Succeeded"
  1486.    
  1487.         } else {
  1488.             Write-Verbose "Add the certificate and key to the NetScaler config"
  1489.             $payload = @{"certkey"="$CertificateCertKeyName";"cert"="/nsconfig/ssl/$($CertificateFileName)";"key"="/nsconfig/ssl/$($CertificateKeyFileName)"}
  1490.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload
  1491.             Write-Verbose "Succeeded"
  1492.         }
  1493.         Write-Verbose "Link `"$CertificateCertKeyName`" to `"$IntermediateCACertKeyName`""
  1494.         $payload = @{"certkey"="$CertificateCertKeyName";"linkcertkeyname"="$IntermediateCACertKeyName";}
  1495.         $response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action link
  1496.         Write-Verbose "Succeeded"
  1497.         if ($SaveNSConfig) {
  1498.             Write-Verbose "Saving NetScaler configuration"
  1499.             InvokeNSRestApi -Session $NSSession -Method POST -Type nsconfig -Action save
  1500.         }
  1501.         ""
  1502.         Write-Host -ForeGroundColor Green "Finished with the certificates!"
  1503.         if (-not $Production){
  1504.             Write-Host -ForeGroundColor Green "You are now ready for the Production version!"
  1505.             Write-Host -ForeGroundColor Green "Add the `"-Production`" parameter and rerun the same script."
  1506.         }
  1507.     } catch {
  1508.         throw "ERROR. Certificate completion failed, details: $($_.Exception.Message | Out-String)"
  1509.     }
  1510. }
  1511.  
  1512. #endregion Upload certificates to NetScaler
  1513.  
  1514. #region Remove Test Certificates
  1515.  
  1516. if ((-not ($CleanNS)) -and $RemoveTestCertificates) {
  1517.     Write-Verbose "Login to NetScaler and save session to global variable"
  1518.     $NSSession = Connect-NetScaler -ManagementURL $NSManagementURL -Credential $NSCredential -PassThru
  1519.     $IntermediateCACertKeyName = "Fake LE Intermediate X1"
  1520.     $IntermediateCASerial = "8be12a0e5944ed3c546431f097614fe5"
  1521.     Write-Verbose "Retreiving existing certificates"
  1522.     $CertDetails = InvokeNSRestApi -Session $NSSession -Method GET -Type sslcertkey
  1523.     Write-Verbose "Checking if IntermediateCA `"$IntermediateCACertKeyName`" already exists"
  1524.     if ($ns10x) {
  1525.         $IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.cert -match $IntermediateCAFileName}
  1526.     } else {
  1527.         $IntermediateCADetails = $CertDetails.sslcertkey | Where-Object {$_.serial -eq $IntermediateCASerial}
  1528.     }
  1529.     $LinkedCertificates = $CertDetails.sslcertkey | Where-Object {$_.linkcertkeyname -eq $IntermediateCADetails.certkey}
  1530.     Write-Verbose "The following certificates were found:`n$($LinkedCertificates | Select-Object certkey,linkcertkeyname,serial | Format-Table | Out-String)"
  1531.     ForEach ($LinkedCertificate in $LinkedCertificates) {
  1532.         $payload = @{"certkey"="$($LinkedCertificate.certkey)";}
  1533.         try {
  1534.             $response = InvokeNSRestApi -Session $NSSession -Method POST -Type sslcertkey -Payload $payload -Action unlink
  1535.             Write-Host -NoNewLine "Unlinked: "
  1536.             Write-Host -ForeGroundColor Green "$($LinkedCertificate.certkey)"
  1537.         } catch {
  1538.             Write-Warning "Could not unlink certkey `"$($LinkedCertificate.certkey)`""
  1539.         }
  1540.     }
  1541.     $FakeCerts = $CertDetails.sslcertkey | Where-Object {$_.issuer -match $IntermediateCACertKeyName}
  1542.     ForEach ($FakeCert in $FakeCerts) {
  1543.         try {
  1544.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type sslcertkey -Resource $($FakeCert.certkey)
  1545.             Write-Host -NoNewLine "Removing: "
  1546.             Write-Host -ForeGroundColor Green "$($FakeCert.certkey)"
  1547.         } catch {
  1548.             Write-Warning "Could not delete certkey `"$($FakeCert.certkey)`" from the netscaler"
  1549.         }
  1550.         $CertFilePath = (split-path $($FakeCert.cert) -Parent).Replace("\","/")
  1551.         $CertFileName = split-path $($FakeCert.cert) -Leaf
  1552.         Write-Host -NoNewLine "Deleted: "
  1553.         Write-Host -ForeGroundColor Green "$(Join-Path -Path $CertFilePath -ChildPath $CertFileName)"
  1554.         $KeyFilePath = (split-path $($FakeCert.key) -Parent).Replace("\","/")
  1555.         $KeyFileName = split-path $($FakeCert.key) -Leaf
  1556.         Write-Host -NoNewLine "Deleted: "
  1557.         Write-Host -ForeGroundColor Green "$(Join-Path -Path $KeyFilePath -ChildPath $KeyFileName)"
  1558.         $Arguments = @{"filelocation"="$CertFilePath";}
  1559.         try {
  1560.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type systemfile -Resource $CertFileName -Arguments $Arguments
  1561.         } catch {
  1562.             Write-Warning "Could not delete file: `"$CertFileName`" from location: `"$CertFilePath`""
  1563.         }
  1564.         $Arguments = @{"filelocation"="$KeyFilePath";}
  1565.         try {
  1566.             $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type systemfile -Resource $KeyFileName -Arguments $Arguments
  1567.         } catch {
  1568.             Write-Warning "Could not delete file: `"$KeyFileName`" from location: `"$KeyFilePath`""
  1569.         }
  1570.        
  1571.     }
  1572.     $Arguments = @{"filelocation"="/nsconfig/ssl";}
  1573.     $CertFiles = InvokeNSRestApi -Session $NSSession -Method Get -Type systemfile -Arguments $Arguments
  1574.     $CertFilesToRemove = $response.systemfile | Where-Object {$_.filename -match "TST-"}
  1575.     ForEach ($CertFileToRemove in $CertFilesToRemove) {
  1576.         $Arguments = @{"filelocation"="$($CertFileToRemove.filelocation)";}
  1577.         try {
  1578.         $response = InvokeNSRestApi -Session $NSSession -Method DELETE -Type systemfile -Resource $($CertFileToRemove.filename) -Arguments $Arguments
  1579.         } catch {
  1580.             Write-Warning "Could not delete file: `"$($CertFileToRemove.filename)`" from location: `"$($CertFileToRemove.filelocation)`""
  1581.         }
  1582.     }
  1583. }
  1584.  
  1585. #endregion Remove Test Certificates
Add Comment
Please, Sign In to add comment