{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "ArcGIS CloudFormation Template: Provisions a ArcGIS site with Portal for ArcGIS, ArcGIS Server, ArcGIS Data Store and ArcGIS Web Adaptor on an EC2 instance running Windows Server 2016. **WARNING** You will be billed by AWS for the AWS resources if you create a stack from this template.",
    "Mappings" : {
        "RegionMap" : {
      "ap-northeast-1": {
        "en": "ami-02de84cbdae7334c7"
      },
      "ap-northeast-2": {
        "en": "ami-0bd9b7da24cf1c646"
      },
      "ap-south-1": {
        "en": "ami-0c8f65f087a504e80"
      },
      "ap-southeast-1": {
        "en": "ami-0fad524a2dfa324ea"
      },
      "ap-southeast-2": {
        "en": "ami-0afa8b2d07967a13f"
      },
      "ca-central-1": {
        "en": "ami-0ff8a19084e4d8b52"
      },
      "eu-central-1": {
        "en": "ami-01bb24a57d94cd724"
      },
      "eu-west-1": {
        "en": "ami-05321fd947594645a"
      },
      "eu-west-2": {
        "en": "ami-07303a9067e64dcc3"
      },
      "sa-east-1": {
        "en": "ami-01e49dadb5332903e"
      },
      "us-east-1": {
        "en": "ami-0065f8d2ca53a067c"
      },
      "us-east-2": {
        "en": "ami-0ac4bb96c160fc6db"
      },
      "us-west-1": {
        "en": "ami-0285900137b0e8742"
      },
      "us-west-2": {
        "en": "ami-0a16651b975b8dab3"
      }
    }
    },
    "Parameters": {
        "DeploymentBucket": {
            "Description": "S3 bucket for license files and SSL certificates",
            "Type": "String",
            "AllowedPattern": "[a-zA-Z][0-9a-zA-Z-_.]{2,62}",
            "ConstraintDescription": "S3 bucket name must be between 3 and 63 characters and and must start with a letter."
        },
        "DriveSizeRoot": {
            "Default": "100",
            "Description": " The size of the C: Drive in GB. ",
            "Type": "Number",
            "MinValue": "100",
            "MaxValue": "1024",
            "ConstraintDescription": " Must be between 100 and 1024 GB. "
        },
        "DriveSizeData": {
            "Default": "100",
            "Description": " The size of the D: Drive in GB. ",
            "Type": "Number",
            "MinValue": "10",
            "MaxValue": "1024",
            "ConstraintDescription": " Must be between 10 and 1024 GB. "
        },
        "InstanceType": {
            "Description": "The EC2 instance type",
            "Type": "String",
            "AllowedValues": [
                "m3.large", "m3.xlarge", "m3.2xlarge",
                "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge",
                "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge",
                "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge",
                "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge",
                "t2.large", "t2.xlarge", "t2.2xlarge"
            ],
            "Default": "m3.xlarge"
        },
        "BDSInstanceType": {
             "Description": "Spatio-temporal Big Data Store EC2 instance type",
             "Type": "String",
             "AllowedValues": [
                "m3.large", "m3.xlarge", "m3.2xlarge",
                "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge",
                "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge",
                "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge",
                "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge",
                "t2.large", "t2.xlarge", "t2.2xlarge"
             ],
            "Default": "m3.xlarge"
        },
        "BDSInstances" : {
            "Description" : "Number of spatio-temporal Big Data Store EC2 instances",
            "Type" : "Number",
            "Default" : "0",
            "AllowedValues" : [0, 1]
        },
        "KeyName": {
            "Description": "The EC2 KeyPair to allow remote access to the instances",
            "Type": "AWS::EC2::KeyPair::KeyName"
        },
        "StoreType": {
            "Description": "ArcGIS Server config store and Portal for ArcGIS content store type",
            "Type": "String",
            "AllowedValues": ["CloudStore", "FileSystem"],
            "Default": "FileSystem"
        }, 
        "ServerLicenseFile": {
            "Description": "ArcGIS Server authorization file (must be uploaded to DeploymentBucket)",
            "Type": "String",
            "AllowedPattern": "[^\"]{1,1024}",
            "ConstraintDescription": "S3 object key name must be between 1 and 1024 characters."
        },
        "PortalLicenseFile": {
            "Description": "Portal for ArcGIS authorization file (must be uploaded to DeploymentBucket)",
            "Type": "String",
            "AllowedPattern": "[^\"]{1,1024}",
            "ConstraintDescription": "S3 object key name must be between 1 and 1024 characters."
        },
        "SiteAdmin": {
            "Description": "User name for ArcGIS Server site admin and Portal initial admin accounts",
            "Type": "String",
            "Default": "admin",
            "AllowedPattern": "[0-9a-zA-Z.]{4,24}",
            "ConstraintDescription": "User name must be between 4 and 24 characters and can only contain digits 0 through 9, ASCII letters A through Z (uppercase and lowercase), and a dot (.)."
        },
        "SiteAdminPassword": {
            "Description": "Password for the site admin account",
            "Type": "String",
            "NoEcho": "true",
            "AllowedPattern": "[0-9a-zA-Z.]{4,24}",
            "ConstraintDescription": "Password must be between 4 and 24 characters and can only contain digits 0 through 9, ASCII letters A through Z (uppercase and lowercase), and a dot (.)."
        },
        "SiteEIPAllocationID": {
            "Description": "Allocation ID of Elastic IP address for VPC (eipalloc-XXXXXXXX)",
            "Type": "String",
            "AllowedPattern": "eipalloc-.*"
        },
        "RunAsUserPassword" : {
            "Description" : "Password for ArcGIS account",
            "Type" : "String",
            "NoEcho" : "true",
            "AllowedPattern": "(?!.*arcgis)(?!.*Arc)(?!.*GIS)(?!.*user)(?!.*account)(?=[^\\\\\\\"]{8,})(?=.*?[^\\w\\s])(?=.*?[0-9])(?=.*?[A-Z]).*?[a-z].*",
            "ConstraintDescription": "Password must be at least eight characters in length and must contain characters from three of the following four categories: English uppercase characters (A through Z), English lowercase characters (a through z), digits (0 through 9), non-alphabetic characters (for example, !, $, #, %). Password must not contain backslashes (\\) or quotation marks (\"). Password must not contain the user's account name (arcgis) or parts of the user's full name (ArcGIS user account) that exceed two consecutive characters."
        },
        "SiteDomain": {
            "Description": "The domain name of your ArcGIS site",
            "Type": "String",
            "AllowedPattern": "[^\\\"\/]{1,253}",
            "ConstraintDescription": "The domain name is invalid."
        },
        "SSLCertificateFile": {
            "Description": "SSL certificate file issued to the site domain (must be uploaded to DeploymentBucket)",
            "Type": "String",
            "AllowedPattern": "[^\"]{1,1024}",
            "ConstraintDescription": "S3 object key name must be between 1 and 1024 characters."
        },
        "SSLCertPassword": {
            "Description": "SSL certificate file password",
            "Type": "String",
            "NoEcho": "true",
            "AllowedPattern": "[^\\\"]{1,128}",
            "ConstraintDescription": "Password must be between 1 and 128 characters and must not contain backslashes (\\) or quotation marks (\")."
        },
        "VPCId" : {
            "Description" : "VPC ID",
            "Type" : "AWS::EC2::VPC::Id" 
        },
        "Subnet" : {
            "Description" : "VPC Subnet ID",
            "Type": "AWS::EC2::Subnet::Id"
        },
        "PostInstallationScript": {
            "Description": "ZIP archive file with custom post installation script (must be uploaded to DeploymentBucket).",
            "Type": "String",
            "AllowedPattern": "[^\"]{1,1024}",
            "ConstraintDescription": "S3 object key name must be between 1 and 1024 characters.",
            "Default": "none"
        }
    },
    "Metadata" : {
      "AWS::CloudFormation::Interface" : {
        "ParameterGroups" : [ {
          "Label" : { "default" : "Network Configuration" },
          "Parameters" : [ "VPCId", "Subnet", "SiteDomain", "SiteEIPAllocationID" ]
        },
        {
          "Label" : { "default":"Amazon EC2 Configuration" },
          "Parameters" : [ "InstanceType", "BDSInstanceType", "BDSInstances", "DriveSizeRoot", "DriveSizeData", "KeyName" ]
        },
        {
          "Label" : { "default":"ArcGIS Enterprise Configuration" },
          "Parameters" : [ "DeploymentBucket", "ServerLicenseFile", "PortalLicenseFile", "StoreType", "SiteAdmin", "SiteAdminPassword", "RunAsUserPassword", "SSLCertificateFile", "SSLCertPassword" ]
        } ]
      }
    },
    "Conditions" : {
        "UseCloudStore" : {"Fn::Equals" : [{"Ref" : "StoreType"}, "CloudStore"]},
        "RunPostInstall" : {"Fn::Not" : [{"Fn::Equals" : [{"Ref" : "PostInstallationScript"}, "none"]}]},
        "SSMSupported" : {"Fn::Not" : [{"Fn::Or": [{"Fn::Equals" : [{"Ref" : "AWS::Region"}, "eu-west-2"]},
                                                   {"Fn::Equals" : [{"Ref" : "AWS::Region"}, "ap-south-1"]},
                                                   {"Fn::Equals" : [{"Ref" : "AWS::Region"}, "ca-central-1"]}]}]}
    },
    "Resources": {
        "ValidateParametersFunction": {
          "Type": "AWS::Lambda::Function",
          "DependsOn": "IAMRole",
          "Properties": {
            "Code": {
              "S3Bucket": {"Fn::Join" : ["", ["arcgisstore1051", "-", {"Ref": "AWS::Region"}]]},
              "S3Key": "7333/lambda/arcgis-cfn-lambda-python3.zip"
            },
            "Handler": "parameters.handler",
            "Runtime": "python3.8",
            "Timeout": "300",
            "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }
          }
        },
        "StopStackFunction": {
          "Type": "AWS::Lambda::Function",
          "DependsOn": "IAMRole",
          "Properties": {
            "Code": {
              "S3Bucket": {"Fn::Join" : ["", ["arcgisstore1051", "-", {"Ref": "AWS::Region"}]]},
              "S3Key": "7333/lambda/arcgis-cfn-lambda-python3.zip"
            },
            "Environment" : {
              "Variables" : {
                "StackName" : {"Ref" : "AWS::StackName"}
              }
            }, 
            "Handler": "stop_start.stop_allinone_stack",
            "Runtime": "python3.8",
            "Timeout": "300",
            "Role": {"Fn::GetAtt" : ["LambdaExecutionRole", "Arn"]},
            "Description" : "Stops all EC2 instances of the CloudFormation stack"
          }
        },
        "StartStackFunction": {
          "Type": "AWS::Lambda::Function",
          "DependsOn": "IAMRole",
          "Properties": {
            "Code": {
              "S3Bucket": {"Fn::Join" : ["", ["arcgisstore1051", "-", {"Ref": "AWS::Region"}]]},
              "S3Key": "7333/lambda/arcgis-cfn-lambda-python3.zip"
            },
            "Environment" : {
              "Variables" : {
                "StackName" : {"Ref" : "AWS::StackName"}
              }
            }, 
            "Handler": "stop_start.start_allinone_stack",
            "Runtime": "python3.8",
            "Timeout": "300",
            "Role": {"Fn::GetAtt" : ["LambdaExecutionRole", "Arn"]},
            "Description" : "Starts all EC2 instances of the CloudFormation stack"
          }
        },
        "LambdaExecutionRole": {
          "Type": "AWS::IAM::Role",
          "Properties": {
            "AssumeRolePolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [{
                "Effect": "Allow",
                "Principal": {"Service": ["lambda.amazonaws.com"]},
                "Action": ["sts:AssumeRole"]
              }]
            },
            "Path": "/",
            "Policies": [{
              "PolicyName": "root",
              "PolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [{
                  "Effect": "Allow",
                  "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],
                  "Resource": "arn:aws:logs:*:*:*"
                },
                {
                  "Effect": "Allow",
                  "Action": ["dynamodb:*"],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": ["s3:*"],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": ["ec2:*"],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": ["cloudformation:*"],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": ["autoscaling:*"],
                  "Resource": "*"
                }]
              }
            }]
          }
        },
        "ValidateServerLicenseFile": {
          "Type": "Custom::ValidateParameters",
          "Properties": {
            "ServiceToken": {"Fn::GetAtt": ["ValidateParametersFunction", "Arn"]},
            "DeploymentBucket": {"Ref": "DeploymentBucket"},
            "S3Key": {"Ref": "ServerLicenseFile"}
          }
        },
        "ValidatePortalLicenseFile": {
          "Type": "Custom::ValidateParameters",
          "DependsOn": "ValidateServerLicenseFile",
          "Properties": {
            "ServiceToken": {"Fn::GetAtt": ["ValidateParametersFunction", "Arn"]},
            "DeploymentBucket": {"Ref": "DeploymentBucket"},
            "S3Key": {"Ref": "PortalLicenseFile"}
          }
        },
        "ValidateSSLCertificateFile": {
          "Type": "Custom::ValidateParameters",
          "DependsOn": "ValidatePortalLicenseFile",
          "Properties": {
            "ServiceToken": {"Fn::GetAtt": ["ValidateParametersFunction", "Arn"]},
            "DeploymentBucket": {"Ref": "DeploymentBucket"},
            "S3Key": {"Ref": "SSLCertificateFile"}
          }
        },
        "ValidatePostInstallationScript": {
          "Type": "Custom::ValidateParameters",
          "Condition": "RunPostInstall",
          "Properties": {
            "ServiceToken": {"Fn::GetAtt": ["ValidateParametersFunction", "Arn"]},
            "DeploymentBucket": {"Ref": "DeploymentBucket"},
            "S3Key": {"Ref": "PostInstallationScript"}
          }
        },
        "ServerConfigStoreFunction": {
          "Type": "AWS::Lambda::Function",
          "DependsOn": "IAMRole",
          "Properties": {
            "Code": {
              "S3Bucket": {"Fn::Join" : ["", ["arcgisstore1051", "-", {"Ref": "AWS::Region"}]]},
              "S3Key": "7333/lambda/arcgis-cfn-lambda-python3.zip"
            },
            "Handler": "server_config_store.handler",
            "Runtime": "python3.8",
            "Timeout": "30",
            "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }
          }
        },
        "ServerConfigStore": {
          "Type": "Custom::ServerConfigStore",
          "Properties": {
            "ServiceToken": {"Fn::GetAtt": ["ServerConfigStoreFunction", "Arn"]},
            "Namespace": {"Fn::Join" : ["", [{"Ref" : "AWS::StackName"}]]}
          }
        },
        "DeploymentLogs": {
            "Type": "AWS::Logs::LogGroup",
            "DependsOn": "ValidateSSLCertificateFile",
            "Properties": {
                "RetentionInDays": 7
            }
        },
        "EIPAssociation": {
            "Type": "AWS::EC2::EIPAssociation",
            "DependsOn": "WaitCondition",
            "Properties": {
                "AllocationId": {"Ref": "SiteEIPAllocationID"},
                "InstanceId": {"Ref": "AllInOneEC2Instance"}
            }
        },
        "IAMRole": {
            "Type": "AWS::IAM::Role",
            "DependsOn": "LambdaExecutionRole",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Statement": [ {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": [ "ec2.amazonaws.com" ]
                        },
                        "Action": [ "sts:AssumeRole" ]
                    } ]
                },
                "Path": "/"
            }
        },
        "IAMPolicy": {
            "Type": "AWS::IAM::Policy",
            "Properties": {
                "PolicyName": "IAMRole",
                "PolicyDocument": {
                    "Statement": [ {
                            "Action": [ "s3:*", "dynamodb:*", "cloudformation:*", "logs:*", "ssm:*", "ec2messages:*" ],
                            "Effect": "Allow",
                            "Resource": "*"
                        }
                    ]
                },
                "Roles": [ {"Ref": "IAMRole"} ]
            }
        },
        "IAMInstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [ {"Ref": "IAMRole"} ]
            }
        },
        "SecurityGroup" : {
          "Type" : "AWS::EC2::SecurityGroup",
          "Properties" : {
            "GroupDescription" : {"Ref" : "AWS::StackName"},
            "VpcId" : {"Ref" : "VPCId"},
            "SecurityGroupIngress" : [ {
              "IpProtocol" : "tcp",
              "FromPort" : "80",
              "ToPort" : "80",
              "CidrIp" : "0.0.0.0/0"
            }, {
              "IpProtocol" : "tcp",
              "FromPort" : "443",
              "ToPort" : "443",
              "CidrIp" : "0.0.0.0/0"
            } ]
          }
        },
        "SecurityGroupIngress" : {
          "Type" : "AWS::EC2::SecurityGroupIngress",
          "Properties" : {
            "GroupId" : {"Ref" : "SecurityGroup"},
            "IpProtocol" : "tcp",
            "FromPort" : "0",
            "ToPort" : "65535",
            "SourceSecurityGroupId" : {"Ref" : "SecurityGroup"}
          }
        },
        "PortalContent": {
            "Type": "AWS::S3::Bucket",
            "Condition" : "UseCloudStore",
            "DeletionPolicy": "Retain",
            "Properties": {
                "Tags": [ {
                    "Key": "Name",
                    "Value": {"Ref": "AWS::StackName"}
                }, {
                    "Key": "Application",
                    "Value": "arcgis-allinone-windows"
                }]
          }
        }, 
        "AllInOneEC2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {"Fn::FindInMap" : ["RegionMap", {"Ref":"AWS::Region"}, "en"]},
                "InstanceType": {"Ref": "InstanceType"},
                "KeyName": {"Ref": "KeyName"},
                "IamInstanceProfile": {"Ref": "IAMInstanceProfile"},
                "Tags": [ {
                    "Key": "Name",
                    "Value": {"Ref": "AWS::StackName"}
                }, {
                    "Key": "Application",
                    "Value": "arcgis-allinone-windows"
                }],
                "Monitoring": true,
                "BlockDeviceMappings": [ {
                    "DeviceName": "/dev/sda1",
                    "Ebs": {
                        "VolumeSize": {"Ref": "DriveSizeRoot"},
                        "DeleteOnTermination": true,
                        "VolumeType": "gp2"
                    }
                }, {
                   "DeviceName": "xvdg",
                   "Ebs": {
                        "VolumeSize": {"Ref": "DriveSizeData"},
                        "DeleteOnTermination": true,
                        "VolumeType": "gp2"
                   }
                },{
                    "DeviceName": "xvdca",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcb",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcc",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcd",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdce",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcf",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcg",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdch",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdci",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcj",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdck",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcl",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcm",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcn",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdco",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcp",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcq",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcr",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcs",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdct",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcu",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcv",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcw",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcx",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcy",
                    "NoDevice": {}
                },{
                    "DeviceName": "xvdcz",
                    "NoDevice": {}
                } ],
                "NetworkInterfaces": [ {
                    "GroupSet": [ {"Ref": "SecurityGroup"} ],
                    "AssociatePublicIpAddress": "true",
                    "DeviceIndex": "0",
                    "DeleteOnTermination": "true",
                    "SubnetId": {"Ref": "Subnet"}
                } ],
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "",
                            [
                                "<powershell>\r\n",
                                "try \r\n",
                                "{\r\n",
                                "  if (", {"Fn::If": ["RunPostInstall", "$true", "$false"]}, ") {\r\n",
                                "    cfn-init -v -c post-install-script -s ", {"Ref": "AWS::StackName"}, " -r CloudWatchSettings", " --region ", {"Ref": "AWS::Region"}, "\r\n",
                                "  }\r\n",
                                "  $stackName   = '", {"Ref": "AWS::StackName"}, "' \r\n",
                                "  $region      = '", {"Ref": "AWS::Region"}, "' \r\n",
                                "  $waitHandle  = '", {"Ref": "WaitHandle"}, "' \r\n",
                                "  $InstanceName = 'AllInOneEC2Instance' \r\n",
                                "  $NodeJSONPath = 'C:\\\\chef\\\\node.json' \r\n",
                                "  $ChefLogFile  = 'C:\\\\chef\\\\chef-run.log' \r\n",
                                "  $execName = \"cfn-init\" \r\n",
                                "  $execArgs = \"-v -s $stackName -r CloudWatchSettings --region $region\" \r\n",
                                "  $process = Start-Process $execName -PassThru -Wait -ArgumentList $execArgs.Split(' ') \r\n",
                                "  if ($process.ExitCode -ne 0) { \r\n",
                                "    throw \"Process 'cfn-init' exit code : $($process.ExitCode)\"   \r\n",
                                "  } \r\n",
                                " \r\n",
                                "  $execArgs = \"-v -s $stackName -r $InstanceName --region $region\" \r\n",
                                "  $process = Start-Process $execName -PassThru -Wait -ArgumentList $execArgs.Split(' ') \r\n",
                                "  if ($process.ExitCode -ne 0) { \r\n",
                                "    throw \"Process 'cfn-init' exit code : $($process.ExitCode)\" \r\n",
                                "  } \r\n",
                                " \r\n",
                                "  $process = Start-Process chef-solo -PassThru -Wait  -ArgumentList (\"-j\", $NodeJSONPath, \"-L\",$ChefLogFile, \"-l\", \"info\") \r\n",
                                "  if ($process.ExitCode -ne 0) { \r\n",
                                "    throw \"Chef run failed. See 'C:\\\\chef\\\\chef-run.log' for details.\" \r\n",
                                "  } \r\n",
                                " \r\n",
                                "  $process = Start-Process cfn-signal -PassThru -Wait -ArgumentList $waitHandle \r\n",
                                "  if ($process.ExitCode -ne 0) { \r\n",
                                "    throw \"Process 'cfn-signal' exit code : $($process.ExitCode)\" \r\n",
                                "  } \r\n",
                                "}   \r\n",
                                "catch  \r\n",
                                "{  \r\n",
                                "  Write-Output \"ERROR: $($_.Exception.Message)\"  \r\n",
                                "  cfn-signal -e 1  -r \"$($_.Exception.Message)\" \"$WaitHandle\"  \r\n",
                                "}  \r\n",
                                "</powershell>\r\n"
                            ]
                        ]
                    }
                }
            },
            "Metadata": {
                "AWS::CloudFormation::Authentication": {
                    "S3AccessCreds": {
                        "type": "S3",
                        "buckets": [ {"Ref": "DeploymentBucket"} ],
                        "roleName": {"Ref": "IAMRole"}
                    }
                },
                "AWS::CloudFormation::Init": {
                    "config": {
                        "commands": {
                            "rename-server-license": {
                                "command": {"Fn::Join": [ "", [ "move C:\\Temp\\server_license.tmp C:\\Temp\\", {"Ref": "ServerLicenseFile"} ] ]}
                            },
                            "rename-portal-license": {
                                "command": {"Fn::Join": [ "", [ "move C:\\Temp\\portal_license.tmp C:\\Temp\\", {"Ref": "PortalLicenseFile"} ] ]}
                            }
                        },
                        "files": {
                            "C:\\Temp\\server_license.tmp": {
                                "source": {"Fn::GetAtt": [ "ValidateServerLicenseFile", "S3ObjectURL" ]},
                                "authentication": "S3AccessCreds"
                            },
                            "C:\\Temp\\portal_license.tmp": {
                                "source": {"Fn::GetAtt": [ "ValidatePortalLicenseFile", "S3ObjectURL" ]},
                                "authentication": "S3AccessCreds"
                            },
                            "C:\\Temp\\keystore.pfx": {
                                "source": {"Fn::GetAtt": [ "ValidateSSLCertificateFile", "S3ObjectURL" ]},
                                "authentication": "S3AccessCreds"
                            },
                            "C:\\chef\\node.json": {
                                "content": {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "{\r\n",
                                            "  \"arcgis\" : {\r\n",
                                            "    \"run_as_password\" : \"", {"Ref" : "RunAsUserPassword"}, "\",\r\n",
                                            "    \"post_install_script\" : \"D:\\\\PostInstallScripts\\\\deploy.bat\",\r\n",
                                            "    \"hosts\" : {\r\n",
                                            "      \"", {"Ref": "SiteDomain"}, "\" : \"\"\r\n",
                                            "    },\r\n",
                                            "    \"iis\" : {\r\n",
                                            "      \"keystore_file\" : \"C:\\\\Temp\\\\keystore.pfx\",\r\n",
                                            "      \"keystore_password\" : \"", {"Ref": "SSLCertPassword"}, "\",\r\n",
                                            "      \"replace_https_binding\" : true\r\n",
                                            "    },\r\n",
                                            "    \"server\" : {\r\n",
                                            "      \"domain_name\" : \"", {"Ref": "SiteDomain"}, "\",\r\n",
                                            "      \"wa_url\" : \"https://", {"Ref": "SiteDomain"}, "/server\",\r\n",
                                            "      \"private_url\" : \"https://", {"Ref": "SiteDomain"}, "/server\",\r\n",
                                            "      \"web_context_url\" : \"https://", {"Ref": "SiteDomain"}, "/server\",\r\n",
                                            "      \"admin_username\" : \"", {"Ref": "SiteAdmin"}, "\",\r\n",
                                            "      \"admin_password\" : \"", {"Ref": "SiteAdminPassword"}, "\",\r\n",
                                            "      \"directories_root\" : \"D:\\\\arcgisserver\",\r\n",
                                            "      \"log_dir\" : \"D:\\\\arcgisserver\\\\logs\",\r\n",
                                            "      \"config_store_type\" : \"", {"Fn::If": ["UseCloudStore", "AMAZON", "FILESYSTEM"]}, "\",\r\n",
                                            "      \"config_store_connection_string\" : \"", {"Fn::If": ["UseCloudStore",
                                              {"Fn::Join" : ["", ["NAMESPACE=", {"Ref" : "AWS::StackName"}, ";REGION=", { "Ref" : "AWS::Region" } ]]},
                                              "D:\\\\arcgisserver\\\\config-store"]}, "\",\r\n",
                                            "      \"authorization_file\" : \"C:\\\\Temp\\\\", {"Ref": "ServerLicenseFile"}, "\"\r\n",
                                            "    },\r\n",
                                            "    \"web_adaptor\" : {\r\n",
                                            "      \"admin_access\" : true\r\n",
                                            "    },\r\n",
                                            "    \"data_store\" : {\r\n",
                                            "      \"data_dir\" : \"D:\\\\arcgisdatastore\"\r\n",
                                            "    },\r\n",
                                            "    \"portal\" : {\r\n",
                                            "      \"domain_name\" : \"", {"Ref": "SiteDomain"}, "\",\r\n",
                                            "      \"wa_url\" : \"https://", {"Ref": "SiteDomain"}, "/portal\",\r\n",
                                            "      \"private_url\" : \"https://", {"Ref": "SiteDomain"}, "/portal\",\r\n",
                                            "      \"web_context_url\" : \"https://", {"Ref": "SiteDomain"}, "/portal\",\r\n",
                                            "      \"admin_username\" : \"", {"Ref": "SiteAdmin"}, "\",\r\n",
                                            "      \"admin_password\" : \"", {"Ref": "SiteAdminPassword"}, "\",\r\n",
                                            "      \"data_dir\" : \"D:\\\\arcgisportal\",\r\n",
                                            "      \"content_store_type\" : \"", {"Fn::If": ["UseCloudStore", "cloudStore", "fileStore"]}, "\",\r\n",
                                            "      \"content_store_provider\" : \"", {"Fn::If": ["UseCloudStore", "Amazon", "FileSystem"]}, "\",\r\n",
                                            "      \"content_store_connection_string\" : ", {"Fn::If": ["UseCloudStore", 
                                                      {"Fn::Join" : ["", ["{\"region\": \"", {"Ref" : "AWS::Region"}, "\", \"credentialType\": \"IAMRole\"}"]]}, 
                                                      "\"D:\\\\arcgisportal\\\\content\""]}, ",\r\n",
                                            "      \"object_store\" : \"", {"Fn::If": ["UseCloudStore", {"Ref": "PortalContent"}, ""]}, "\",\r\n",
                                            "      \"authorization_file\" : \"C:\\\\Temp\\\\", {"Ref": "PortalLicenseFile"}, "\"\r\n",
                                            "    }\r\n",
                                            "  },\r\n",
                                            "  \"run_list\" : [\r\n",
                                            "    \"recipe[arcgis-enterprise::system]\",\r\n",
                                            "    \"recipe[esri-iis]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::server]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::server_wa]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::datastore]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::portal]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::portal_wa]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::federation]\",\r\n",
                                            "    \"recipe[arcgis-enterprise::post_install]\"]\r\n",
                                            "}\r\n"
                                        ]
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        },
        "EC2InstanceRecoveryAlarm" : {
            "Type" : "AWS::CloudWatch::Alarm",
            "Properties" : {
                "AlarmDescription" : "Trigger a recovery when instance status check fails for 5 consecutive minutes.",
                "MetricName" : "StatusCheckFailed_System",
                "Namespace" : "AWS/EC2",
                "Statistic" : "Minimum",
                "Period" : "60",
                "EvaluationPeriods" : "5",
                "Threshold" : "0",
                "ComparisonOperator" : "GreaterThanThreshold",
                "AlarmActions" : [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
                "Dimensions" : [ {
                    "Name" : "InstanceId",
                    "Value" : {"Ref" : "AllInOneEC2Instance"}
                } ]
            }
        },
        "WaitHandle": {
            "Type": "AWS::CloudFormation::WaitConditionHandle",
            "Properties": {}
        },
        "WaitCondition": {
            "Type": "AWS::CloudFormation::WaitCondition",
            "Properties": {
                "Handle": {"Ref": "WaitHandle"},
                "Timeout": "7200"
            }
        },
       "LaunchConfig" : {
         "Type" : "AWS::AutoScaling::LaunchConfiguration",
         "DependsOn" : "WaitCondition",
         "Properties" : {
           "AssociatePublicIpAddress" : true,
           "ImageId" : {"Fn::FindInMap" : ["RegionMap", {"Ref":"AWS::Region"}, "en"]},
           "InstanceType" : {"Ref" : "BDSInstanceType"},
           "KeyName" : {"Ref" : "KeyName"},
           "IamInstanceProfile" : {"Ref" : "IAMInstanceProfile"},
           "SecurityGroups" : [ {"Ref": "SecurityGroup"} ],
           "InstanceMonitoring" : true,
           "BlockDeviceMappings": [ {
             "DeviceName": "/dev/sda1",
             "Ebs": {
               "VolumeSize": {"Ref": "DriveSizeRoot"},
               "DeleteOnTermination": true,
               "VolumeType": "gp2"
             }
           }, {
             "DeviceName": "xvdg",
             "Ebs": {
               "VolumeSize": {"Ref": "DriveSizeData"},
               "DeleteOnTermination": true,
               "VolumeType": "gp2"
             }
           }],
           "UserData" : {
             "Fn::Base64" : {
               "Fn::Join" : [
                 "",
                 [
                    "<powershell>\r\n",
                    "try \r\n",
                    "{  \r\n",
                    "  $stackName   = '", {"Ref": "AWS::StackName"}, "' \r\n",
                    "  $region      = '", {"Ref": "AWS::Region"}, "' \r\n",
                    "  $waitHandle  = '", {"Ref" : "AutoScalingGroupWaitHandle"}, "'\r\n",
                    "  $InstanceName = 'LaunchConfig'\r\n",
                    "  $NodeJSONPath = 'C:\\\\chef\\\\node.json' \r\n",
                    "  $ChefLogFile  = 'C:\\\\chef\\\\chef-run.log' \r\n",
                    "  $execName = \"cfn-init\" \r\n",
                    "  $execArgs = \"-v -s $stackName -r CloudWatchSettings --region $region\" \r\n",
                    "  $process = Start-Process $execName -PassThru -Wait -ArgumentList $execArgs.Split(' ') \r\n",
                    "  if ($process.ExitCode -ne 0) { \r\n",
                    "    throw \"Process 'cfn-init' exit code : $($process.ExitCode)\"   \r\n",
                    "  } \r\n",
                    " \r\n",
                    "  $execArgs = \"-v -s $stackName -r $InstanceName --region $region\" \r\n",
                    "  $process = Start-Process $execName -PassThru -Wait -ArgumentList $execArgs.Split(' ') \r\n",
                    "  if ($process.ExitCode -ne 0) { \r\n",
                    "    throw \"Process 'cfn-init' exit code : $($process.ExitCode)\" \r\n",
                    "  } \r\n",
                    " \r\n",
                    "  $process = Start-Process chef-solo -PassThru -Wait  -ArgumentList (\"-j\", $NodeJSONPath, \"-L\",$ChefLogFile, \"-l\", \"info\") \r\n",
                    "  if ($process.ExitCode -ne 0) { \r\n",
                    "    throw \"Chef run failed. See 'C:\\\\chef\\\\chef-run.log' for details.\" \r\n",
                    "  } \r\n",
                    " \r\n",
                    "  $process = Start-Process cfn-signal -PassThru -Wait -ArgumentList $waitHandle \r\n",
                    "  if ($process.ExitCode -ne 0) { \r\n",
                    "    throw \"Process 'cfn-signal' exit code : $($process.ExitCode)\" \r\n",
                    "  } \r\n",
                    "}   \r\n",
                    "catch  \r\n",
                    "{  \r\n",
                    "  Write-Output \"ERROR: $($_.Exception.Message)\"  \r\n",
                    "  cfn-signal -e 1  -r \"$($_.Exception.Message)\" \"$WaitHandle\"  \r\n",
                    "}  \r\n",
                    "</powershell>\r\n"
                 ]
               ]
             }
           }
         },
         "Metadata" : {
           "AWS::CloudFormation::Authentication" : {
             "S3AccessCreds" : {
               "type" : "S3",
               "buckets" : [ {"Ref" : "DeploymentBucket"} ],
               "roleName" : {"Ref" : "IAMRole"}
             }
           },
           "AWS::CloudFormation::Init" : {
             "config" : {
               "files" : {
                 "C:\\chef\\node.json" : {
                   "content" : {
                     "Fn::Join" : [ "", [
                       "{\r\n",
                       "  \"arcgis\" : {\r\n",
                       "    \"run_as_password\" : \"", {"Ref" : "RunAsUserPassword"}, "\",\r\n",
                       "    \"server\" : {\r\n",
                       "      \"admin_username\" : \"", {"Ref" : "SiteAdmin"}, "\",\r\n",
                       "      \"admin_password\" : \"", {"Ref" : "SiteAdminPassword" }, "\",\r\n",
                       "      \"domain_name\" : \"", { "Fn::GetAtt" : [ "AllInOneEC2Instance", "PrivateIp" ] }, "\",\r\n",
                       "      \"private_url\" : \"https://", { "Fn::GetAtt" : [ "AllInOneEC2Instance", "PrivateIp" ] }, ":6443/arcgis\"\r\n",
                       "    },\r\n",
                       "    \"data_store\" : {\r\n",
                       "      \"types\" : \"spatiotemporal\",\r\n",
                       "      \"preferredidentifier\" : \"ip\",\r\n",
                       "      \"data_dir\" : \"D:\\\\arcgisdatastore\",\r\n",
                       "      \"backup_dir\" : \"\\\\\\\\", { "Fn::GetAtt" : [ "AllInOneEC2Instance", "PrivateIp" ] }, "\\\\data\\\\arcgisdatastore\\\\backup\"\r\n",
                       "    }\r\n",
                       "  },\r\n",
                       "  \"run_list\" : [\r\n",
                       "    \"recipe[arcgis-enterprise::datastore]\"]\r\n",
                       "}\r\n" ] ]
                   }
                 }
               }
             }
           }
         }
       },
       "AutoScalingGroup" : {
         "Type" : "AWS::AutoScaling::AutoScalingGroup",
         "Properties" : {
           "VPCZoneIdentifier" : [ {"Ref" : "Subnet"} ],
           "Cooldown" : "300",
           "MaxSize" : {"Ref" : "BDSInstances"},
           "MinSize" : {"Ref" : "BDSInstances"},
           "LaunchConfigurationName" : {"Ref" : "LaunchConfig"},
           "HealthCheckType" : "EC2",
           "HealthCheckGracePeriod" : "3600",
           "Tags" : [ {
             "Key" : "Name",
             "Value" : {"Fn::Join" : ["", [{"Ref" : "AWS::StackName"}, "-bds"]]},
             "PropagateAtLaunch" : true
           } ]
         },
         "UpdatePolicy": {
           "AutoScalingReplacingUpdate": {
             "WillReplace": "true"
           }
         }
       },
       "AutoScalingGroupWaitHandle" : {
         "Type" : "AWS::CloudFormation::WaitConditionHandle",
         "Properties" : {}
       },
       "AutoScalingGroupWaitCondition" : {
         "Type" : "AWS::CloudFormation::WaitCondition",
         "DependsOn" : "LaunchConfig",
         "Properties" : {
           "Count" : {"Ref" : "BDSInstances"},
           "Handle" : {"Ref" : "AutoScalingGroupWaitHandle"},
           "Timeout" : "10800"
         }
       },
       "CloudWatchSettings": {
            "Type": "AWS::Logs::MetricFilter",
            "Properties": {
                "LogGroupName": {"Ref": "DeploymentLogs"},
                "FilterPattern": "[level=FATAL, message]",
                "MetricTransformations": [
                    {
                        "MetricValue": "1",
                        "MetricNamespace": "ArcGIS/Deployment",
                        "MetricName": "ErrorCount"
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Init": {
                    "configSets" : {
                        "default": ["config"],
                        "post-install-script": ["post-install-config"]
                    },
                    "post-install-config": {
                        "sources" : {
                            "D:\\PostInstallScripts" : {"Fn::If": ["RunPostInstall", {"Fn::GetAtt": [ "ValidatePostInstallationScript", "S3ObjectURL" ]}, ""]}
                        }
                    },
                    "config": {
                        "sources": {
                            "C:\\chef": "https://arcgisstore1051.s3.amazonaws.com/7333/cookbooks/arcgis-3.1.0-cookbooks.zip",
                            "C:\\Program Files\\Amazon\\cfn-bootstrap" : "https://arcgisstore1051.s3.amazonaws.com/endpoints.zip"
                        }
                    }
                }
            }
        },
        "SSMDocument" : {
          "Type" : "AWS::SSM::Document",
          "Condition" : "SSMSupported",
          "Properties" : {
          "DocumentType" : "Command",
          "Content" : {
            "schemaVersion": "2.0",
            "description": "CloudWatch Logs tasks",
            "mainSteps": [
             {
              "action" :"aws:cloudWatch",
              "name": "cloudWatch",
              "settings": {
                "startType": "Enabled"
              },
              "inputs": {
                  "EngineConfiguration": {
                  "PollInterval": "00:00:15",
                  "Components": [ {
                    "Id": "CfnInitLogStream",
                    "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                    "Parameters": {
                      "Region": { "Ref": "AWS::Region" },
                      "LogGroup": { "Ref": "DeploymentLogs" },
                      "LogStream": "{instance_id}/cfn-init.log"
                    }
                  },
                  {
                    "Id": "ChefRunLogStream",
                    "FullName": "AWS.EC2.Windows.CloudWatch.CloudWatchLogsOutput,AWS.EC2.Windows.CloudWatch",
                    "Parameters": {
                      "Region": { "Ref": "AWS::Region" },
                      "LogGroup": { "Ref": "DeploymentLogs" },
                      "LogStream": "{instance_id}/chef-run.log"
                    }
                  },
                  {
                    "Id": "CfnInitLogs",
                    "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                    "Parameters": {
                      "LogDirectoryPath": "C:\\cfn\\log",
                      "TimestampFormat": "yyyy-MM-dd HH:mm:ss,fff",
                      "Encoding": "UTF-8",
                      "Filter": "cfn-init.log",
                      "CultureName": "en-US",
                      "TimeZoneKind": "Local",
                      "LineCount": "1"
                    }
                  },
                  {
                    "Id": "ChefRunLogs",
                    "FullName": "AWS.EC2.Windows.CloudWatch.CustomLog.CustomLogInputComponent,AWS.EC2.Windows.CloudWatch",
                    "Parameters": {
                      "LogDirectoryPath": "C:\\chef",
                      "TimestampFormat": "[yyyy-MM-ddTHH:mm:sszzz]",
                      "Encoding": "UTF-8",
                      "Filter": "chef-run.log",
                      "CultureName": "en-US",
                      "TimeZoneKind": "Local",
                      "LineCount": "1"
                    }
                  }],
                  "Flows": {
                    "Flows":["CfnInitLogs,CfnInitLogStream", "ChefRunLogs,ChefRunLogStream"]
                  }
                }
              }
            },
            {
              "action": "aws:runPowerShellScript",
              "name": "runPowerShellScript",
              "inputs": {
                "runCommand": ["Start-Sleep -s 30;echo EOF >> C:\\chef\\chef-run.log; echo EOF >> C:\\cfn\\log\\cfn-init.log"]
              }
            }]
          }
        }
      },
      "SSMAssociation": {
        "Type": "AWS::SSM::Association",
        "Condition" : "SSMSupported",
        "Properties": {
          "Name": { "Ref": "SSMDocument" },
          "Targets": [{
            "Key": "tag:aws:cloudformation:stack-id",
            "Values": [{"Ref": "AWS::StackId"}]
          }]
        }
      }
    },
    "Outputs": {
        "AdminURL": {
            "Value": {"Fn::Join": [ "", [ "https://", {"Ref": "SiteDomain"}, "/server/manager" ] ]},
            "Description": "ArcGIS Server Administrator Directory URL"
        },
        "RestURL": {
            "Value": {"Fn::Join": [ "", [ "https://", {"Ref": "SiteDomain"}, "/server/rest" ] ]},
            "Description": "ArcGIS REST Services Directory URL"
        },
        "PortalURL": {
            "Value": {"Fn::Join": [ "", [ "https://", {"Ref": "SiteDomain"}, "/portal/home" ] ]},
            "Description": "Portal for ArcGIS Home URL"
        },
        "LogsURL": {
            "Value": {"Fn::Join": ["", [ "https://console.aws.amazon.com/cloudwatch/home?region=", {"Ref": "AWS::Region"}, "#logStream:group=", {"Ref": "DeploymentLogs"} ] ]},
            "Description": "Deployment Logs"
        },
        "StopStackFunction": {
          "Value" : {"Fn::Join": ["", [ "https://console.aws.amazon.com/lambda/home?region=", {"Ref": "AWS::Region"}, "#/functions/", {"Ref": "StopStackFunction"} ] ]},
          "Description" : "Lambda function used to stop all EC2 instances in the stack."
        },
        "StartStackFunction": {
          "Value" : {"Fn::Join": ["", [ "https://console.aws.amazon.com/lambda/home?region=", {"Ref": "AWS::Region"}, "#/functions/", {"Ref": "StartStackFunction"} ] ]},
          "Description" : "Lambda function used to start all EC2 instances in the stack."
        }
    }
}
