Infrastructure & Automation

Building a Microsoft test environment using nested Quick Starts

To test their Windows applications, developers typically need a test environment that closely mimics the target production environment. Aspects common to Windows test environments include a network, an Active Directory deployment, a Microsoft SQL Server deployment, a Microsoft Exchange Server deployment, a Microsoft SharePoint deployment, and other common Microsoft workloads.

While AWS customers can build Microsoft test environments on AWS manually, they can save significant time by using existing Microsoft Quick Starts as nested stacks. That automates much of the deployment and frees developers to work on application development.

About this blog post
Time to read 10 minutes
Time to complete 25 minutes (not including deployment)
Cost to complete ~ $10
Learning level Intermediate (200)
AWS services Amazon Virtual Private Cloud (Amazon VPC)
AWS CloudFormation
Amazon S3
Amazon EC2
AWS Systems Manager

Overview of the Microsoft workload solution

AWS Quick Starts include automated deployments of popular Microsoft workloads built by AWS solutions architects. The underlying AWS CloudFormation templates are stored in public GitHub repositories and can be used as AWS CloudFormation submodules. A Windows application developer who wants to deploy a test environment can place a CloudFormation template in a GitHub repository, use the git submodule add command to add the required Quick Start repositories as submodules, and then reference the submodules in their CloudFormation templates.

The following diagram shows the AWS resources that are deployed by this CloudFormation template.

architecture diagram of microsoft workload test environment.

Prerequisites

For this walkthrough, you need the following prerequisites:

  • An AWS account
  • An EC2 key pair
  • A GitHub account
  • Basic knowledge of common Microsoft workloads
  • Basic knowledge of CloudFormation templates
  • A copy of the SharePoint 2019 installation media in .ZIP format (optional)

Note: this blog post assumes that the reader is familiar with CloudFormation templates and parameters. For more information, see the AWS documentation for CloudFormation templates, Parameters, ParameterGroup, and ParameterLabel.

Walkthrough for deploying the nested Microsoft workload stacks

This walkthrough describes the steps to deploy a full Windows test stack:

  • A VPC with public and private subnets
  • A redundant Active Directory environment with two domain controllers
  • A redundant SQL environment with an AlwaysOn Availability Group and database replication
  • A redundant SharePoint environment that uses the SQL environment for its databases
  • A redundant Exchange environment
  • An AWS Auto Scaling group with Remote Desktop Gateway for remote access to the environment

When deploying Windows environments on AWS, customers can deploy only those Quick Starts that are relevant to their workloads. (See the AWS CloudFormation documentation to learn how conditions can be used to select only certain submodules during deployment.) The Quick Starts used for this walkthrough have been selected because they are common deployments.

The following steps describe how to deploy this sample Microsoft test environment stack:

  1. Create a GitHub repository
  2. Clone the GitHub repository to a development workstation and create templates and submodules subdirectories.
  3. Create a template file in the templates subdirectory.
  4. Navigate to the submodules subdirectory and use git submodule add to incorporate the various Microsoft submodules.
  5. Create parameters, parameter groups, and parameter labels.
  6. Incorporate the various Microsoft Quick Start submodules as nested stacks.
  7. Upload all templates and SharePoint 2019 installation media to an S3 bucket.
  8. Launch the stack.

The Quick Start GitHub repositories can be found at the following links:

You can find the completed version of this walkthrough at https://github.com/aws-quickstart/msft-nested-example.

Step 1: Create a GitHub repository

  1. Navigate to your GitHub account (https://github.com/<accountname>).
  2. In the Repositories pane, choose New to create a new repository. For the purpose of this blog post, I use the name msft-nested-example, but the repository can be named anything within the GitHub guidelines. Make sure to select the check box to Initialize this repository with a README.

Step 2: Clone the GitHub repository to a development workstation and create subdirectories

  1. Use the Clone or download link to clone the repository to your workstation or other development environment (IDE); e.g., Amazon WorkSpaces.
    git clone https://github.com/<accountname>/msft-nested-example.git
  2. In your IDE, navigate to the cloned repository, and create submodules and templates subdirectories.
    cd ./msft-nested-example
    mkdir submodules
    mkdir templates

Step 3: Create a template file in the templates subdirectory

  1. Use your IDE to create a new template file (in this example, I call it msft.template) in the templates subdirectory.

Step 4: Incorporate the Microsoft Quick Start submodules

  1. Navigate to the submodules directory.
    cd ./submodules
  2. Add the VPC, Active Directory, Microsoft SQL, SharePoint, Exchange, and Remote Desktop Gateway submodules.
    git submodule add https://github.com/aws-quickstart/quickstart-aws-vpc.git
    git submodule add https://github.com/aws-quickstart/quickstart-microsoft-activedirectory.git
    git submodule add https://github.com/aws-quickstart/quickstart-microsoft-sql.git
    git submodule add https://github.com/aws-quickstart/quickstart-microsoft-sharepoint.git
    git submodule add https://github.com/aws-quickstart/quickstart-microsoft-exchange.git
    git submodule add https://github.com/aws-quickstart/quickstart-microsoft-rdgateway.git
    
  3. Initialize the submodules (download their contents and the contents of their respective submodules).
    git submodule update --init --recursive

Step 5: Create parameters

  1. Open the AWS CloudFormation file in the templates subdirectory that was created in step 3.
  2. Define following parameter groups and parameters.
    AWSTemplateFormatVersion: '2010-09-09'
    Description: 'This template is an example of nested Microsoft Quick Starts'
    Metadata:
      AWS::CloudFormation::Interface:
        ParameterGroups:
          - Label:
              default: Network configuration
            Parameters:
              - KeyPairName
              - AvailabilityZones
          - Label:
              default: Microsoft Active Directory configuration
            Parameters:
              - DomainAdminUser
              - DomainAdminPassword
              - DomainDNSName
              - DomainNetBIOSName
          - Label:
              default: Microsoft SQL Server configuration
            Parameters:
              - SQLServiceAccount
              - SQLServiceAccountPassword
              - AvailabiltyGroupName
          - Label:
              default: Microsoft SharePoint configuration
            Parameters:
              - SPBinaryBucket
              - SPBinaryKey
              - SPProductKey
          - Label:
              default: Microsoft Exchange configuration
            Parameters:
              - ExchangeNode1PrivateIP1
              - ExchangeNode1PrivateIP2
              - ExchangeNode2PrivateIP1
              - ExchangeNode2PrivateIP2
              - FileServerPrivateIP
          - Label:
              default: Microsoft Remote Desktop Gateway configuration
            Parameters:
              - NumberOfRDGWHosts
              - RDGWCIDR
          - Label:
              default: S3 Bucket Configuration
            Parameters:
              - S3BucketName
              - S3KeyPrefix
    

    This example uses the default values for many parameters, including the Exchange Server version, server hostnames, instance types, and others. To create a more customized environment, you can include these parameters.

  3. To make the AWS CloudFormation launch page more readable, add parameter labels.
        ParameterLabels:
          AvailabiltyGroupName:
            default: Availability group name
          AvailabilityZones:
            default: Availability Zones
          DomainAdminPassword:
            default: Domain admin password
          DomainAdminUser:
            default: Domain admin user name
          DomainDNSName:
            default: Domain DNS name
          DomainNetBIOSName:
            default: Domain NetBIOS name
          ExchangeNode1PrivateIP1:
            default: Exchange Node 1 private IP address 1
          ExchangeNode1PrivateIP2:
            default: Exchange Node 1 private IP address 2
          ExchangeNode2PrivateIP1:
            default: Exchange Node 2 private IP address 1
          ExchangeNode2PrivateIP2:
            default: Exchange Node 2 private IP address 2
          FileServerPrivateIP:
            default: File Server private IP address
          KeyPairName:
            default: Key pair mame
          NumberOfRDGWHosts:
            default: Number of RD Gateway hosts
          RDGWCIDR:
            default: Allowed RD Gateway external access CIDR
          S3BucketName:
            default: S3 bucket name
          S3KeyPrefix:
            default: S3 key prefix
          SPBinaryBucket:
            default: SharePoint binary bucket
          SPBinaryKey:
            default: SharePoint binary key
          SPProductKey:
            default: SharePoint product key
          SQLServiceAccount:
            default: Service account name
          SQLServiceAccountPassword:
            default: Service account password
    
  4. Finally, within the template, describe all of the parameters, including character constraints and default values.
    Parameters:
      AvailabiltyGroupName:
        AllowedPattern: '[a-zA-Z0-9\-]+'
        Default: "SQLAG1"
        Description: "NetBIOS name of the SQL database or availability group (up to 15 characters)."
        MaxLength: '15'
        MinLength: '1'
        Type: "String"
      AvailabilityZones:
        Description: 'List of Availability Zones to use for the subnets in the VPC. Only two Availability Zones are used for this deployment, and the logical order is preserved.'
        Type: List<AWS::EC2::AvailabilityZone::Name>
      DomainAdminPassword:
        AllowedPattern: (?=^.{6,255}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*
        Description: Password for the domain admin user. Must be at least 8 characters
          and contain letters, numbers, and symbols.
        MaxLength: '32'
        MinLength: '8'
        NoEcho: 'true'
        Type: String
      DomainAdminUser:
        AllowedPattern: '[a-zA-Z0-9]*'
        Default: Admin
        Description: User name for the account that will be added as Domain Administrator.
          This is separate from the default Administrator account.
        MaxLength: '25'
        MinLength: '5'
        Type: String
      DomainDNSName:
        AllowedPattern: '[a-zA-Z0-9\-]+\..+'
        Default: example.com
        Description: Fully qualified domain name (FQDN) of the forest root domain.
        MaxLength: '25'
        MinLength: '2'
        Type: String
      DomainNetBIOSName:
        AllowedPattern: '[a-zA-Z0-9]+'
        Default: example
        Description: NetBIOS name of the domain (up to 15 characters) for users of earlier
          versions of Windows.
        MaxLength: '15'
        MinLength: '1'
        Type: String
      ExchangeNode1PrivateIP1:
        AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
        Default: 10.0.0.110
        Description: The primary private IP for Exchange node 1.
        Type: String
      ExchangeNode1PrivateIP2:
        AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
        Default: 10.0.0.111
        Description: The secondary private IP for Exchange node 1.
        Type: String
      ExchangeNode2PrivateIP1:
        AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
        Default: 10.0.32.110
        Description: The primary private IP for Exchange node 2.
        Type: String
      ExchangeNode2PrivateIP2:
        AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
        Default: 10.0.32.111
        Description: The secondary private IP for Exchange node 2.
        Type: String
      FileServerPrivateIP:
        AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
        Default: 10.0.0.210
        Description: The primary private IP for the file-share witness server.
        Type: String
      KeyPairName:
        Description: Public/private key pair that allows you to securely connect to your instance
          after it launches.
        Type: AWS::EC2::KeyPair::KeyName
      NumberOfRDGWHosts:
        AllowedValues:
          - '1'
          - '2'
          - '3'
          - '4'
        Default: '1'
        Description: The number of RD Gateway hosts to create (up to four).
        Type: String
      RDGWCIDR:
        AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$
        ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x
        Description: Allowed CIDR block for external access to the RD Gateway hosts.
        Type: String
      S3BucketName:
        AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$
        ConstraintDescription: S3 bucket name can include numbers, lowercase
          letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen
          (-).
        Description: S3 bucket name for the assets. S3 bucket name
          can include numbers, lowercase letters, uppercase letters, and hyphens (-).
          It cannot start or end with a hyphen (-).
        Type: String
      S3KeyPrefix:
        AllowedPattern: ^[0-9a-zA-Z-/]*$
        ConstraintDescription: S3 key prefix can include numbers, lowercase letters,
          uppercase letters, hyphens (-), and forward slash (/).
        Description: S3 key prefix for the assets. S3 key prefix
          can include numbers, lowercase letters, uppercase letters, hyphens (-), and
          forward slash (/).
        Type: String
      SPBinaryBucket:
        Type: String
        MinLength: 2
        MaxLength: 255
      SPBinaryKey:
        Type: String
        MinLength: 2
        MaxLength: 255
      SPProductKey:
        Type: String
        Description: The product key to use with SharePoint.
        MinLength: 29
        MaxLength: 29
        Default: M692G-8N2JP-GG8B2-2W2P7-YY7J6 # Default SharePoint 2019 Enterprise Trial Key
      SQLServiceAccount:
        AllowedPattern: '[a-zA-Z0-9]*'
        Default: sqlsa
        Description: User name for the SQL Server service account. This account is a Domain
          User.
        MaxLength: '25'
        MinLength: '5'
        Type: String
      SQLServiceAccountPassword:
        AllowedPattern: (?=^.{6,255}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*
        Description: Password for the SQL Server service account. Must be at least 8 characters
          and contain letters, numbers, and symbols.
        MaxLength: '32'
        MinLength: '8'
        NoEcho: 'true'
        Type: String
    

Step 6: Incorporate Quick Starts as nested stacks

In the Resources section of the template, you can add the various Quick Start submodules as AWS CloudFormation stacks. The outputs from deployed stacks can be passed as parameters to subsequent stacks. For instance, when launching the Microsoft stacks, the VPCID parameter can be extracted from the output of the VPC stack (VPCStack.Outputs.VPCID).

  1. Add the VPC stack.
    Resources:
      VPCStack:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}submodules/quickstart-aws-vpc/templates/aws-vpc.template
          Parameters:
            AvailabilityZones: !Join
              - ','
              - !Ref 'AvailabilityZones'
            KeyPairName: !Ref 'KeyPairName'
            NumberOfAZs: '2'
    
  2. Add the Active Directory stack.By setting the DependsOn attribute to the VPC stack, you can ensure that the Active Directory stack will not deploy until the VPC stack is complete.
      ADStack:
        Type: AWS::CloudFormation::Stack
        DependsOn: VPCStack
        Properties:
          TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}submodules/quickstart-microsoft-activedirectory/templates/ad-1.template
          Parameters:
            DomainAdminPassword: !Ref 'DomainAdminPassword'
            DomainAdminUser: !Ref 'DomainAdminUser'
            DomainDNSName: !Ref 'DomainDNSName'
            DomainNetBIOSName: !Ref 'DomainNetBIOSName'
            KeyPairName: !Ref 'KeyPairName'
            PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet1AID'
            PrivateSubnet2ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet2AID'
            VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
            QSS3BucketName: !Ref 'S3BucketName'
            QSS3KeyPrefix: !Sub '${S3KeyPrefix}submodules/quickstart-microsoft-activedirectory/'
            VPCCIDR: !GetAtt 'VPCStack.Outputs.VPCCIDR'
    
  3. Add the SQL Server stack.By setting the DependsOn attribute to the Active Directory stack, you can ensure that the SQL stack will not deploy until the Active Directory stack is complete.
      SQLStack:
        Type: AWS::CloudFormation::Stack
        DependsOn: ADStack
        Properties:
          TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}submodules/quickstart-microsoft-sql/templates/sql.template
          Parameters:
            ADScenarioType: Microsoft AD on Amazon EC2
            DomainAdminPassword: !Ref 'DomainAdminPassword'
            DomainAdminUser: !Ref 'DomainAdminUser'
            DomainDNSName: !Ref 'DomainDNSName'
            DomainMemberSGID: !GetAtt 'ADStack.Outputs.DomainMemberSGID'
            DomainNetBIOSName: !Ref 'DomainNetBIOSName'
            KeyPairName: !Ref 'KeyPairName'
            SQLServiceAccount: !Ref 'SQLServiceAccount'
            SQLServiceAccountPassword: !Ref 'SQLServiceAccountPassword'
            AvailabiltyGroupName: !Ref 'AvailabiltyGroupName'
            PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet1AID'
            PrivateSubnet2ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet2AID'
            QSS3BucketName: !Ref 'S3BucketName'
            QSS3KeyPrefix: !Sub '${S3KeyPrefix}submodules/quickstart-microsoft-sql/'
            VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
    
  4. Add the SharePoint stack.By setting the DependsOn attribute to the SQL Server stack, you can ensure that the SharePoint stack will not deploy until the SQL Server stack is complete.Note: A copy of the SharePoint 2019 installation media (in .ZIP format) is required to deploy SharePoint. If you do not have access to this, omit the SharePoint stack from the template.
      SharePointFarmStack:
        Type: AWS::CloudFormation::Stack
        DependsOn: SQLStack
        Properties:
          TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}submodules/quickstart-microsoft-sharepoint/templates/sharepoint-farm.yaml
          Parameters:
            ADAdminPassword: !Ref 'DomainAdminPassword'
            ADAdminUserName: !Ref 'DomainAdminUser'
            DomainDNSName: !Ref 'DomainDNSName'
            DomainNetBIOSName: !Ref 'DomainNetBIOSName'
            ADMemberSecurityGroup: !GetAtt 'ADStack.Outputs.DomainMemberSGID'
            KeyPairName: !Ref 'KeyPairName'
            Subnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet1AID'
            Subnet2ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet2AID'
            SPProductKey: !Ref 'SPProductKey'
            SQLServerAccessSecurityGroup: !GetAtt 'SQLStack.Outputs.SQLServerAccessSecurityGroupID'
            VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
            VPCCIDR: !GetAtt 'VPCStack.Outputs.VPCCIDR'
            SPBinaryBucket: !Ref 'SPBinaryBucket'
            SPBinaryKey: !Ref 'SPBinaryKey'
            SQLAdminUserName: !Ref 'SQLServiceAccount'
            SQLAdminPassword: !Ref 'SQLServiceAccountPassword'
            SPDatabaseName: !Ref 'AvailabiltyGroupName'
    
  5. Add the Exchange Server stack.By setting the DependsOn attribute to the Active Directory stack, you can ensure that the Exchange stack will not deploy until the Active Directory stack is complete.
      ExchangeStack:
        Type: AWS::CloudFormation::Stack
        DependsOn: ADStack
        Properties:
          TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}submodules/quickstart-microsoft-exchange/templates/exchange.template
          Parameters:
            DomainAdminPassword: !Ref 'DomainAdminPassword'
            DomainAdminUser: !Ref 'DomainAdminUser'
            DomainDNSName: !Ref 'DomainDNSName'
            DomainMemberSGID: !GetAtt 'ADStack.Outputs.DomainMemberSGID'
            DomainNetBIOSName: !Ref 'DomainNetBIOSName'
            KeyPairName: !Ref 'KeyPairName'
            PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet1AID'
            PrivateSubnet2ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet2AID'
            PublicSubnet1ID: !GetAtt 'VPCStack.Outputs.PublicSubnet1ID'
            PublicSubnet2ID: !GetAtt 'VPCStack.Outputs.PublicSubnet2ID'
            ExchangeNode1PrivateIP1: !Ref 'ExchangeNode1PrivateIP1'
            ExchangeNode1PrivateIP2: !Ref 'ExchangeNode1PrivateIP2'
            ExchangeNode2PrivateIP1: !Ref 'ExchangeNode2PrivateIP1'
            ExchangeNode2PrivateIP2: !Ref 'ExchangeNode2PrivateIP2'
            FileServerPrivateIP: !Ref 'FileServerPrivateIP'
            QSS3BucketName: !Ref 'S3BucketName'
            QSS3KeyPrefix: !Sub '${S3KeyPrefix}submodules/quickstart-microsoft-exchange/'
            VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
            VPCCidrBlock: !GetAtt 'VPCStack.Outputs.VPCCIDR'
    
  6. Add the Remote Desktop Gateway stack.By setting the DependsOn attribute to the Active Directory stack, you can ensure that the Remote Desktop Gateway stack will not deploy until the Active Directory stack is complete.
      RDGWStack:
        Type: AWS::CloudFormation::Stack
        DependsOn: ADStack
        Properties:
          TemplateURL: !Sub https://${S3BucketName}.s3.amazonaws.com/${S3KeyPrefix}submodules/quickstart-microsoft-rdgateway/templates/rdgw-standalone.template
          Parameters:
            AdminPassword: !Ref 'DomainAdminPassword'
            AdminUser: !Ref 'DomainAdminUser'
            DomainDNSName: !Ref 'DomainDNSName'
            KeyPairName: !Ref 'KeyPairName'
            NumberOfRDGWHosts: !Ref 'NumberOfRDGWHosts'
            PublicSubnet1ID: !GetAtt 'VPCStack.Outputs.PublicSubnet1ID'
            PublicSubnet2ID: !GetAtt 'VPCStack.Outputs.PublicSubnet2ID'
            QSS3BucketName: !Ref 'S3BucketName'
            QSS3KeyPrefix: !Sub '${S3KeyPrefix}submodules/quickstart-microsoft-rdgateway/'
            RDGWCIDR: !Ref 'RDGWCIDR'
            VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
    

Step 7: Upload files to the S3 bucket

  1. If you do not already have an S3 bucket available, navigate to the AWS Management Console, choose S3, and create an S3 bucket. Ensure that the bucket allows public access.
  2. Create a directory in the S3 bucket, and upload the entire contents of your local copy of the GitHub repository to this directory. Later, you will enter the directory name as the S3BucketName parameter.

Step 8: Launch the CloudFormation template

  1. Navigate to the AWS Management Console, and select CloudFormation.
  2. Choose Create stack, and select With new resources (standard).
    create stack drop down menu.
  3. Enter the S3 location of your template (https://<S3BucketName>.s3.amazonaws.com/&Lt;S3KeyPrefix>templates/msft.template), or upload the template from your local copy of the GitHub repository.
  4. Fill out the fields that don’t have default values.
    • Stack Name. Enter a unique name for the stack.
    • Key pair name. Select an EC2 key pair to connect to your instances.
    • Availability Zones. Select two Availability Zones for the deployment.
    • Domain admin password. This is the password used to administer Active Directory.
    • Service account password. This is the password used to run SQL Server.
    • SharePoint binary bucket. If you uploaded the SharePoint installation media, enter the bucket name here.
    • SharePoint binary key. If you uploaded the SharePoint installation media, enter the S3 key here.
    • Allowed RD Gateway external access CIDR. Enter the CIDR that will have access to the Remote Desktop Gateway farm.
    • S3 Bucket name. Enter the S3 bucket where you uploaded the GitHub repository contents.
    • S3 key prefix. Enter the S3 key prefix where you uploaded the GitHub repository contents. Ensure that the key prefix ends with a forward slash (“/”).
  5. Choose Next.
  6. Keep the default stack options, and choose Next.
  7. Select the check boxes for I acknowledge that AWS CloudFormation might create IAM resources with custom names and I acknowledge that AWS CloudFormation might require the following capability: CAPABILITY_AUTO_EXPAND, and choose Create stack.
    Two acknowledgement check boxes.
    Stack creation should begin. Each nested stack will have its own object in the AWS CloudFormation console.
    nested stacks shown in the console during stack creation.
    Upon completion, a full Microsoft stack is deployed, including the following resources:

    • Two domain controllers
    • Two Windows Server failover cluster servers running SQL Server
    • A file server to act as the failover cluster witness
    • Two Exchange nodes
    • A file server to act as the Exchange Server cluster witness
    • Four SharePoint servers
    • Remote Desktop Gateway in an Auto Scaling group

    Deployment takes approximately 4 hours.
    Name, instance ID, and instance type for the instances.

Cleaning up

To avoid incurring future charges, delete the resources. In the AWS CloudFormation console, select the main stack that you created, and then choose Delete. All objects that were created during launch, including all of the nested stacks, will be deleted.

Delete button for cleaning up the nested stacks.

Conclusion

In this walkthrough, I showed you how to create a single CloudFormation template that leverages existing Quick Starts as submodules to deploy a full Microsoft stack in an automated fashion. Visit the Microsoft section of the AWS Quick Starts page to view the Microsoft products currently available to use as submodules. View the AWS Quick Start GitHub organization page to find their corresponding Git links to use them as submodules for future Microsoft deployments.