DSCResources/ArcGIS_Server_TLS/ArcGIS_Server_TLS.psm1
<#
.SYNOPSIS Creates a SelfSigned Certificate or Installs a SSL Certificated Provided and Configures it with Server .PARAMETER ServerHostName Optional Host Name or IP of the Machine on which the Server has been installed and is to be configured. .PARAMETER Ensure Take the values Present or Absent. - "Present" ensures the certificate is installed and configured with the Server. - "Absent" ensures the certificate configured with the Server is uninstalled and deleted(Not Implemented). .PARAMETER SiteName Site Name or Default Context of Server .PARAMETER ServerRole Site Name or Default Context of Server .PARAMETER SiteAdministrator A MSFT_Credential Object - Primary Site Administrator. .PARAMETER CertificateFileLocation Certificate Path from where to fetch the certificate to be installed. .PARAMETER CertificatePassword Sercret Certificate Password or Key. .PARAMETER CName CName with which the Certificate will be associated. .PARAMETER PortalEndPoint #Not sure - Adds a Host Mapping of Portal Machine and associates it with the certificate being Installed. .PARAMETER EnableSSL #Not Sure - Boolean to indicate to whether to enable SSL on Server Site .PARAMETER ImportOnly #Not Sure - Boolean to indicate to if the Certificate is be created or Imported .PARAMETER SslRootOrIntermediate Takes a JSON string list of all the root or intermediate certificates to import #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $false)] [System.String] $ServerHostName, [parameter(Mandatory = $true)] [System.String] $SiteName ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false $null # TODO } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $false)] [System.String] $ServerHostName, [parameter(Mandatory = $true)] [System.String] $SiteName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $CertificateFileLocation, [System.Management.Automation.PSCredential] $CertificatePassword, [System.String] $CName, [System.String] $PortalEndPoint, [System.Boolean] $EnableSSL, [System.Boolean] $ImportOnly, [System.String] $SslRootOrIntermediate, [System.String] $ServerType ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false if($CertificateFileLocation -and -not(Test-Path $CertificateFileLocation)){ throw "Certificate File '$CertificateFileLocation' is not found or inaccessible" } $ServiceName = "ArcGIS Server" $SitePort = 6443 if($ServerType -ieq "NotebookServer"){ $ServiceName = "ArcGIS Notebook Server" $SitePort = 11443 }elseif($ServerType -ieq "MissionServer"){ $ServiceName = "ArcGIS Mission Server" $SitePort = 20443 } $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $InstallDir = (Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir $RestartRequired = $false $FQDN = if($ServerHostName){ Get-FQDN $ServerHostName }else{ Get-FQDN $env:COMPUTERNAME } $ServerUrl = "https://$($FQDN):$($SitePort)" Wait-ForUrl -Url "$($ServerUrl)/$SiteName/admin/" $Referer = $ServerUrl $token = Get-ServerToken -ServerEndPoint $ServerURL -ServerSiteName $SiteName -Credential $SiteAdministrator -Referer $Referer if(-not($token.token)){ throw "Unable to retrieve token for Site Administrator" } $Info = Invoke-ArcGISWebRequest -Url ($ServerUrl.TrimEnd('/') + "/arcgis/rest/info") -HttpFormParameters @{f = 'json';} -Referer $Referer -Verbose -HttpMethod 'GET' $ServerMinorVersion = "$($Info.fullVersion)".Split('.')[1] if($EnableSSL -and -not($ServerType -ieq "NotebookServer" -or $ServerType -ieq "MissionServer")) { # Get the current security configuration Write-Verbose 'Getting security config for site' $secConfig = Get-SecurityConfig -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -Referer $Referer if(-not($secConfig.sslEnabled)) { # Enable HTTPS on the securty config Write-Verbose 'Enabling HTTPS on security config for site' $enableResponse = Invoke-EnableHTTPSOnSecurityConfig -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -SecurityConfig $secConfig -Referer $Referer # Changing the protocol will cause the web server to restart. Write-Verbose "Waiting for Url '$ServerUrl/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerUrl/$SiteName/admin/" -SleepTimeInSeconds 15 -MaxWaitTimeInSeconds 90 } } if($CName) { if($PortalEndPoint -and ($PortalEndPoint -as [ipaddress])) { Write-Verbose "Adding Host mapping for $PortalEndPoint" Add-HostMapping -hostname $PortalEndPoint -ipaddress $PortalEndPoint } elseif($CName -as [ipaddress]) { Write-Verbose "Adding Host mapping for $CName" Add-HostMapping -hostname $CName -ipaddress $CName } # Get the machine name in the site $MachineName = $FQDN $allMachines = Get-Machines -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -Referer $Referer if(-not($allMachines.machines | Where-Object { $_.machineName -ieq $MachineName })) { $MachineName = $env:COMPUTERNAME if(-not($allMachines.machines | Where-Object { $_.machineName -ieq $MachineName })){ throw "Not able to find machine in site with either hostname $MachineName or fully qualified domain name $FQDN" } } # Get the machine details Write-Verbose "Get Machine details for [$MachineName]" $machine = Get-MachineDetails -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -MachineName $MachineName -Referer $Referer $NewCertIssuer = $null $NewCertThumbprint = $null if($CertificateFileLocation -and ($null -ne $CertificatePassword)) { $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($CertificateFileLocation,$CertificatePassword.GetNetworkCredential().Password,'DefaultKeySet') $NewCertIssuer = $cert.Issuer $NewCertThumbprint = $cert.Thumbprint Write-Verbose "Issuer for the supplied certificate is $NewCertIssuer" Write-Verbose "Thumbprint for the supplied certificate is $NewCertThumbprint" } $CertForMachine = Get-SSLCertificateForMachine -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName -SSLCertName $CName.ToLower() -Version $ServerMinorVersion $ExistingCertIssuer = $CertForMachine.Issuer $ExistingCertThumprint = $CertForMachine.Thumprint Write-Verbose "Existing Cert Issuer $ExistingCertIssuer" if((($ServerMinorVersion -ge 6) -and ( ($null -eq $ExistingCertThumprint) -or ($NewCertThumbprint -and ($ExistingCertThumprint -ine $NewCertThumbprint)))) -or (($ServerMinorVersion -lt 6) -and (($null -eq $ExistingCertIssuer) -or ($NewCertIssuer -and ($ExistingCertIssuer -ine $NewCertIssuer))))){ if($CertForMachine) { Write-Verbose "Certificate with CName $CName already exists for machine $MachineName. Deleting it" try { $res = Invoke-DeleteSSLCertForMachine -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName -SSLCertName $CName.ToLower() Write-Verbose "Delete Certificate Operation result - $($res | ConvertTo-Json)" } catch { Write-Verbose "[WARNING] Error deleting SSL Cert with CName $CName. Error:- $_" } }else{ Write-Verbose "Certificate for CName $CName not found" } if($CertificateFileLocation -and ($null -ne $CertificatePassword)) { # Import the Supplied Certificate Write-Verbose "Importing Supplied Certificate with Alias $CName" Import-ExistingCertificate -ServerUrl $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer ` -MachineName $MachineName -CertAlias $CName -CertificatePassword $CertificatePassword ` -CertificateFilePath $CertificateFileLocation -ServerType $ServerType }else { # Generate a Self signed cert Write-Verbose 'Generating SelfSignedCertificate' Invoke-GenerateSelfSignedCertificate -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -MachineName $MachineName ` -CertAlias $CName -CertCommonName $CName -CertOrganization $CName -Referer $Referer } if($ImportOnly) { Write-Verbose "Import Only Scenario. No need to update certificate alias for Machine" }else { # Update the SSL Cert for machine Write-Verbose "Updating SSL Certificate for machine [$MachineName]" $machine.webServerCertificateAlias = $CName Update-SSLCertificate -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -MachineName $MachineName -MachineProperties $machine -Referer $Referer -Version $ServerMinorVersion Start-Sleep -Seconds 30 } } # Adding an SSL Certificate will cause the web server to restart. Wait for it to come back Write-Verbose "Waiting for Url '$ServerUrl/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerUrl/$SiteName/admin" -SleepTimeInSeconds 15 -MaxWaitTimeInSeconds 150 -HttpMethod 'GET' -Verbose if(-not($ImportOnly)) { Write-Verbose "Desired CName:- $CName Check if machine is using this" $machineDetails = Get-MachineDetails -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName Write-Verbose "WebCertificateAlias :- $($machineDetails.webServerCertificateAlias)" if($CName -ine $machineDetails.webServerCertificateAlias) { $machineDetails.webServerCertificateAlias = $CName Write-Verbose "Updating SSL Certificate to have Desired CName:- $CName" Update-SSLCertificate -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -MachineName $MachineName -Referer $Referer -MachineProperties $machineDetails -Version $ServerMinorVersion Start-Sleep -Seconds 30 # Updating an SSL Certificate will cause the web server to restart. Write-Verbose "Waiting for Url '$ServerURL/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerUrl/$SiteName/admin" -SleepTimeInSeconds 15 -MaxWaitTimeInSeconds 150 -HttpMethod 'GET' -Verbose } }else { Write-Verbose "Import Only Scenario. No need to update certificate alias for Machine" } $GeoEventServiceName = 'ArcGISGeoEvent' $GeoEventService = Get-Service -Name $GeoEventServiceName -ErrorAction Ignore if($GeoEventService.Status -ieq 'Running') { $GeoEventServerHttpsUrl = "https://localhost:6143" ### ### If the SSL Certificate is changed. Restart the GeoEvent Service so that it will pick up the new certificate ### Restart-ArcGISService -ServiceName $GeoEventServiceName -Verbose Write-Verbose "Waiting for Url '$GeoEventServerHttpsUrl/geoevent/rest' to respond" Wait-ForUrl -Url "$GeoEventServerHttpsUrl/geoevent/rest" -SleepTimeInSeconds 20 -MaxWaitTimeInSeconds 150 -HttpMethod 'GET' -Verbose Write-Verbose "Restarted Service $GeoEventServiceName" } } #RootOrIntermediateCertificate $certNames = Get-AllSSLCertificateCNamesForMachine -ServerUrl $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN foreach ($key in ($SslRootOrIntermediate | ConvertFrom-Json)){ if ($certNames.certificates -icontains $key.Alias){ Write-Verbose "Set RootOrIntermediate $($key.Alias) is in List of SSL-Certificates no Action Required" }else{ Write-Verbose "Set RootOrIntermediate $($key.Alias) is NOT in List of SSL-Certificates Import-RootOrIntermediate" try{ Import-RootOrIntermediateCertificate -ServerUrl $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $MachineName -CertAlias $key.Alias -CertificateFilePath $key.Path }catch{ Write-Verbose "Error in Import-RootOrIntermediateCertificate :- $_" } } } if($RestartRequired) { Restart-ArcGISService -ServiceName $ServiceName -Verbose } Write-Verbose "Waiting for Url '$ServerURL/$SiteName/admin' to respond" Wait-ForUrl -Url "$ServerURL/$SiteName/admin" -SleepTimeInSeconds 10 -MaxWaitTimeInSeconds 60 -HttpMethod 'GET' if(-not($ServerType -ieq "NotebookServer" -or $ServerType -ieq "MissionServer")){ Write-Verbose 'Verifying that security config for site can be retrieved' $config = Get-SecurityConfig -ServerURL $ServerURL -SiteName $SiteName -Token $token.token -Referer $Referer Write-Verbose "SSLEnabled:- $($config.sslEnabled)" } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $false)] [System.String] $ServerHostName, [parameter(Mandatory = $true)] [System.String] $SiteName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $CertificateFileLocation, [System.Management.Automation.PSCredential] $CertificatePassword, [System.String] $CName, [System.String] $PortalEndPoint, [System.Boolean] $EnableSSL, [System.Boolean] $ImportOnly, [System.String] $SslRootOrIntermediate, [System.String] $ServerType ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false if($CertificateFileLocation -and -not(Test-Path $CertificateFileLocation)){ throw "Certificate File '$CertificateFileLocation' is not found or inaccessible" } [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null $result = $false $FQDN = if($ServerHostName){ Get-FQDN $ServerHostName }else{ Get-FQDN $env:COMPUTERNAME } $SitePort = 6443 if($ServerType -ieq "NotebookServer"){ $SitePort = 11443 }elseif($ServerType -ieq "MissionServer"){ $SitePort = 20443 } $ServerUrl = "https://$($FQDN):$($SitePort)" Wait-ForUrl -Url "$($ServerUrl)/$SiteName/admin/" -MaxWaitTimeInSeconds 60 -HttpMethod 'GET' $Referer = $ServerUrl $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName $SiteName -Credential $SiteAdministrator -Referer $Referer if(-not($token.token)){ throw "Unable to retrieve token for Site Administrator" } $Info = Invoke-ArcGISWebRequest -Url ($ServerUrl.TrimEnd('/') + "/arcgis/rest/info") -HttpFormParameters @{f = 'json';} -Referer $Referer -Verbose -HttpMethod 'GET' $ServerMinorVersion = "$($Info.fullVersion)".Split('.')[1] Write-Verbose $ServerMinorVersion if($EnableSSL -and -not($ServerType -ieq "NotebookServer" -or $ServerType -ieq "MissionServer")){ $secConfig = Get-SecurityConfig -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer $result = ($secConfig -and $secConfig.sslEnabled) Write-Verbose "SSL Enabled:- $result" } $CertWithCNameExists = $false if($result -or (-not($EnableSSL -and -not($ServerType -ieq "NotebookServer" -or $ServerType -ieq "MissionServer")))) { # SSL is enabled # Check the CName and issues on the SSL Certificate Write-Verbose "Checking Issuer and CName on Certificate" $NewCertIssuer = $null $NewCertThumbprint = $null if($CertificateFileLocation -and($null -ne $CertificatePassword)) { Write-Verbose "Examine certificate from $CertificateFileLocation" $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($CertificateFileLocation, $CertificatePassword.GetNetworkCredential().Password, 'DefaultKeySet') $NewCertIssuer = $cert.Issuer $NewCertThumbprint = $cert.Thumbprint Write-Verbose "Issuer for the supplied certificate is $NewCertIssuer" Write-Verbose "Thumbprint for the supplied certificate is $NewCertThumbprint" } $certNames = Get-AllSSLCertificateCNamesForMachine -ServerUrl $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN if($ImportOnly) { Write-Verbose "Import Only Scenario. Check if Certificate exists" if($certNames.certificates -icontains $CName) { Write-Verbose "Certificate with $CName already exists for Machine $FQDN" $CertWithCNameExists = $true }else{ Write-Verbose "Certificate with $CName not found for Machine $FQDN" } } else { $CertForMachine = Get-SSLCertificateForMachine -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN -SSLCertName $CName.ToLower() -Version $ServerMinorVersion -Verbose if($null -eq $CertForMachine){ Write-Verbose "Certificate with CName $CName not found on machine '$FQDN'" $result = $false }else{ if($ServerMinorVersion -ge 6){ $ExistingCertThumprint = $CertForMachine.Thumbprint Write-Verbose "Existing Cert Thumprint $ExistingCertThumprint" if($NewCertThumbprint -and ($ExistingCertThumprint -ine $NewCertThumbprint)){ Write-Verbose "New Cert does not match existing cert" Write-Verbose "Existing:- $ExistingCertThumprint New:- $NewCertThumbprint" $result = $false }else{ $CheckForCName = $True } }else{ $ExistingCertIssuer = $CertForMachine.Issuer Write-Verbose "Existing Cert Issuer $ExistingCertIssuer" if($NewCertIssuer -and ($ExistingCertIssuer -ine $NewCertIssuer)){ Write-Verbose "New Cert does not match existing cert" Write-Verbose "Existing:- $ExistingCertIssuer New:- $NewCertIssuer" $result = $false }else{ $CheckForCName = $True } } } } } if($CheckForCName -and $CName){ Write-Verbose "Desired CName:- $CName. Checking if machine is using this" $machineDetails = Get-MachineDetails -ServerURL $ServerUrl -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN if($CName -ieq $machineDetails.webServerCertificateAlias) { Write-Verbose "WebServerCertificateAlias '$($machineDetails.webServerCertificateAlias)' matches Desired CName of '$CName'" $CertWithCNameExists = $true $result = $true }else { Write-Verbose "WebServerCertificateAlias '$($machineDetails.webServerCertificateAlias)' does not match Desired CName of '$CName'" } } if(-not($CertWithCNameExists)) { Write-Verbose "Certificate with CName does not exist as expected" $result = $false }else { Write-Verbose "Certificate with CName exists as expected" $result = $true } if ($result) { # test for RootOrIntermediate Certificate-List $testRootorIntermediate = $true foreach ($key in ($SslRootOrIntermediate | ConvertFrom-Json)){ if ($certNames.certificates -icontains $key.Alias){ Write-Verbose "Test RootOrIntermediate $($key.Alias) is in List of SSL-Certificates" }else{ $testRootorIntermediate = $false Write-Verbose "Test RootOrIntermediate $($key.Alias) is NOT in List of SSL-Certificates" break; } } $result = $testRootorIntermediate } Write-Verbose "Returning $result from Test-TargetResource" if($Ensure -ieq 'Present') { $result } elseif($Ensure -ieq 'Absent') { (-not($result)) } } function Invoke-EnableHTTPSOnSecurityConfig { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $SiteName, [System.String] $Token, [System.String] $Referer, $SecurityConfig ) if(-not($SecurityConfig)) { throw "Security Config parameter is not provided" } $UpdateSecurityConfigUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/security/config/update" $props = @{ f= 'json'; token = $Token; Protocol = 'HTTP_AND_HTTPS'; authenticationTier = $SecurityConfig.authenticationTier; allowDirectAccess = $SecurityConfig.allowDirectAccess; cipherSuites = $SecurityConfig.cipherSuites } Invoke-ArcGISWebRequest -Url $UpdateSecurityConfigUrl -HttpFormParameters $props -Referer $Referer -TimeOutSec 300 } function Invoke-DeleteSSLCertForMachine { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $SiteName, [System.String] $Token, [System.String] $Referer, [System.String] $MachineName, [System.String] $SSLCertName ) $DeleteSSlCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslCertificates/$SSLCertName/delete" Invoke-ArcGISWebRequest -Url $DeleteSSlCertUrl -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'POST' -TimeoutSec 150 } function Invoke-GenerateSelfSignedCertificate { [CmdletBinding()] param([string]$ServerURL, [System.String] $SiteName, [System.String] $Token, [System.String] $Referer, [System.String] $MachineName, [System.String] $CertAlias, [System.String] $CertCommonName, [System.String] $CertOrganization, [System.String] $ValidityInDays = 1825 ) $GenerateSelfSignedCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslCertificates/generate" $props = @{ f= 'json'; token = $Token; alias = $CertAlias; commonName = $CertCommonName; organization = $CertOrganization; validity = $ValidityInDays } Invoke-ArcGISWebRequest -Url $GenerateSelfSignedCertUrl -HttpFormParameters $props -Referer $Referer -TimeOutSec 150 } function Import-ExistingCertificate { [CmdletBinding()] param( [System.String] $ServerUrl, [System.String] $SiteName, [System.String] $Token, [System.String] $Referer, [System.String] $MachineName, [System.String] $CertAlias, [System.Management.Automation.PSCredential] $CertificatePassword, [System.String] $CertificateFilePath, [System.String] $ServerType ) $ImportCACertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslCertificates/importExistingServerCertificate" $props = @{ f= 'json'; alias = $CertAlias; certPassword = $CertificatePassword.GetNetworkCredential().Password } $Header = @{} if(-not($ServerType -ieq "NotebookServer" -or $ServerType -ieq "MissionServer")){ $props["token"] = $Token; }else{ $Header["X-Esri-Authorization"] = "Bearer $Token" } $res = Invoke-UploadFile -url $ImportCACertUrl -filePath $CertificateFilePath -fileContentType 'application/x-pkcs12' -formParams $props -Referer $Referer -fileParameterName 'certFile' -httpHeaders $Header -Verbose if($res -and $res.Content) { $response = $res | ConvertFrom-Json Confirm-ResponseStatus $response -Url $ImportCACertUrl } else { Write-Verbose "[WARNING] Response from $ImportCACertUrl was $res" } } function Import-RootOrIntermediateCertificate { [CmdletBinding()] param( [System.String] $ServerUrl, [System.String] $SiteName = 'arcgis', [System.String] $Token, [System.String] $Referer, [string] $MachineName, [System.String] $CertAlias, [System.String] $CertificateFilePath ) $ImportCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslCertificates/importRootOrIntermediate" $props = @{ f= 'json'; token = $Token; alias = $CertAlias; } $res = Invoke-UploadFile -url $ImportCertUrl -filePath $CertificateFilePath -fileContentType 'application/x-pkcs12' -formParams $props -Referer $Referer -fileParameterName 'rootCACertificate' if($res -and $res.Content) { $response = $res | ConvertFrom-Json Confirm-ResponseStatus $response -Url $ImportCACertUrl } else { Write-Verbose "[WARNING] Response from $ImportCertUrl was null" } } function Get-SecurityConfig { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer ) $GetSecurityConfigUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/security/config/" Write-Verbose "Url:- $GetSecurityConfigUrl" Invoke-ArcGISWebRequest -Url $GetSecurityConfigUrl -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' -TimeOutSec 30 } function Update-SSLCertificate { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$MachineName, [string]$Referer, $MachineProperties, [int]$MaxAttempts = 5, [int]$SleepTimeInSecondsBetweenAttempts = 30, [System.Int32] $Version ) $UpdateSSLCertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/edit" $MachineProperties.psobject.properties | Foreach-Object -begin {$h=@{}} -process {$h."$($_.Name)" = $_.Value} -end {$h} # convert PSCustomObject to hashtable if($Version -lt 7){ $h.JMXPort = $MachineProperties.ports.JMXPort $h.OpenEJBPort = $MachineProperties.ports.OpenEJBPort $h.NamingPort = $MachineProperties.ports.NamingPort $h.DerbyPort = $MachineProperties.ports.DerbyPort } $h.ports = $null $h.f = 'json' $h.token = $Token [bool]$Done = $false [int]$Attempt = 1 while(-not($Done) -and $Attempt -le $MaxAttempts) { $AttemptStr = '' if($Attempt -gt 1) { $AttemptStr = "Attempt # $Attempt" } Write-Verbose "Update SSLCert Name $AttemptStr" try { $response = Invoke-ArcGISWebRequest -Url $UpdateSSLCertUrl -HttpFormParameters $h -Referer $Referer -TimeOutSec 150 if($response.status -ieq 'success'){ Write-Verbose "Update Web Server SSL Certificate Successful! Server will Restart now." $Done = $true }else{ if(($response.status -ieq 'error') -and $response.messages){ Write-Verbose "[WARNING]:- $($response.messages -join ',')" Start-Sleep -Seconds $SleepTimeInSecondsBetweenAttempts } } } catch { if($Attempt -ge $MaxAttempts) { Write-Verbose "[WARNING] Update failed after $MaxAttempts. Last Response:- $($_)" #throw "Update failed after $MaxAttempts. Error:- $($_)" } Start-Sleep -Seconds $SleepTimeInSecondsBetweenAttempts } $Attempt++ } $response } function Get-Machines { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName = 'arcgis', [string]$Token, [string]$Referer ) $GetMachinesUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/" Invoke-ArcGISWebRequest -Url $GetMachinesUrl -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' -TimeoutSec 150 } function Get-MachineDetails { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName ) $GetMachineDetailsUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/" Invoke-ArcGISWebRequest -Url $GetMachineDetailsUrl -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' -TimeoutSec 150 } function Get-AllSSLCertificateCNamesForMachine { [CmdletBinding()] param( [string]$ServerURL, [string]$SiteName = 'arcgis', [string]$Token, [string]$Referer, [string]$MachineName ) $certURL = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslCertificates/" Invoke-ArcGISWebRequest -Url $certURL -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' } function Get-SSLCertificateForMachine { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param( [string]$ServerURL, [string]$SiteName, [string]$Token, [string]$Referer, [string]$MachineName, [string]$SSLCertName, [System.Int32] $Version ) $CertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$MachineName/sslCertificates/$SSLCertName" try{ if($Version -ge 6){ $json = Invoke-ArcGISWebRequest -Url $CertUrl -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' if($json.error){ $errMsgs = ($json.error.messages -join ', ') Write-Verbose "[WARNING] Response from $CertUrl is $errMsgs" $null }elseif($json.status -and $json.status -ieq "error"){ $errMsgs = ($json.messages -join ', ') Write-Verbose "[WARNING] Response from $CertUrl is $errMsgs" $null }else{ $issuer = $json.issuer $CN = if($issuer) { ($issuer.Split(',') | ConvertFrom-StringData).CN } else { $null } @{ Issuer = $issuer CName = $CN Thumbprint = $json.sha1Fingerprint } } }else{ $props = @{ f= 'json'; token = $Token; } $cmdBody = ConvertTo-HttpBody $props $headers = @{'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } #Can't use ArcGIS WebRequest Method as the output might not be a JSON $res = Invoke-WebRequest -Uri $CertUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing ### Response is not valid JSON. Hence use Regex #Write-Verbose "Response $($res.Content)" if(-not($res.Content)){ Write-Verbose "[WARNING] Response from $CertUrl is NULL" $null }else { if($res.Content.IndexOf('error') -gt -1){ $json = $res.Content | ConvertFrom-Json $errMsgs = ($json.messages -join ', ') if($errMsgs -and ($errMsgs.IndexOf('Could not find resource or operation') -lt 0)) { Write-Verbose "[WARNING] Response from $CertUrl is $errMsgs" } $null }else { $IssuerValue = $null $Issuer = [regex]::matches($res.Content, '"[Ii]ssuer":[ ]?\"([A-Za-z =,\.0-9\-]+)\"') $Issuer.Groups | ForEach-Object{ if($_.Value -and $_.Value.Length -gt 0){ $Pos = $_.Value.ToLower().IndexOf('"issuer"') if($Pos -gt -1) { $Str = $_.Value.Substring($Pos + '"Issuer"'.Length) $Pos = $Str.IndexOf('"') if($Pos -gt -1) { $Str = $Str.Substring($Pos + 1) } $IssuerValue = $Str.TrimEnd('"') } } } Write-Verbose "Issuer Value:- $IssuerValue" $CN = if($IssuerValue) { ($IssuerValue.Split(',') | ConvertFrom-StringData).CN } else { $null } Write-Verbose "CN:- $CN" @{ Issuer = $IssuerValue CName = $CN Thumbprint = $null } } } } } catch{ # If no cert exists, an error is returned Write-Verbose "[WARNING] Error checking $CertUrl Error:- $_" $null } } Export-ModuleMember -Function *-TargetResource |