Configurations-OnPrem/ArcGISServer.ps1

Configuration ArcGISServer
{
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [System.Management.Automation.PSCredential]
        $ServiceCredential,

        [Parameter(Mandatory=$false)]
        [System.Boolean]
        $ForceServiceCredentialUpdate = $false,

        [Parameter(Mandatory=$false)]
        [System.Boolean]
        $ServiceCredentialIsDomainAccount = $false,

        [Parameter(Mandatory=$false)]
        [System.Boolean]
        $ServiceCredentialIsMSA = $false,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [System.Management.Automation.PSCredential]
        $ServerPrimarySiteAdminCredential,

        [Parameter(Mandatory=$True)]
        [System.String]
        $Version,
        
        [Parameter(Mandatory=$False)]
        [System.String]
        $PrimaryServerMachine,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ServerRole,

        [Parameter(Mandatory=$False)]
        [System.Array]
        $AdditionalServerRoles,

        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $OpenFirewallPorts = $False,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ConfigStoreLocation,

        [Parameter(Mandatory=$false)]
        [System.String]
        $ServerDirectoriesRootLocation,

        [Parameter(Mandatory=$false)]
        [System.Array]
        $ServerDirectories = $null,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ServerLogsLocation = $null,

        [Parameter(Mandatory=$False)]
        [System.String]
        $LocalRepositoryPath = $null,
        
        [Parameter(Mandatory=$False)]
        [System.Object]
        $RegisteredDirectories,

        [Parameter(Mandatory=$False)]
        [System.String]
        [ValidateSet("Azure","AWS", "None")]
        $CloudProvider = "None",

        [parameter(Mandatory = $False)]    
        [System.Boolean]
        $IsCloudNativeServer = $False,

        [parameter(Mandatory = $False)]    
        [System.Array]
        $CloudNativeTags = $null,

        [parameter(Mandatory = $False)]    
        [System.String]
        $CloudNativeLocalDirectory = $False,

        [Parameter(Mandatory=$False)]
        [System.String]
        $CloudNamespace = "None",

        [Parameter(Mandatory=$False)]
        [System.String]
        $AWSRegion = "None",

        [Parameter(Mandatory=$False)]
        [System.String]
        [ValidateSet("AccessKey","IAMRole","None")]
        $AWSCloudAuthenticationType = "None",

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AWSCloudAccessKeyCredential,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AWSCloudNativeS3BucketName,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AWSCloudNativeS3RegionEndpointURL,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AWSCloudNativeS3RootDir,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AWSCloudNativeDynamoDBRegionEndpointURL,
        
        [Parameter(Mandatory=$False)]
        [System.String]
        $AWSCloudNativeQueueServiceRegionEndpointURL,

        [Parameter(Mandatory=$False)]
        [System.String]
        [ValidateSet("AccessKey", "SASToken", "ServicePrincipal","UserAssignedIdentity","None")]
        $AzureCloudAuthenticationType = "None",

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AzureCloudStorageAccountCredential,

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AzureCloudServicePrincipalCredential,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudServicePrincipalTenantId,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudServicePrincipalAuthorityHost,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudUserAssignedIdentityClientId,
        
        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AzureCloudNativeStorageAccountCredential,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeStorageAccountContainerName,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeStorageAccountRootDir,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeStorageAccountAccountEndpointUrl,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeStorageAccountRegionEndpointUrl,

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AzureCloudNativeCosmosDBAccountCredential,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeCosmosDBAccountEndpointUrl,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeCosmosDBRegionEndpointUrl,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeCosmosDBAccountDatabaseId,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeCosmosDBAccountSubscriptionId,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeCosmosDBAccountResourceGroupName,

        [Parameter(Mandatory=$False)]
        [System.String]
        [ValidateSet("Direct","Gateway")]
        $AzureCloudNativeCosmosDBAccountConnectionMode = "Gateway",

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $AzureCloudNativeServiceBusNamespaceCredential,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeServiceBusNamespaceEndpointUrl,

        [Parameter(Mandatory=$False)]
        [System.String]
        $AzureCloudNativeServiceBusNamespaceRegionEndpointUrl,

        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $UsesAzureFilesForConfigStore = $False,

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $ConfigStoreAzureFilesCredentials,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ConfigStoreAzureFileShareName,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ConfigStoreAzureFilesCloudNamespace,

        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $UsesAzureFilesForServerDirectories = $False,

        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $ServerDirectoriesAzureFilesCredentials,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ServerDirectoriesAzureFileShareName,

        [Parameter(Mandatory=$False)]
        [System.String]
        $ServerDirectoriesAzureFilesCloudNamespace,

        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $EnableHTTPSOnly = $False,

        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $EnableHSTS = $False,

        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $UsesSSL = $False,

        [Parameter(Mandatory=$false)]
        [System.String]
        $WebSocketContextUrl,
        
        [Parameter(Mandatory=$False)]
        [System.Boolean]
        $DebugMode = $False
    )

    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -ModuleName ArcGIS -ModuleVersion 5.0.0 -Name ArcGIS_xFirewall, ArcGIS_Server, ArcGIS_Service_Account, ArcGIS_GeoEvent, ArcGIS_WaitForComponent, ArcGIS_Server_TLS, ArcGIS_Server_RegisterDirectories,ArcGIS_HostNameSettings

    if($UsesAzureFilesForConfigStore){
        $ConfigStorePos = $ConfigStoreAzureFilesCredentials.UserName.IndexOf('.blob.')
        $ConfigStoreAzureFilesEndpoint = if($ConfigStorePos -gt -1){ $ConfigStoreAzureFilesCredentials.UserName.Replace('.blob.','.file.') }else{ $ConfigStoreAzureFilesCredentials.UserName }
        $ConfigStoreAzureFileShareName = $ConfigStoreAzureFileShareName.ToLower() # Azure file shares need to be lower case
        $ConfigStoreLocation = "\\$($ConfigStoreAzureFilesEndpoint)\$($ConfigStoreAzureFileShareName)\$($ConfigStoreAzureFilesCloudNamespace)\server\config-store"
    }

    if($UsesAzureFilesForServerDirectories){
        $ServerDirectoriesPos = $ServerDirectoriesAzureFilesCredentials.UserName.IndexOf('.blob.')
        $ServerDirectoriesAzureFilesEndpoint = if($ServerDirectoriesPos -gt -1){$ServerDirectoriesAzureFilesCredentials.UserName.Replace('.blob.','.file.')}else{ $ServerDirectoriesAzureFilesCredentials.UserName }                   
        $ServerDirectoriesAzureFileShareName = $ServerDirectoriesAzureFileShareName.ToLower() # Azure file shares need to be lower case
        $ServerDirectoriesRootLocation = "\\$($ServerDirectoriesAzureFilesEndpoint)\$($ServerDirectoriesAzureFileShareName)\$($ServerDirectoriesAzureFilesCloudNamespace)\server\server-dirs" 
    }

    Node $AllNodes.NodeName
    { 
        if($Node.Thumbprint){
            LocalConfigurationManager
            {
                CertificateId = $Node.Thumbprint
            }
        }
        
        $IsMultiMachineServer = (($AllNodes | Measure-Object).Count -gt 1)

        $VersionArray = $Version.Split(".")
        $Depends = @()
        if($OpenFirewallPorts -or $IsMultiMachineServer ) # Server only deployment or behind an ILB or has DataStore nodes that need to register using admin
        {
            ArcGIS_xFirewall Server_FirewallRules
            {
                Name                  = "ArcGISServer" 
                DisplayName           = "ArcGIS for Server" 
                DisplayGroup          = "ArcGIS for Server" 
                Ensure                = 'Present' 
                Access                = "Allow" 
                State                 = "Enabled" 
                Profile               = ("Domain","Private","Public") 
                LocalPort             = ("6443")                       
                Protocol              = "TCP" 
            }
            $Depends += '[ArcGIS_xFirewall]Server_FirewallRules'
        }
        if($IsMultiMachineServer) 
        {
            if($ServerRole -ieq 'GeoAnalytics' -or ($ServerRole -ieq "GeneralPurposeServer" -and $AdditionalServerRoles -icontains "GeoAnalytics")) 
            {  
                $Depends += '[ArcGIS_xFirewall]GeoAnalytics_InboundFirewallRules' 
                $Depends += '[ArcGIS_xFirewall]GeoAnalytics_OutboundFirewallRules' 

                $GeoAnalyticsPorts = @("7077")
                if($VersionArray[0] -gt 10 -or ($VersionArray[0] -eq 10 -or $VersionArray[1] -gt 8)){
                    $GeoAnalyticsPorts += @("12181","12182","12190")
                }else{
                    $GeoAnalyticsPorts += @("2181","2182","2190")
                }

                ArcGIS_xFirewall GeoAnalytics_InboundFirewallRules
                {
                    Name                  = "ArcGISGeoAnalyticsInboundFirewallRules" 
                    DisplayName           = "ArcGIS GeoAnalytics" 
                    DisplayGroup          = "ArcGIS GeoAnalytics" 
                    Ensure                = 'Present'
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = $GeoAnalyticsPorts    # Spark and Zookeeper
                    Protocol              = "TCP" 
                }

                ArcGIS_xFirewall GeoAnalytics_OutboundFirewallRules
                {
                    Name                  = "ArcGISGeoAnalyticsOutboundFirewallRules" 
                    DisplayName           = "ArcGIS GeoAnalytics" 
                    DisplayGroup          = "ArcGIS GeoAnalytics" 
                    Ensure                = 'Present'
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = $GeoAnalyticsPorts    # Spark and Zookeeper
                    Protocol              = "TCP" 
                    Direction             = "Outbound"    
                }

                ArcGIS_xFirewall GeoAnalyticsCompute_InboundFirewallRules
                {
                    Name                  = "ArcGISGeoAnalyticsComputeInboundFirewallRules" 
                    DisplayName           = "ArcGIS GeoAnalytics" 
                    DisplayGroup          = "ArcGIS GeoAnalytics" 
                    Ensure                = 'Present'
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = ("56540-56550")    # GA Compute
                    Protocol              = "TCP" 
                }

                ArcGIS_xFirewall GeoAnalyticsCompute_OutboundFirewallRules
                {
                    Name                  = "ArcGISGeoAnalyticsComputeOutboundFirewallRules" 
                    DisplayName           = "ArcGIS GeoAnalytics" 
                    DisplayGroup          = "ArcGIS GeoAnalytics" 
                    Ensure                = 'Present'
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = ("56540-56550")    # GA Compute
                    Protocol              = "TCP" 
                    Direction             = "Outbound"    
                }
            }
        }

        $DataDirs = @()
        # Only add config store location if not using Azure Files for config store or is not using a cloud provider for config store
        if($CloudProvider -ieq "None" -and -not($UsesAzureFilesForConfigStore)){
            $DataDirs += @($ConfigStoreLocation)
        }
        # Only add server directories root location if not using Azure Files for server directories or is not using cloud native server deployment
        if(-not($IsCloudNativeServer) -and -not($UsesAzureFilesForServerDirectories)){
            $DataDirs += @($ServerDirectoriesRootLocation)
            if($ServerDirectories -ne $null){
                foreach($dir in $ServerDirectories){
                    $DataDirs += $dir.physicalPath
                }
            }
        }

        if($null -ne $ServerLogsLocation){
            $DataDirs += @($ServerLogsLocation)
        }

        if($null -ne $LocalRepositoryPath){
            $DataDirs += @($LocalRepositoryPath)
        }

        ArcGIS_Service_Account Server_RunAs_Account
        {
            Name = 'ArcGIS Server'
            RunAsAccount = $ServiceCredential
            ForceRunAsAccountUpdate = $ForceServiceCredentialUpdate
            Ensure = 'Present'
            DependsOn = $Depends
            DataDir = $DataDirs
            IsDomainAccount = $ServiceCredentialIsDomainAccount
            IsMSAAccount = $ServiceCredentialIsMSA
            SetStartupToAutomatic = $True
        }

        $Depends += '[ArcGIS_Service_Account]Server_RunAs_Account' 

        ArcGIS_HostNameSettings ServerHostNameSettings{
            ComponentName   = "Server"
            Version         = $Version
            HostName        = $Node.NodeName
            DependsOn       = $DependsOn
        }
        $DependsOn += '[ArcGIS_HostNameSettings]ServerHostNameSettings'

        if(-not($ServiceCredentialIsMSA) -and ($UsesAzureFilesForConfigStore -or $UsesAzureFilesForServerDirectories)) 
        {
            if($UsesAzureFilesForConfigStore -and $ConfigStoreAzureFilesEndpoint -and $ConfigStoreAzureFilesCredentials){
                $ConfigStoreFilesStorageAccountName = $ConfigStoreAzureFilesEndpoint.Substring(0, $ConfigStoreAzureFilesEndpoint.IndexOf('.'))
                $ConfigStoreStorageAccountKey       = $ConfigStoreAzureFilesCredentials.GetNetworkCredential().Password

                Script PersistConfigStoreCloudStorageCredentials
                {
                    TestScript = { 
                                    $result = cmdkey "/list:$using:ConfigStoreAzureFilesEndpoint"
                                    $result | ForEach-Object{Write-verbose -Message "cmdkey: $_" -Verbose}
                                    if($result -like '*none*')
                                    {
                                        return $false
                                    }
                                    return $true
                                }
                    SetScript = { 
                                    $result = cmdkey "/add:$using:ConfigStoreAzureFilesEndpoint" "/user:$using:ConfigStoreFilesStorageAccountName" "/pass:$using:ConfigStoreStorageAccountKey" 
                                    $result | ForEach-Object{Write-verbose -Message "cmdkey: $_" -Verbose}
                                }
                    GetScript            = { return @{} }                  
                    DependsOn            = $Depends
                    PsDscRunAsCredential = $ServiceCredential # This is critical, cmdkey must run as the service account to persist property
                }              
                $Depends += '[Script]PersistConfigStoreCloudStorageCredentials'
            }

            if($UsesAzureFilesForServerDirectories -and $ServerDirectoriesAzureFilesEndpoint -and $ServerDirectoriesAzureFilesCredentials){
                $ServerDirectoriesFilesStorageAccountName = $ServerDirectoriesAzureFilesEndpoint.Substring(0, $ServerDirectoriesAzureFilesEndpoint.IndexOf('.'))
                $ServerDirectoriesStorageAccountKey       = $ServerDirectoriesAzureFilesCredentials.GetNetworkCredential().Password

                Script PersistServerDirectoriesCloudStorageCredentials
                {
                    TestScript = { 
                                    $result = cmdkey "/list:$using:ServerDirectoriesAzureFilesEndpoint"
                                    $result | ForEach-Object{Write-verbose -Message "cmdkey: $_" -Verbose}
                                    if($result -like '*none*')
                                    {
                                        return $false
                                    }
                                    return $true
                                }
                    SetScript = { 
                                    $result = cmdkey "/add:$using:ServerDirectoriesAzureFilesEndpoint" "/user:$using:ServerDirectoriesFilesStorageAccountName" "/pass:$using:ServerDirectoriesStorageAccountKey" 
                                    $result | ForEach-Object{Write-verbose -Message "cmdkey: $_" -Verbose}
                                }
                    GetScript            = { return @{} }                  
                    DependsOn            = $Depends
                    PsDscRunAsCredential = $ServiceCredential # This is critical, cmdkey must run as the service account to persist property
                }              
                $Depends += '[Script]PersistServerDirectoriesCloudStorageCredentials'
            }
        }

        if($Node.NodeName -ine $PrimaryServerMachine)
        {
            if($UsesSSL){
                ArcGIS_WaitForComponent "WaitForServer$($PrimaryServerMachine)"{
                    Component = "Server"
                    InvokingComponent = "Server"
                    ComponentHostName = $PrimaryServerMachine
                    ComponentContext = "arcgis"
                    Credential = $ServerPrimarySiteAdminCredential
                    Ensure = "Present"
                    RetryIntervalSec = 60
                    RetryCount = 100
                }
                $Depends += "[ArcGIS_WaitForComponent]WaitForServer$($PrimaryServerMachine)"
            }else{
                WaitForAll "WaitForAllServer$($PrimaryServerMachine)"{
                    ResourceName = "[ArcGIS_Server]Server$($PrimaryServerMachine)"
                    NodeName = $PrimaryServerMachine
                    RetryIntervalSec = 60
                    RetryCount = 100
                    DependsOn = $Depends
                }
                $Depends += "[WaitForAll]WaitForAllServer$($PrimaryServerMachine)"
            }
        }

        ArcGIS_Server "Server$($Node.NodeName)"
        {
            Version = $Version
            ServerHostName = $Node.NodeName
            Ensure = 'Present'
            SiteAdministrator = $ServerPrimarySiteAdminCredential
            ConfigurationStoreLocation = $ConfigStoreLocation
            ServerDirectoriesRootLocation = $ServerDirectoriesRootLocation
            ServerDirectories = if($null -ne $ServerDirectories){ (ConvertTo-JSON $ServerDirectories -Depth 5) }else{ $null }
            ServerLogsLocation = $ServerLogsLocation
            LocalRepositoryPath = $LocalRepositoryPath
            Join =  if($Node.NodeName -ine $PrimaryServerMachine) { $true } else { $false } 
            PeerServerHostName = $PrimaryServerMachine
            DependsOn = $Depends
            LogLevel = if($DebugMode) { 'DEBUG' } else { 'WARNING' }            
            CloudProvider = $CloudProvider
            IsCloudNativeServer = $IsCloudNativeServer
            CloudNamespace = $CloudNamespace
            AWSCloudAuthenticationType = $AWSCloudAuthenticationType
            AWSRegion = $AWSRegion
            AWSCloudAccessKeyCredential = $AWSCloudAccessKeyCredential
            AzureCloudAuthenticationType = $AzureCloudAuthenticationType
            AzureCloudStorageAccountCredential = $AzureCloudStorageAccountCredential
            AzureCloudServicePrincipalCredential = $AzureCloudServicePrincipalCredential
            AzureCloudServicePrincipalTenantId = $AzureCloudServicePrincipalTenantId
            AzureCloudServicePrincipalAuthorityHost = $AzureCloudServicePrincipalAuthorityHost
            AzureCloudUserAssignedIdentityClientId = $AzureCloudUserAssignedIdentityClientId
            CloudNativeTags = if($CloudNativeTags){(ConvertTo-JSON $CloudNativeTags -Depth 5 -Compress)}else{$null}
            CloudNativeLocalDirectory = $CloudNativeLocalDirectory
            AWSCloudNativeS3BucketName = $AWSCloudNativeS3BucketName
            AWSCloudNativeS3RegionEndpointURL = $AWSCloudNativeS3RegionEndpointURL
            AWSCloudNativeS3RootDir = $AWSCloudNativeS3RootDir
            AWSCloudNativeDynamoDBRegionEndpointURL = $AWSCloudNativeDynamoDBRegionEndpointURL
            AWSCloudNativeQueueServiceRegionEndpointURL = $AWSCloudNativeQueueServiceRegionEndpointURL
            AzureCloudNativeStorageAccountCredential = $AzureCloudNativeStorageAccountCredential
            AzureCloudNativeStorageAccountContainerName = $AzureCloudNativeStorageAccountContainerName
            AzureCloudNativeStorageAccountRootDir = $AzureCloudNativeStorageAccountRootDir
            AzureCloudNativeStorageAccountAccountEndpointUrl = $AzureCloudNativeStorageAccountAccountEndpointUrl
            AzureCloudNativeStorageAccountRegionEndpointUrl = $AzureCloudNativeStorageAccountRegionEndpointUrl
            AzureCloudNativeCosmosDBAccountCredential = $AzureCloudNativeCosmosDBAccountCredential
            AzureCloudNativeCosmosDBAccountEndpointUrl = $AzureCloudNativeCosmosDBAccountEndpointUrl
            AzureCloudNativeCosmosDBRegionEndpointUrl = $AzureCloudNativeCosmosDBRegionEndpointUrl
            AzureCloudNativeCosmosDBAccountDatabaseId = $AzureCloudNativeCosmosDBAccountDatabaseId
            AzureCloudNativeCosmosDBAccountSubscriptionId = $AzureCloudNativeCosmosDBAccountSubscriptionId
            AzureCloudNativeCosmosDBAccountResourceGroupName = $AzureCloudNativeCosmosDBAccountResourceGroupName
            AzureCloudNativeCosmosDBAccountConnectionMode = $AzureCloudNativeCosmosDBAccountConnectionMode
            AzureCloudNativeServiceBusNamespaceCredential = $AzureCloudNativeServiceBusNamespaceCredential
            AzureCloudNativeServiceBusNamespaceEndpointUrl  = $AzureCloudNativeServiceBusNamespaceEndpointUrl
            AzureCloudNativeServiceBusNamespaceRegionEndpointUrl = $AzureCloudNativeServiceBusNamespaceRegionEndpointUrl
        }
        $Depends += "[ArcGIS_Server]Server$($Node.NodeName)"
        
        $ImportCertChainValue = $true  # default to true
        $ForceImportCertificate = $false
        if ([version]$Version -ge [version]"11.3") {
            if ($Node.SSLCertificate -and $Node.SSLCertificate.ImportCertificateChain -ne $null) {
                $ImportCertChainValue = $Node.SSLCertificate.ImportCertificateChain
            }
            if ($Node.SSLCertificate -and $Node.SSLCertificate.ForceImport -ne $null) {
                $ForceImportCertificate = $Node.SSLCertificate.ForceImport
            }
        }

        ArcGIS_Server_TLS "Server_TLS_$($Node.NodeName)"
        {
            ServerHostName = $Node.NodeName
            SiteAdministrator = $ServerPrimarySiteAdminCredential
            WebServerCertificateAlias =  if($Node.SSLCertificate){$Node.SSLCertificate.CName}else{$null}
            CertificateFileLocation = if($Node.SSLCertificate){$Node.SSLCertificate.Path}else{$null}
            CertificatePassword = if($Node.SSLCertificate){$Node.SSLCertificate.Password}else{$null}
            SslRootOrIntermediate = if($Node.SslRootOrIntermediate){$Node.SslRootOrIntermediate}else{$null}
            EnableHTTPSOnly = $EnableHTTPSOnly
            EnableHSTS = $EnableHSTS
            ServerType = "Server"
            Version    = $Version
            ImportCertificateChain = $ImportCertChainValue
            ForceImportCertificate = $ForceImportCertificate
            DependsOn = $Depends
        }
        $Depends += "[ArcGIS_Server_TLS]Server_TLS_$($Node.NodeName)"
        
        if ($RegisteredDirectories -and ($Node.NodeName -ieq $PrimaryServerMachine)) {
            ArcGIS_Server_RegisterDirectories "Server$($Node.NodeName)RegisterDirectories"
            { 
                ServerHostName = $Node.NodeName
                Ensure = 'Present'
                SiteAdministrator = $ServerPrimarySiteAdminCredential
                DirectoriesJSON = $RegisteredDirectories
                DependsOn = $Depends
            }
            $Depends += "[ArcGIS_Server_RegisterDirectories]Server$($Node.NodeName)RegisterDirectories"
        }

        if($ServerRole -ieq "GeoEvent" -or ($ServerRole -ieq "GeneralPurposeServer" -and $AdditionalServerRoles -icontains "GeoEvent")) 
        { 
            #This condition is an issue
            ArcGIS_Service_Account GeoEvent_RunAs_Account
            {
                Name = 'ArcGISGeoEvent'
                RunAsAccount = $ServiceCredential
                ForceRunAsAccountUpdate = $ForceServiceCredentialUpdate
                Ensure =  "Present"
                DependsOn = $Depends
                DataDir = "$env:ProgramData\Esri\GeoEvent"
                IsDomainAccount = $ServiceCredentialIsDomainAccount
                IsMSAAccount = $ServiceCredentialIsMSA
                SetStartupToAutomatic = $True
            }
            $Depends += "[ArcGIS_Service_Account]GeoEvent_RunAs_Account"

            ArcGIS_xFirewall GeoEvent_FirewallRules
            {
                Name                  = "ArcGISGeoEventFirewallRules" 
                DisplayName           = "ArcGIS GeoEvent" 
                DisplayGroup          = "ArcGIS GeoEvent Extension" 
                Ensure                = "Present"
                Access                = "Allow" 
                State                 = "Enabled" 
                Profile               = ("Domain","Private","Public")
                LocalPort             = ("6143","6180","5565","5575")
                Protocol              = "TCP" 
                DependsOn             = $Depends
            }
            $Depends += "[ArcGIS_xFirewall]GeoEvent_FirewallRules"
            
            if($IsMultiMachineServer -and ($VersionArray[0] -eq 10 -and $VersionArray[1] -lt 9))
            {
                ArcGIS_xFirewall GeoEvent_FirewallRules_Zookeeper
                {
                    Name                  = "ArcGISGeoEventFirewallRulesClusterZookeeper" 
                    DisplayName           = "ArcGIS GeoEvent Extension Cluster Zookeeper" 
                    DisplayGroup          = "ArcGIS GeoEvent Extension" 
                    Ensure                = 'Present' 
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = ("4181","4182","4190")
                    Protocol              = "TCP" 
                }

                ArcGIS_xFirewall GeoEvent_FirewallRule_Zookeeper_Outbound
                {
                    Name                  = "ArcGISGeoEventFirewallRulesClusterOutboundZookeeper" 
                    DisplayName           = "ArcGIS GeoEvent Extension Cluster Outbound Zookeeper" 
                    DisplayGroup          = "ArcGIS GeoEvent Extension" 
                    Ensure                = 'Present' 
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    RemotePort            = ("4181","4182","4190")
                    Protocol              = "TCP" 
                    Direction             = "Outbound"    
                }
                $ServerDependsOn += @('[ArcGIS_xFirewall]GeoEvent_FirewallRule_Zookeeper_Outbound','[ArcGIS_xFirewall]GeoEvent_FirewallRules_Zookeeper')

                $GeoEventPorts = ("27271","27272","27273","9191","9192","9193","9194","9220","9320","5565","5575")
                if($VersionArray[0] -gt 10 -or ($VersionArray[0] -eq 10 -or $VersionArray[1] -gt 8)){
                    $GeoEventPorts += @("12181","12182","12190")
                }else{
                    $GeoEventPorts += @("2181","2182","2190")
                }

                ArcGIS_xFirewall GeoEvent_FirewallRules_MultiMachine
                {
                    Name                  = "ArcGISGeoEventFirewallRulesCluster" 
                    DisplayName           = "ArcGIS GeoEvent Extension Cluster" 
                    DisplayGroup          = "ArcGIS GeoEvent Extension" 
                    Ensure                = "Present"
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = $GeoEventPorts
                    Protocol              = "TCP" 
                    DependsOn             = $Depends
                }
                $Depends += "[ArcGIS_xFirewall]GeoEvent_FirewallRules_MultiMachine"

                ArcGIS_xFirewall GeoEvent_FirewallRules_MultiMachine_OutBound
                {
                    Name                  = "ArcGISGeoEventFirewallRulesClusterOutbound" 
                    DisplayName           = "ArcGIS GeoEvent Extension Cluster Outbound" 
                    DisplayGroup          = "ArcGIS GeoEvent Extension" 
                    Ensure                =  "Present"
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    RemotePort            = $GeoEventPorts
                    Protocol              = "TCP" 
                    Direction             = "Outbound"    
                    DependsOn             = $Depends
                }
                $Depends += "[ArcGIS_xFirewall]GeoEvent_FirewallRules_MultiMachine_OutBound"

                ArcGIS_xFirewall GeoEventGatewayService_Firewall
                {
                    Name                  = "ArcGISGeoEventGateway"
                    DisplayName           = "ArcGIS GeoEvent Gateway"
                    DisplayGroup          = "ArcGIS GeoEvent Extension"
                    Ensure                = 'Present'
                    Access                = "Allow"
                    State                 = "Enabled"
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = ("9092")
                    Protocol              = "TCP"
                    DependsOn             = $Depends
                }
                $Depends += "[ArcGIS_xFirewall]GeoEventGatewayService_Firewall"
            }
            if($null -eq $WebSocketContextUrl -or $WebSocketContextUrl -eq ""){
                $WebSocketContextUrl = "wss://$(Get-FQDN $Node.NodeName):6143/arcgis"
            }

            ArcGIS_GeoEvent ArcGIS_GeoEvent
            {
                ServerHostName            = $Node.NodeName
                Name                      = 'ArcGIS GeoEvent'
                Ensure                      =  "Present"
                SiteAdministrator         = $ServerPrimarySiteAdminCredential
                WebSocketContextUrl       = $WebSocketContextUrl
                Version                      = $Version
                DependsOn                 = $Depends
                #SiteAdminUrl = if($ConfigData.ExternalDNSName) { "https://$($ConfigData.ExternalDNSName)/arcgis/admin" } else { $null }
            }
        }

        if($ServerRole -ieq "WorkflowManagerServer" -or ($ServerRole -ieq "GeneralPurposeServer" -and $AdditionalServerRoles -icontains "WorkflowManagerServer")) 
        {
            #This condition is an issue
            ArcGIS_Service_Account WorkflowManager_RunAs_Account
            {
                Name = 'WorkflowManager'
                RunAsAccount = $ServiceCredential
                ForceRunAsAccountUpdate = $ForceServiceCredentialUpdate
                Ensure =  "Present"
                DependsOn = $Depends
                DataDir = "$env:ProgramData\Esri\workflowmanager"
                IsDomainAccount = $ServiceCredentialIsDomainAccount
                IsMSAAccount = $ServiceCredentialIsMSA
                SetStartupToAutomatic = $True
            }
            $Depends += "[ArcGIS_Service_Account]WorkflowManager_RunAs_Account"

            ArcGIS_xFirewall WorkflowManagerServer_FirewallRules
            {
                Name                  = "ArcGISWorkflowManagerServerFirewallRules" 
                DisplayName           = "ArcGIS Workflow Manager Server" 
                DisplayGroup          = "ArcGIS Workflow Manager Server Extension" 
                Ensure                = "Present"
                Access                = "Allow" 
                State                 = "Enabled" 
                Profile               = ("Domain","Private","Public")
                LocalPort             = ("13443")
                Protocol              = "TCP" 
                DependsOn             = $Depends
            }
            $Depends += "[ArcGIS_xFirewall]WorkflowManagerServer_FirewallRules"

            if($IsMultiMachineServer){
                $WfmPorts = @("9830", "9820", "9840", "9880")
                if(($VersionArray[0] -gt 11) -or ($VersionArray[0] -ieq 11 -and $VersionArray[1] -ge 3)){
                    $WfmPorts = @("13820", "13830", "13840", "9880")
                }
                ArcGIS_xFirewall WorkflowManagerServer_FirewallRules_MultiMachine_OutBound
                {
                    Name                  = "ArcGISWorkflowManagerServerFirewallRulesClusterOutbound" 
                    DisplayName           = "ArcGIS WorkflowManagerServer Extension Cluster Outbound" 
                    DisplayGroup          = "ArcGIS WorkflowManagerServer Extension" 
                    Ensure                =  "Present"
                    Access                = "Allow" 
                    State                 = "Enabled" 
                    Profile               = ("Domain","Private","Public")
                    RemotePort            = $WfmPorts
                    Protocol              = "TCP" 
                    Direction             = "Outbound"    
                    DependsOn             = $Depends
                }
                $Depends += "[ArcGIS_xFirewall]WorkflowManagerServer_FirewallRules_MultiMachine_OutBound"

                ArcGIS_xFirewall WorkflowManagerServer_FirewallRules_MultiMachine_InBound
                {
                    Name                  = "ArcGISWorkflowManagerServerFirewallRulesClusterInbound"
                    DisplayName           = "ArcGIS WorkflowManagerServer Extension Cluster Inbound"
                    DisplayGroup          = "ArcGIS WorkflowManagerServer Extension"
                    Ensure                = 'Present'
                    Access                = "Allow"
                    State                 = "Enabled"
                    Profile               = ("Domain","Private","Public")
                    LocalPort             = $WfmPorts
                    Protocol              = "TCP"
                    Direction             = "Inbound"
                    DependsOn             = $Depends
                }
                $Depends += "[ArcGIS_xFirewall]WorkflowManagerServer_FirewallRules_MultiMachine_InBound"
            }
        }
    }
}