DSCResources/ArcGIS_TLSCertificateImport/ArcGIS_TLSCertificateImport.psm1
<#
.SYNOPSIS Imports a SSL certificate from remote machine to local machines root store. .PARAMETER Ensure Take the values Present or Absent. - "Present" ensures the certificate is Imported from remote machine to local machines root store. - "Absent" ensures the certificate is removed from local machines root store. .PARAMETER HostName Host Name of the Remote Machine whose SSL Certificate needs to be imported into the trusted local store. .PARAMETER ApplicationPath Application Path from where the certificate is to imported. .PARAMETER StoreLocation Location of the Store where the SSL Certificate will be imported .PARAMETER StoreName Store Name in the Store Location where the SSL Certificate will be imported .PARAMETER SiteAdministrator Credential to the Access the link to import Certificates into Trusted Store. .PARAMETER HttpsPort Port to which this certificate will be binded #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $HostName, [parameter(Mandatory = $true)] [System.String] $ApplicationPath, [parameter(Mandatory = $true)] [System.String] $StoreLocation = 'LocalMachine', [parameter(Mandatory = $true)] [System.String] $StoreName = 'Root', [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SiteAdministrator, [parameter(Mandatory = $true)] [uint32] $HttpsPort, [parameter(Mandatory = $false)] [System.String] $ServerType ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false $null } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $HostName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $ApplicationPath, [parameter(Mandatory = $true)] [System.String] $StoreLocation = 'LocalMachine', [parameter(Mandatory = $true)] [System.String] $StoreName = 'Root', [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SiteAdministrator, [parameter(Mandatory = $true)] [uint32] $HttpsPort, [parameter(Mandatory = $false)] [System.String] $ServerType ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null $FQDN = Get-FQDN $HostName $AppPath = $ApplicationPath.TrimStart('/') $Url = "https://$($FQDN):$($HttpsPort)/$AppPath" Write-Verbose "Test Certificate existence from '$Url' in $StoreLocation and $StoreName" $result = Test-CertificateInTrustedCertificateStore -Url $Url -StoreLocation $StoreLocation -StoreName $StoreName if($Ensure -ieq 'Present') { $result } elseif($Ensure -ieq 'Absent') { (-not($result)) } } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $HostName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $ApplicationPath, [parameter(Mandatory = $true)] [System.String] $StoreLocation = 'LocalMachine', [parameter(Mandatory = $true)] [System.String] $StoreName = 'Root', [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SiteAdministrator, [parameter(Mandatory = $true)] [uint32] $HttpsPort, [parameter(Mandatory = $false)] [System.String] $ServerType ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false if($Ensure -ieq 'Present') { [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null $FQDN = Get-FQDN $HostName $AppPath = $ApplicationPath.TrimStart('/') $Url = "https://$($FQDN):$($HttpsPort)/$AppPath" Write-Verbose "Certificate import from '$Url' into $StoreLocation and $StoreName" if(-not(Test-CertificateInTrustedCertificateStore -Url $Url -StoreLocation $StoreLocation -StoreName $StoreName)) { Write-Verbose "Import certificate from $Url" Import-CertFromServerIntoTrustedCertificateStore -Url $Url -StoreLocation $StoreLocation -StoreName $StoreName -SiteAdministrator $SiteAdministrator -ServerType $ServerType } }else { Write-Verbose "Ensure ='Absent' not implemented" } } function Test-CertificateInTrustedCertificateStore { [CmdletBinding()] [OutputType([System.Boolean])] param( [parameter(Mandatory = $true)] [System.String] $Url, [parameter(Mandatory = $false)] [System.String] $StoreLocation = 'LocalMachine', [parameter(Mandatory = $false)] [System.String] $StoreName = 'Root' ) $global:certCheck = $false [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert = $args[1] [System.Net.Security.SslPolicyErrors]$errors = $args[3] if($errors -ne [System.Net.Security.SslPolicyErrors]::None) { if(-not(Test-Path "Cert:\$StoreLocation\$StoreName\$($cert.Thumbprint)")) { Write-Verbose "Certificate '$($cert.Thumbprint)' does not exist in $StoreName store in $StoreLocation" }else { $global:certCheck = $true Write-Verbose "Certificate '$($cert.Thumbprint)' already exists in $StoreName store in $StoreLocation" } }else{ $global:certCheck = $true } } try { Write-Verbose "Connecting to $Url to retrieve SSL certificate" [System.Net.HttpWebRequest]$request = [System.Net.WebRequest]::Create($Url) [System.Net.HttpWebResponse]$response = $request.GetResponse() $respStream = $response.GetResponseStream() Write-Verbose "Successfully connected to $Url" } catch{ Write-Verbose "Connecting to $Url. Expected Error:- $_" } finally { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} [System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls } $global:certCheck } function Get-AllSSLCertificateCNamesForMachine { [CmdletBinding()] param( [string]$ServerHostName = 'localhost', [string]$SiteName = 'arcgis', [string]$Token, [string]$Referer, [string]$MachineName, [string]$ServerType ) $SitePort = if($ServerType -ieq "NotebookServer"){ 11443 }elseif($ServerType -ieq "MissionServer"){ 20443 }else{ 6443 } Invoke-ArcGISWebRequest -Url "https://$($ServerHostName):$($SitePort)/$SiteName/admin/machines/$MachineName/sslCertificates/" -HttpFormParameters @{ f= 'json'; token = $Token; } -Referer $Referer -HttpMethod 'GET' } function Import-CertFromServerIntoTrustedCertificateStore { [CmdletBinding()] param( [parameter(Mandatory = $true)] [System.String] $Url, [parameter(Mandatory = $false)] [System.String] $StoreLocation = 'LocalMachine', [parameter(Mandatory = $false)] [System.String] $StoreName = 'Root', [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $ServerType ) [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert = $args[1] [System.Net.Security.SslPolicyErrors]$errors = $args[3] # Import Certificate into ArcGIS Server (establish trust between JVM) if($SiteAdministrator) { $FQDN = Get-FQDN $env:COMPUTERNAME $SitePort = if($ServerType -ieq "NotebookServer"){ 11443 }elseif($ServerType -ieq "MissionServer"){ 20443 }else{ 6443 } $ServerUrl = "https://$($FQDN):$($SitePort)" $SiteName = 'arcgis' #Wait-ForUrl -Url "$($ServerUrl)/$SiteName/admin/" -MaxWaitTimeInSeconds 60 -HttpMethod 'GET' $Referer = $ServerUrl $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName 'arcgis' -Credential $SiteAdministrator -Referer $Referer $CertOnDiskPath = Join-Path $env:TEMP "$($cert.Thumbprint).cer" Set-Content -Path $CertOnDiskPath -Value ($cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)) -Encoding Byte -Force $Subject = $cert.Subject $Splits = $Subject -split ',' foreach($split in $Splits) { $SubSplit = $split -split '=' $SubSplitKey = $SubSplit | Select-Object -First 1 $SubSplitValue = $SubSplit | Select-Object -Last 1 if($SubSplit -ieq 'CN'){ $Issuer = $SubSplitValue $break } } $ub = New-Object System.UriBuilder -ArgumentList $Url $Alias = "$($ub.Host)-$($ub.Port)" Write-Verbose "Thumbprint of certificate is $($cert.Thumbprint). Issue is $($Issuer). Alias being used is $($Alias)." if($Alias) { $certNames = Get-AllSSLCertificateCNamesForMachine -ServerHostName $FQDN -SiteName $SiteName -Token $token.token -Referer $Referer -MachineName $FQDN -ServerType $ServerType if($certNames.certificates -icontains $Alias) { Write-Verbose "Certificate with alias $Alias already exists for Machine $FQDN" }else{ Write-Verbose "Certificate with alias $Alias not found for Machine $FQDN" $ImportCACertUrl = $ServerURL.TrimEnd("/") + "/$SiteName/admin/machines/$FQDN/sslCertificates/importRootOrIntermediate" $props = @{ f= 'json'; token = $token.token; alias = $Alias } Write-Verbose "Import Certificate URL:- $ImportCACertUrl" Invoke-UploadFile -url $ImportCACertUrl -filePath $CertOnDiskPath ` -fileContentType 'application/pkix-cert' -fileParameterName 'rootCACertificate' ` -fileName "$($cert.Thumbprint).cer" -Referer $Referer -formParams $props } }else { Write-Verbose 'Unable to determine alias from certificate exposed by web server' } if(Test-Path $CertOnDiskPath -ErrorAction Ignore) { Remove-Item $CertOnDiskPath -Force -ErrorAction Ignore } }else { Write-Verbose "Not importing SSL Certificate into ArcGIS Server" } if($errors -ne [System.Net.Security.SslPolicyErrors]::None) { if(-not(Test-Path "Cert:\$StoreLocation\$StoreName\$($cert.Thumbprint)")) { Write-Verbose "Importing Certificate '$($cert.Thumbprint)' to $StoreName store in $StoreLocation" $certStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store $StoreName, $StoreLocation $certStore.Open("MaxAllowed") $certStore.Add($cert) $certStore.Close() Write-Verbose "Imported Certificate to $StoreName store in $StoreLocation" }else { Write-Verbose "Certificate '$($cert.Thumbprint)' already exists in $StoreName store in $StoreLocation" } } } try { Write-Verbose "Connecting to $Url to retrieve SSL certificate" [System.Net.HttpWebRequest]$request = [System.Net.WebRequest]::Create($Url) [System.Net.HttpWebResponse]$response = $request.GetResponse() $respStream = $response.GetResponseStream() Write-Verbose "Successfully connected to $Url" } catch{ Write-Verbose "Connecting to $Url. Expected Error:- $_" } finally { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} [System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls } } Export-ModuleMember -Function *-TargetResource |