Jump to content
Welcome to our new Citrix community!

Citrix DaaS and Terraform - Automatic Deployment of a Resource Location on Amazon EC2

  • Contributed By: Gerhard Krenn Special Thanks To: Jason Samuel, Avijit Gahtori, Zhuolun Liu, Fred Liu

Overview

This guide aims to provide an overview of using Terraform to create a complete Citrix DaaS Resource Location on Amazon EC2.
At the end of the process, you created:

  • A new Citrix Cloud Resource Location (RL) running on Amazon EC2
  • 2 Cloud Connector Virtual Machines registered with the Domain and the Resource Location
  • A Hypervisor Connection and a Hypervisor Pool pointing to the new Resource Location in Amazon EC2
  • A Machine Catalog based on the uploaded Master Image VHD or on an Amazon EC2-based Master Image
  • A Delivery Group based on the Machine Catalog with full Autoscale Support
  • Example policies and policy scope bound to the Delivery Group

What is Terraform

Terraform is an Infrastructure-as-Code (IaC) tool that defines cloud and on-prem resources in easy-readable configuration files rather than through a GUI.

IaC allows you to build, change, and manage your infrastructure safely and consistently by defining resource configurations.
These configurations can be versioned, reused, and shared and are created in its native declarative configuration language known as HashiCorp Configuration Language (HCL), or optionally using JSON.

Terraform creates and manages resources on Cloud platforms and other services through their application programming interfaces (APIs). Terraform providers are compatible with virtually any platform or service with an accessible API.

deployment-guides-CCOnAWS-terraform-ec2-scheme.png

More information about Terraform can be found at https://developer.hashicorp.com/terraform/intro.

Installation

HashiCorp distributes Terraform as a binary package. You can also install Terraform using popular package managers. In this example, we use Chocolatey for Windows to deploy Terraform. Chocolatey is a free and open-source package management system for Windows. Install the Terraform package from the CLI.

Installation of Chocolatey

Open a PowerShell shell with Administrative rights and paste the following command:

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

Chocolatey downloads and installs all necessary components automatically:

PS C:\TACG> Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString (https://community.chocolatey.org/install.ps1))       
                                                                
 Forcing web requests to allow TLS v1.2 (Required for requests to Chocolatey.org)
 Getting latest version of the Chocolatey package for download.                                                         
 Not using proxy.    
                                                                                                   
 Getting Chocolatey from https://community.chocolatey.org/api/v2/package/chocolatey/2.2.2.
 Downloading https://community.chocolatey.org/api/v2/package/chocolatey/2.2.2 to C:\TACG\AppData\Local\Temp\chocolatey\chocoInstall\chocolatey.zip
 Not using proxy.

 Extracting C:\TACG\AppData\Local\Temp\chocolatey\chocoInstall\chocolatey.zip to C:\TACG\AppData\Local\Temp\chocolatey\chocoInstall
 
Installing Chocolatey on the local machine
 Creating ChocolateyInstall as an environment variable (targeting 'Machine')
   Setting ChocolateyInstall to 'C:\ProgramData\chocolatey'
 WARNING: It's very likely you will need to close and reopen your shell before you can use choco.
 Restricting write permissions to Administrators
 We are setting up the Chocolatey package repository.
 The packages themselves go to 'C:\ProgramData\chocolatey\lib'
   (i.e. C:\ProgramData\chocolatey\lib\yourPackageName).
 A shim file for the command line goes to 'C:\ProgramData\chocolatey\bin' and points to an executable in 'C:\ProgramData\chocolatey\lib\yourPackageName'.

 Creating Chocolatey folders if they do not already exist.

 chocolatey.nupkg file not installed in lib.
  Attempting to locate it from bootstrapper.
 PATH environment variable does not have C:\ProgramData\chocolatey\bin in it. Adding...
 WARNING: Not setting tab completion: Profile file does not exist at
 'C:\TACG\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1'.

 Chocolatey (choco.exe) is now ready.
 You can call choco from anywhere, command line or powershell by typing choco.
 Run choco /? for a list of functions.
 You may need to shut down and restart powershell and/or consoles first prior to using choco.
 Ensuring Chocolatey commands are on the path
 Ensuring chocolatey.nupkg is in the lib folder

PS C:\TACG>

Run choco --v to check if Chocolatey was installed successfully:

PS C:\TACG> choco --v
 Chocolatey v2.2.2

 PS C:\TACG>

 

 


Installation of Terraform

After the successful installation of Chocolatey you can install Terraform by running this command on the PowerShell session:

 

PS C:\TACG> choco install terraform
 Chocolatey v2.2.2
 Installing the following packages:
 terraform
 By installing, you accept licenses for the packages.
 Progress: Downloading terraform 1.6.4... 100%

 terraform v1.7.4 [Approved]
 terraform package files install completed. Performing other installation steps.
 The package terraform wants to run 'chocolateyInstall.ps1'.
 Note: If you don't run this script, the installation will fail.
 Note: To confirm automatically next time, use '-y' or consider:
 choco feature enable -n allowGlobalConfirmation
 Do you want to run the script?([Y]es/[A]ll - yes to all/[N]o/[P]rint): A

 Removing old terraform plug-ins
 Downloading terraform 64 bit from 'https://releases.hashicorp.com/terraform/1.7.4/terraform_1.7.4_windows_amd64.zip'
 Progress: 100% - Completed download of C:\TACG\AppData\Local\Temp\chocolatey\terraform\1.7.4\terraform_1.7.4_windows_amd64.zip (25.05 MB).
 Download of terraform_1.7.4_windows_amd64.zip (25.05 MB) completed.
 Hashes match.
 
Extracting C:\TACG\AppData\Local\Temp\chocolatey\terraform\1.7.4\terraform_1.7.4_windows_amd64.zip to C:\ProgramData\chocolatey\lib\terraform\tools...
 C:\ProgramData\chocolatey\lib\terraform\tools
  ShimGen has successfully created a shim for terraform.exe

  The install of terraform was successful.
  Software installed to 'C:\ProgramData\chocolatey\lib\terraform\tools'

 Chocolatey installed 1/1 packages.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

PS C:\TACG>


Run terraform -version to check if Terraform installed successfully:

PS C:\TACG> terraform -version
 Terraform v1.7.4 on windows_amd64
 
 PS C:\TACG>

The installation of Terraform is now completed.

Terraform - Basics and Commands

Terraform Block

The terraform {} block contains Terraform settings, including the required providers to provision your infrastructure. Terraform installs providers from the Terraform Registry.

Providers

The provider block configures the specified provider. A provider is a plug-in that Terraform uses to create and manage your resources. Providing multiple provider blocks in the Terraform configuration enables managing resources from different providers.

Resources

Resource blocks define the components of the infrastructure - physical, virtual, or logical. These blocks contain arguments to configure the resource. The provider's reference lists the required and optional arguments for each resource.

The core Terraform workflow consists of three stages

Write:
You define resources that are deployed, altered, or deleted.

Plan:
Terraform creates an execution plan describing the infrastructure that it creates, updates, or destroys based on the existing infrastructure and your configuration.

Apply:
On approval, Terraform does the proposed operations in the correct order, respecting any resource dependencies.

Terraform does not only add complete configurations, it also allows you to change previously added configurations.
For example, changing the DNS servers of an NIC of an Amazon EC2 VM does not require redeploying the whole configuration - Terraform only alters the needed resources.

Terraform Provider for Citrix

Citrix has developed a custom Terraform provider for automating Citrix product deployments and configurations.

Note:

The Citrix Terraform provider is currently in Tech Preview!
This guide is updated when the provider has reached RTM.

Using Terraform with Citrix' provider, you can manage your Citrix products via Infrastructure as Code. Terraform is giving you higher efficiency and consistency on infrastructure management and better reusability on infrastructure configuration.

The provider defines individual units of infrastructure and currently supports both Citrix Virtual Apps and Desktops and Citrix Desktop as a Service solutions.
You can automate the creation of a site setup including host connections, machine catalogs, and delivery groups.
You can deploy resources in Amazon EC2, AWS, and GCP in addition to supported on-premises Hypervisors.

Note:

All information about the Citrix Terraform provider can be found on GitHub: https://github.com/citrix/terraform-provider-citrix

deployment-guides-CCOnAWS-terraform-github.png

Terraform expects to be invoked from a working directory that contains configuration files written in the Terraform language.
Terraform uses configuration content from this directory and also uses the directory to store settings, cached plug-ins and modules, and state data.

A working directory must be initialized before Terraform can do any operations in it.
Initialize the working directory by using the command:

PS C:\TACG> terraform init

 Initializing the backend...

 Successfully configured the backend "local"! Terraform will automatically use this backend unless the backend configuration changes.

 Initializing provider plug-ins...
 - Finding citrix/citrix versions matching ">= 0.5.3"...
 - Installing citrix/citrix v0.5.3...
 - Installed citrix/citrix v0.5.3 (signed by a HashiCorp partner, key ID 25D62DD8407EA386)

 Partner and community providers are signed by their developers.
 If you'd like to know more about provider signing, you can read about it here:
 https://www.terraform.io/docs/cli/plug-ins/signing.html Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future.

 Terraform has been successfully initialized!

 You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. 
 All Terraform commands should now work.

 If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. 
 If you forget, other commands will detect it and remind you to do so if necessary.

PS C:\TACG>

 

The provider defines how Terraform can interact with the underlying API. Configurations must declare which providers they require so Terraform can install and use them.

Terraform CLI finds and installs providers when initializing a working directory. It can automatically download providers from a Terraform registry, or load them from a local mirror or cache.

Example: Terraform configuration files - provider.tf

The file provider.tf contains the information on the target site where to apply the configuration.
Depending on whether it is a Citrix Cloud site or a Citrix On-Premises site, the provider needs to be configured differently:

# Cloud Provider
provider "Citrix" {
  customer_id   = "idofthexxxxxxxxx"                     ‘Citrix Cloud Customer ID
  client_id     = "3edrxxxx-XXXX-XXXX-XXXX-XXXXXXXXXX"   ‘ID of the Secure API client planned to use
  client_secret = "*********************"                ‘Secret of the Secure API client planned to use
}

A guide for the creation of a secure API client can be found in Citrix Developer Docs and is shown later as well.

# On-Premises Provider
provider "Citrix" {
  hostname      = "10.0.0.6"
  client_id     = "foo.local\\admin"
  client_secret = "foo"
}
Example - Schema used for the Provider configuration
  • client_id (String): Client Id for Citrix DaaS service authentication
    For Citrix On-Premises customers: Use this variable to specify the Domain-Admin Username.
    For Citrix Cloud customers: Use this variable to specify Cloud API Key Client ID.
    Can be set via the Environment Variable CITRIX_CLIENT_ID.

  • client_secret (String, Sensitive): Client Secret for Citrix DaaS service authentication
    For Citrix On-Premises customers: Use this variable to specify the Domain-Admin Password.
    For Citrix Cloud customers: Use this variable to specify Cloud API Key Client Secret.
    Can be set via the Environment Variable CITRIX_CLIENT_SECRET.|

  • customer_id (String): Citrix Cloud customer ID
    Only applicable for Citrix Cloud customers.
    Can be set via the Environment Variable CITRIX_CUSTOMER_ID.

  • disable_ssl_verification (Boolean): Disable SSL verification against the target DDC
    Only applicable to on-premises customers. Citrix Cloud customers do not need this option. Set to true to skip SSL verification only when the target DDC does not have a valid SSL certificate issued by a trusted CA.
    When set to true, please make sure that your provider config is set for a known DDC hostname.
    It is recommended to configure a valid certificate for the target DDC.
    Can be set via the Environment Variable CITRIX_DISABLE_SSL_VERIFICATION.|

  • environment (String): Citrix Cloud environment of the customer
    Only applicable for Citrix Cloud customers. Available options: Production, Staging, Japan, JapanStaging.
    Can be set via the Environment Variable CITRIX_ENVIRONMENT.|

  • hostname (String) | Hostname/base URL of Citrix DaaS service
    For Citrix On-Premises customers (Required): Use this variable to specify the Delivery Controller hostname.
    For Citrix Cloud customers (Optional): Use this variable to override the Citrix DaaS service hostname.
    Can be set via the Environment Variable CITRIX_HOSTNAME.|

Note:

The Citrix Terraform provider is currently in Tech Preview!
This guide is updated when the provider has reached RTM.

 

Deploying a Citrix Cloud Resource location on Amazon EC2 using Terraform

Overview

This guide aims to showcase the possibility of creating a complete Citrix Cloud Resource Location on Amazon EC2 using Terraform. We want to reduce manual interventions to the absolute minimum.

All Terraform configuration files can be found late on GitHub - we update this guide when the GitHub repository is ready.

In this guide we use an existing domain and will not deploy a new domain - for further instructions for deploying a new domain refer to the guide Citrix DaaS and Terraform - Automatic Deployment of a Resource Location on Microsoft Azure. Note that this guide will be reworked soon!

The AD deployment used for this guide consists of a Hub-and-Spoke model - each Resource Location running on a Hypervisor/Hyperscaler is connected to the main Domain Controller by using IPSec-based Site-to-Site VPNs. Each Resource Location has its own sub-domain.

NOTE: For easier reading and understanding, we did not use any loop-constructs or count keywords - each resource is created explicitly.

The Terraform flow is split into different parts:

The Terraform flow is split into different parts:

  • Part One - this part can be run on any computer where Terraform is installed :
    • Creating the initially needed Resources on Amazon EC2:
      • Creating all needed IAM roles on Amazon EC2
      • Creating all needed IAM Instance profiles on Amazon EC2
      • Creating all needed IAM policies on Amazon EC2
      • Creating all needed Secret Manager configurations on Amazon EC2
      • Creating all needed DHCP configurations on Amazon EC2
      • Creating a Windows Server 2022-based Master Image VM used for deploying the Machine Catalog in step 3
      • Creating two Windows Server 2022-based VMs used as Cloud Connector VMs in step 2
      • Creating a Windows Server 2022-based VM acting as a Administrative workstation for running the Terraform steps 2 and 3 - this is necessary because of using WinRM for further configuration and deployment in steps 2 and 3!
      • Creating all necessary scripts for joining the VMs to the existing sub-domain
      • Putting the VMs into the existing sub-domain

NOTE: The Master Image needs to be configured before it can be deployed - Terraform will configure a blank, Domain-joined VM! The Administrative VM must have Terraform installed - use the Chocolately Guidance provided previously for installation

  • Part Two - this part can only be run on the previously created Administrative VM as the deployment of steps 2 and 3 relies heavily on WinRM:

    • Configuring the three previously created Virtual Machines on Amazon EC2:

      • Installing the needed software on the CCs
      • Installing the needed software on the Admin-VM
    • Creating the necessary Resources in Citrix Cloud:

      • Creating a Resource Location in Citrix Cloud
      • Configuring the 2 CCs as Cloud Connectors
      • Registering the 2 CCs in the newly created Resource Location
  • Part Three:

    • Creating the Machine Catalog and Delivery Group in Citrix Cloud:
      • Retrieving the Site- and Zone-ID of the Resource Location
      • Creating a dedicated Hypervisor Connection to Amazon EC2
      • Creating a dedicated Hypervisor Resource Pool
      • Creating a Machine Catalog (MC) in the newly created Resource Location
      • Creating a Delivery Group (DG) based on the MC in the newly created Resource Location

NOTE: Make sure that all Terraform-related VMs can communicate using WinRM.
If the Admin-VM is not able to connect to the CCs using WinRM, the deployment fails.
Various configuration guides for WinRM can be found on the Internet.

Determine if WinRM connections/communications are functioning

We strongly recommend a quick check to determine the communication before starting the Terraform scripts.
Open a PowerShell console and type the following command:

PS C:\TACG> test-wsman -ComputerName <IP-Address of the computer you want to reach> -Credential <IP-Address of the computer you want to reach>\administrator -Authentication Basic 

The response should look like:  
wsmid           : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd  
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd  
ProductVendor   : Microsoft Corporation  
ProductVersion  : OS: 0.0.0 SP: 0.0 Stack: 3.0  

Another possibility is to open a PowerShell console and type:  
Enter-PSSession -ComputerName <IP-Address of the computer you want to reach> -Credential <IP-Address of the computer you want to reach>\administrator  

The response should look like:  
[172.31.22.104]: PS C:\Users\Administrator\Documents>

A short Terraform script also checks if the communication via WinRM between the Admin-VM and in this example, the CC1-VM is working as intended:

locals {
  #### Test the WinRM communication
  #### Need to invoke PowerShell as Domain User as the provisioner does not allow to be run in a Domain Users-context
  TerraformTestWinRMScript     = <<-EOT
  $PSUsername = '${var.Provisioner_DomainAdmin-Username}'
  $PSPassword = '${var.Provisioner_DomainAdmin-Password}'
  $PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
  $PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
  Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
  $FileNameForData = 'C:\temp\xdinst\Processes.txt'
  If (Test-Path $FileNameForData) {Remove-Item -Path $FileNameForData -Force}
  Get-Process | Out-File -FilePath 'C:\temp\xdinst\Processes.txt'
  }
  EOT
}
 
#### Write script into local data-directory
resource "local_file" "WriteWinRMTestScriptIntoDataDirectory" {
  filename = "${path.module}/data/Terraform-Test-WinRM.ps1"
  content  = local.TerraformTestWinRMScript
}
 
resource "null_resource" "CreateTestScriptOnCC1" {
 
connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_CC1-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
   provisioner "file" {
    source      = "${path.module}/data/Terraform-Test-WinRM.ps1"
    destination = "C:/temp/xdinst/Terraform-Test-WinRM.ps1"
   
  }
 
  provisioner "remote-exec" {
    inline = [
      "powershell -File 'C:/temp/xdinst/Terraform-Test-WinRM.ps1'"
    ]
  }
}

If you can see in the Terraform console something like...:

null_resource.CreateTestScriptOnCC1: Creating...
null_resource.CreateTestScriptOnCC1: Provisioning with 'remote-exec'...
null_resource.CreateTestScriptOnCC1 (remote-exec): Connecting to remote host via WinRM...
null_resource.CreateTestScriptOnCC1 (remote-exec):   Host: 172.31.22.103
null_resource.CreateTestScriptOnCC1 (remote-exec):   Port: 5985
null_resource.CreateTestScriptOnCC1 (remote-exec):   User: administrator
null_resource.CreateTestScriptOnCC1 (remote-exec):   Password: true
null_resource.CreateTestScriptOnCC1 (remote-exec):   HTTPS: false
null_resource.CreateTestScriptOnCC1 (remote-exec):   Insecure: false
null_resource.CreateTestScriptOnCC1 (remote-exec):   NTLM: false
null_resource.CreateTestScriptOnCC1 (remote-exec):   CACert: false
null_resource.CreateTestScriptOnCC1 (remote-exec): Connected!  

#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
null_resource.CreateTestScriptOnCC1 (remote-exec): C:\Users\Administrator>powershell -File c:/temp/xdinst/DATA/Terraform-Test-WinRM.ps1

#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.CreateTestScriptOnCC1: Creation complete after 3s [id=1571484748961023525]

...then you can be sure that the provisioning using WinRM is working as intended!

Configuration using variables

All needed configuration settings are stored in the corresponding Variables which need to be set. Some Configuration settings are propagated throughout the whole Terraform configuration...

You need to start each of the 3 modules manually using the Terraform workflow terraform init, terraform plan, and terraform apply in the corresponding module directory. Terraform then completes the necessary configuration steps of the corresponding module.

NOTE: Each module must be completed successfully before the next module can be started!

File System structure

Root-Directory

Module 1: _CConAWS-Creation:

Filename                                                                                                        Purpose                                                
_CConAWS-Creation-Create.tf Resource configuration and primary flow definition
_CConAWS-Creation-Create-variables.tf Definition of Variables
_CConAWS-Creation-Create.auto.tfvars.json Setting the values of the Variables
_CConAWS-Creation-Provider.tf Provider definition and configuration
_CConAWS-Creation-Provider-variables.tf Definition of Variables
_CConAWS-Creation-Provider.auto.tfvars.json Setting the values of the Variables
Add-EC2InstanceToDomainAdminVM.ps1 Powershell-Script for joining the Admin-VM to the Domain
Add-EC2InstanceToDomainCC1.ps1 Powershell-Script for joining the CC1-VM to the Domain
Add-EC2InstanceToDomainCC2.ps1 Powershell-Script for joining the CC2-VM to the Domain
Add-EC2InstanceToDomainWMI.ps1 Powershell-Script for joining the CC2-VM to the Domain
DATA-Directory Place to put files to upload using file provisioning
  (NOT RECOMMENDED - see later explanation


Module 2: _CConAWS-Install:

Filename                                                                                                         Purpose                                               
_CCOnAWS-Install-CreatePreReqs.tf Resource configuration and primary flow definition
_CCOnAWS-Install-CreatePreReqs-variables.tf Definition of Variables
_CCOnAWS-Install-CreatePreReqs.auto.tfvars.json Setting the values of the Variables
_CConAWS-Install-Provider.tf Provider definition and configuration
_CConAWS-Install-Provider-variables.tf Definition of Variables
_CConAWS-Install-Provider.auto.tfvars.json Setting the values of the Variables
GetSiteID.ps1 PowerShell script to make a REST-API call to determine the CC-Site-ID
GetZoneID.ps1 PowerShell script to make a REST-API call to determine the CC-Zone-ID
DATA/InstallPreReqsOnAVM1.ps1 PowerShell script to deploy needed pre-requisites on the Admin-VM
DATA/InstallPreReqsOnAVM2.ps1 PowerShell script to deploy needed pre-requisites on the Admin-VM
DATA/InstallPreReqsOnCC.ps1 PowerShell script to deploy needed pre-requisites on the Admin-VM

Module 3: _CConAWS-CCStuff:

Filename                                                                                                         Purpose                                               
_CCOnAWS-CCStuff-CreateCCEntities.tf Resource configuration and primary flow definition
_CCOnAWS-CCStuff-CreateCCEntities-variables.tf Definition of Variables
_CCOnAWS-CCStuff-CreateCCEntities.auto.tfvars.json Setting the values of the Variables
_CConAWS-CCStuff-Provider.tf Provider definition and configuration
_CConAWS-CCStuff-Provider-variables.tf Definition of Variables
_CConAWS-CCStuff-Provider.auto.tfvars.json Setting the values of the Variables

NOTE: All Terraform-related directories and files (.terraform, -terrafrom.lock.hcl, terraform.tfstate, terraform.tfstate) must not be changed or deleted - doing so might break the deployment!

Change the settings in the .json files according to your needs.

The following prerequisites are needed before setting the corresponding settings or running the Terraform workflow to ensure a smooth and error-free build.

Prerequisites

Installing AWS.Tools for PowerShell and AWS CLI

In this guide, we use AWS CLI and PowerShell cmdlets to determine further needed information.

deployment-guides-CCOnAWS-PreReqs-AWSCLI.png

deployment-guides-CCOnAWS-PreReqs-PS.AWS.Tools.png

Further information about AWS CLI and the installation/configuration can be found at AWS Command Line Interface, further information about the PowerShell cmdlets for AWS can be found at Installing the AWS Tools for PowerShell on Windows.

Examples:
PS C:\TACG> Install-AWSToolsModule AWS.Tools.EC2 -Force  
Installing module AWS.Tools.EC2 version 4.1.533.0  

PS C:\TACG> Install-AWSToolsModule AWS.Tools.IdentityManagement -Force  
Installing module AWS.Tools.IdentityManagement version 4.1.533.0  

PS C:\TACG> Install-AWSToolsModule AWS.Tools.SimpleSystemsManagement -Force  
Installing module AWS.Tools.SimpleSystemsManagement version 4.1.533.0

PS C:\TACG>


Existing Amazon EC2 entities

We anticipate that the following resources are existing and are already configured on Amazon EC2:

  • A working tenant
  • All needed rights for the IAM user on the tenant
  • A VPC
  • At least one subnet in the VPC
  • A security group configured for allowing inbound connections from the subnet and partially from the Internet: WinRM-HTTP, WinRM-HTTPS, UDP, DNS (UDP and TCP), ICMP (for testing purposes), HTTP, HTTPS, TCP (for testing purposes), RDP. No blocking rules for outbound connections should be in place
  • An access key with its secret (see a description how to create the key later on)

We can get the needed information about the VPC by using PowerShell:

PS C:\TACG> Get-EC2VPC

CidrBlock                   : 172.31.0.0/16
CidrBlockAssociationSet     : {vpc-cidr-assoc-0a91XXXXXXXXXXX}
DhcpOptionsId               : dopt-0a71XXXXXXXXXXX
InstanceTenancy             : default
Ipv6CidrBlockAssociationSet : {}
IsDefault                   : True
OwnerId                     : 968XXXXXX
State                       : available
Tags                        : {}
VpcId                       : vpc-0f9XXXXXXXXXXXX

Note the VpcId and put it into the corresponding .auto.tvars.json file.

We can get the needed information about one or more subnets also by using PowerShell:

PS C:\TACG> Get-EC2Subnet

AssignIpv6AddressOnCreation   : False
AvailabilityZone              : eu-central-1b
AvailabilityZoneId            : euc1-az3
AvailableIpAddressCount       : 4091
CidrBlock                     : 172.31.32.0/20
CustomerOwnedIpv4Pool         :
DefaultForAz                  : True
EnableDns64                   : False
EnableLniAtDeviceIndex        : 0
Ipv6CidrBlockAssociationSet   : {}
Ipv6Native                    : False
MapCustomerOwnedIpOnLaunch    : False
MapPublicIpOnLaunch           : True
OutpostArn                    :
OwnerId                       : 968XXXXXX
PrivateDnsNameOptionsOnLaunch : Amazon.EC2.Model.PrivateDnsNameOptionsOnLaunch
State                         : available
SubnetArn                     : arn:aws:ec2:eu-central-1:968XXXXXX:subnet/subnet-02e91c49df134f849
SubnetId                      : subnet-02eXXXXXXXXXX
Tags                          : {Name}
VpcId                         : vpc-0f9XXXXXXXXXXXX

AssignIpv6AddressOnCreation   : False
AvailabilityZone              : eu-central-1a
AvailabilityZoneId            : euc1-az2
AvailableIpAddressCount       : 4089
CidrBlock                     : 172.31.16.0/20
CustomerOwnedIpv4Pool         :
DefaultForAz                  : True
EnableDns64                   : False
EnableLniAtDeviceIndex        : 0
Ipv6CidrBlockAssociationSet   : {}
Ipv6Native                    : False
MapCustomerOwnedIpOnLaunch    : False
MapPublicIpOnLaunch           : True
OutpostArn                    :
OwnerId                       : 968XXXXXX
PrivateDnsNameOptionsOnLaunch : Amazon.EC2.Model.PrivateDnsNameOptionsOnLaunch
State                         : available
SubnetArn                     : arn:aws:ec2:eu-central-1:968XXXXXX:subnet/subnet-07eXXXXXXXXXX
SubnetId                      : subnet-07eXXXXXXXXXX
Tags                          : {Name}
VpcId                         : vpc-0f9XXXXXXXXXXXX

AssignIpv6AddressOnCreation   : False
AvailabilityZone              : eu-central-1c
AvailabilityZoneId            : euc1-az1
AvailableIpAddressCount       : 4090
CidrBlock                     : 172.31.0.0/20
CustomerOwnedIpv4Pool         :
DefaultForAz                  : True
EnableDns64                   : False
EnableLniAtDeviceIndex        : 0
Ipv6CidrBlockAssociationSet   : {}
Ipv6Native                    : False
MapCustomerOwnedIpOnLaunch    : False
MapPublicIpOnLaunch           : True
OutpostArn                    :
OwnerId                       : 968XXXXXX
PrivateDnsNameOptionsOnLaunch : Amazon.EC2.Model.PrivateDnsNameOptionsOnLaunch
State                         : available
SubnetArn                     : arn:aws:ec2:eu-central-1:968XXXXXX:subnet/subnet-0359XXXXXXXXXXX
SubnetId                      : subnet-0359XXXXXXXXXXX
Tags                          : {Name}
VpcId                         : vpc-0f9XXXXXXXXXXXX

Note the SubnetID of the Availability Zone that you want to use and put it into the corresponding .auto.tvars.json file.

Getting the region in Amazon EC2 where the resources will be deployed

The currently configured default region can be found by using for example AWS CLI - open a PowerShell window and type:

PS C:\TACG> aws configure get region
eu-central-1

PS C:\TACG>

Write down the Location as we need to assign it to variables.

Getting the available AMI Image-IDs from Amazon EC2

We want to automatically deploy the virtual machines necessary for the DC and the CCs - so we need detailed configuration settings:

  • Set the credentials needed for allowing PowerShell to access the EC2 tenant:

PS C:\TACG> Set-AWSCredential -AccessKey AKIXXXXXXXXXXXXXXXX -SecretKey RiXXXXXXXXXXXXXXXXXXXXXXXXXX -StoreAs default

 

  • Get the available AMI images:

 

PS C:\TACG> Initialize-AWSDefaultConfiguration -ProfileName default -Region eu-central-1
PS C:\TACG> Get-SSMLatestEC2Image -Path ami-windows-latest -ProfileName default -Region eu-central-1

Name                                                      Value
----                                                      -----
EC2LaunchV2-Windows_Server-2016-English-Full-Base         ami-05da8c5b8c31e1071
Windows_Server-2016-English-Full-SQL_2014_SP3_Enterprise  ami-0792b126a5682d6e8
Windows_Server-2016-German-Full-Base                      ami-04482c384c5f44eba
Windows_Server-2016-Japanese-Full-SQL_2016_SP3_Standard   ami-06bae50c6434d597c
Windows_Server-2016-Japanese-Full-SQL_2017_Web            ami-069867bf028ce1d11
Windows_Server-2019-English-Core-EKS_Optimized-1.25       ami-0dc34920ee17ff0c7
Windows_Server-2019-Italian-Full-Base                     ami-0f6d5ffbe2b4e6daa
Windows_Server-2022-Japanese-Full-SQL_2019_Enterprise     ami-0ce4c5ab9a9ee18e0
Windows_Server-2022-Portuguese_Brazil-Full-Base           ami-0fe6028dce619a01c
amzn2-ami-hvm-2.0.20191217.0-x86_64-gp2-mono              ami-0f7a4c9d36399c73f
Windows_Server-2016-English-Deep-Learning                 ami-0873c2c3320a70d5b
Windows_Server-2016-Japanese-Full-SQL_2016_SP3_Web        ami-08565efb3c4b556ba
Windows_Server-2016-Korean-Full-Base                      ami-08a0270377841480d
Windows_Server-2019-English-STIG-Core                     ami-0b4eb638a465efce5
Windows_Server-2019-French-Full-Base                      ami-0443c855ecad9de50
Windows_Server-2022-English-Full-Base                     ami-0ad8b6fa068e0299a
...

 

Note the value of the AMI that you want to use - for example ami-0ad8b6fa068e0299a.

Getting the available VM sizes from Amazon EC2

We need to determine the available VM sizes. A PowerShell script helps us to list the available instance types on Amazon EC2:

PS C:\TACG> PS C:\TACG> (Get-EC2InstanceType -Region eu-central-1).Count
694

We need to filter the results to narrow down usable instances - we want to use instances with max. 4 vCPUs and max. 8 GB RAM:

PS C:\TACG> Get-EC2InstanceType -Region eu-central-1 | Select-Object -Property InstanceType, @{Name="vCPUs"; Expression={$_.VCpuInfo.DefaultVCpus}}, @{Name="Memory in GB"; Expression={$_.MemoryInfo.SizeInMiB / 1024}} | Where-Object {$_vCPUs -le 4 -and $_."Memory in GB" -le 8 } | Sort-Object InstanceType | Format-Table InstanceType,vCPUs,"Memory in GB"

InstanceType   vCPUs Memory in GB
------------   ----- ------------
a1.large           2            4
a1.medium          1            2
a1.xlarge          4            8
c3.large           2         3,75
c3.xlarge          4          7,5
c4.large           2         3,75
c4.xlarge          4          7,5
c5.large           2            4
c5.xlarge          4            8
c5a.large          2            4
c5a.xlarge         4            8
c5ad.large         2            4
c5ad.xlarge        4            8
c5d.large          2            4
c5d.xlarge         4            8
c5n.large          2         5,25
c6a.large          2            4
c6a.xlarge         4            8
c6g.large          2            4
c6g.medium         1            2
c6g.xlarge         4            8
c6gd.large         2            4
c6gd.medium        1            2
c6gd.xlarge        4            8
c6gn.large         2            4
c6gn.medium        1            2
c6gn.xlarge        4            8
c6i.large          2            4
c6i.xlarge         4            8
c6id.large         2            4
c6id.xlarge        4            8
c6in.large         2            4
c6in.xlarge        4            8
c7a.large          2            4
c7a.medium         1            2
c7a.xlarge         4            8
c7g.large          2            4
c7g.medium         1            2
c7g.xlarge         4            8
c7gd.large         2            4
c7gd.medium        1            2
c7gd.xlarge        4            8
c7i.large          2            4
c7i.xlarge         4            8
t2.large           2            8
t2.medium          2            4
t2.micro           1            1
t2.nano            1          0,5
t2.small           1            2
t3.large           2            8
t3.medium          2            4
t3.micro           2            1
t3.nano            2          0,5
t3.small           2            2
t3a.large          2            8
t3a.medium         2            4
t3a.micro          2            1
t3a.nano           2          0,5
t3a.small          2            2
t4g.large          2            8
t4g.medium         2            4
t4g.micro          2            1
t4g.nano           2          0,5
t4g.small          2            2
...

PS C:\TACG>

Note the Instancetype parameter of the Amazon EC2 Resource Location that you want to use. We use t3.medium and t3.large.
Be sure to use the Citrix Terraform Provider version 0.5.3 or higher or we need to pass the Instance type to the Terraform provider in a different format (examples):

Amazon EC2 syntax: Needed format:
t3.nano T3 Nano Instance
t3.small T3 Small Instance
t3.medium T3 Medium Instance
t3.large T3 Large Instance
e2.small E2 Small Instance
e2.medium E2 Medium Instance

Caution: Be sure that your subscription has no quota limitation on the chosen VM type and you have enough resources on Amazon EC2 to create all the Virtual Machines planned to put into the Machine Catalog by checking quotas - otherwise the creation of the Machine Catalog fails if there are not enough compute resources available! The AWS Quota code for Standard On-Demand instances is L-1216C47A.

Example: Checking the current quotas for the instances (N-family) which we plan to use in this guide:

PS C:\TACG> Install-AWSToolsModule AWS.Tools.ServiceQuotas
PS C:\TACG> Get-SQServiceList

ServiceCode             ServiceName
-----------             -----------
AWSCloudMap             AWS Cloud Map
access-analyzer         Access Analyzer
acm                     AWS Certificate Manager (ACM)
acm-pca                 AWS Private Certificate Authority
...
ec2                     Amazon Elastic Compute Cloud (Amazon EC2)
ec2-ipam                IPAM
ec2fastlaunch           EC2 Fast Launch
...

PS C:\TACG> Get-SQServiceQuota -ServiceCode ec2 -QuotaCode L-1216C47A

Adjustable          : True
ErrorReason         :
GlobalQuota         : False
Period              :
QuotaAppliedAtLevel : ACCOUNT
QuotaArn            : arn:aws:servicequotas:eu-central-1:9XXXXXXXXX:ec2/L-1216C47A
QuotaCode           : L-1216C47A
QuotaContext        :
QuotaName           : Running On-Demand Standard (A, C, D, H, I, M, R, T, Z) instances
ServiceCode         : ec2
ServiceName         : Amazon Elastic Compute Cloud (Amazon EC2)
Unit                : None
UsageMetric         : Amazon.ServiceQuotas.Model.MetricInfo
Value               : 256

PS C:\TACG>

 

The output of the cmdlet shows that we should have enough available resources on the instance level.
The quotas can be increased using the Amazon EC2 Console or PowerShell.
More information about increasing vCPU quotas can be found here: Amazon Elastic Compute Cloud (Amazon EC2) quotas.

Further Software Components for Configuration and Deployment

The Terraform deployment needs actual versions of the following software components:

These components are required during the workflow. The Terraform engine looks for these files. In this guide we anticipate that the necessary software can be downloaded from a Storage Repository - we use an Azure Storage Blob where all necessary software is uploaded to.
The URIs of the Storage Repository can be set in the corresponding variables:

  • For the Cloud Connector: "CC_Install_CWCURI":"https://wmwblob.blob.core.windows.net/tfdata/cwcconnector.exe"
  • For the Remote PowerShell SDK: "CC_Install_RPoSHURI":"https://wmwblob.blob.core.windows.net/tfdata/CitrixPoshSdk.exe"

Creating an Access Key with a Secret for Amazon EC2 Authentication in AWS CLI and/or AWS.Tools for PowerShell

Access Keys are long-term credentials for an IAM user or the root user which are used for Authentication and Authorization in EC2.
They consist of two parts: an Access Key-ID and a Secret Access Key. Both are needed for Authentication and Authorization.

deployment-guides-CCOnAWS-PreReqs-AWSCLI-IAM1.png

deployment-guides-CCOnAWS-PreReqs-AWSCLI-IAM2.png

deployment-guides-CCOnAWS-PreReqs-AWSCLI-IAM3.png

Further information about Access Key management and the configuration can be found in Managing access keys for IAM users.

The needed security information for the IAM Policies is stored in an EC2-Secrets Manager:

deployment-guides-CCOnAWS-PreReqs-SecretManager-1.png

deployment-guides-CCOnAWS-PreReqs-SecretManager-2.png

deployment-guides-CCOnAWS-PreReqs-SecretManager-3.png

deployment-guides-CCOnAWS-PreReqs-SecretManager-4.png

Further information about EC2-Secrets Manager and the configuration can be found at AWS Secrets Manager.

Creating a Secure Client in Citrix Cloud

The Secure Client in Citrix Cloud is the same as the Access Key in Amazon EC2. It is used for Authentication.
API clients in Citrix Cloud are always tied to one administrator and one customer. API clients are not visible to other administrators. If you want to access to more than one customer, you must create API clients within each customer.
API clients are automatically restricted to the rights of the administrator that created it. For example, if an administrator is restricted to access only notifications, then the administrator’s API clients have the same restrictions:

  • Reducing an administrator’s access also reduces the access of the API clients owned by that administrator
  • Removing an administrator’s access also removes the administrator’s API clients.

To create an API client, select the Identity and Access Management option from the menu. If this option does not appear, you do not have adequate permissions to create an API client. Contact your administrator to get the required permissions.

  1. Open Identity and Access Management in WebStudio:
    Creating an API Client in Citrix Cloud

  2. Click API Access, Secure Clients and put a name in the textbox next to the button Create Client. After entering a name. click Create Client:
    Creating an API Client in Citrix Cloud

  3. After the Secure Client is created, copy and write down the shown ID and Secret:
    Creating an API Client in Citrix Cloud

The Secret is only visible during creation - after closing the window you are not able to get it anymore.
The client-id and client-secret fields are needed by the Citrix Terraform provider.
The also needed customer-id field can be found in your Citrix Cloud details.

Put the values in the corresponding .auto.tvars.json file:

...
"cc-customerId": "uzXXXXXXXX",
"cc-apikey-clientId": "f4eXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"cc-apikey-clientSecret": "VXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"cc-apikey-type": "client_credentials",
...


Creating a Bearer Token in Citrix Cloud

The Bearer Token is needed for the Authorization of some REST-API calls in Citrix Cloud.
As the Citrix provider currently has not implemented all functionalities yet, some REST-API calls are still needed. The Bearer Token authorizes these calls.

It is important to set the URI to call and the required parameters correct: The URI must follow this syntax:
For example [https://api-us.cloud.com/cctrustoauth2/{customerid}/tokens/clients] where {customerid} is your Customer ID you obtained from the Account Settings page.
If your Customer ID is for example 1234567890, the URI is [https://api-us.cloud.com/cctrustoauth2/1234567890/tokens/clients]

In this example, we use the Postman application to create a Bearer Token:

  1. Paste the correct URI into Postman´s address bar and select POST as the method. Verify the correct settings of the API call.
    Creating a Bearer Token using Postman
    If everything is set correctly, Postman shows a Response containing a JSON-formatted file containing the Bearer token in the field access-token: The token is normally valid for 3600 seconds.

  2. Put the values in the corresponding .auto.tvars.json file:

    ...
    "cc-apikey-type": "client_credentials",
    "cc-apikey-bearer": "CWSAuth bearer=eyJhbGciOiJSUzI1NiIsI...0q0IW7SZFVzeBittWnEwTYOZ7Q
    "
    ...

NOTE: In this deployment, Terraform automatically requests a valid Bearer Token using a REST-API call from Citrix Cloud and stores the Bearer Token on the hard disk.
If subsequent needs for having a Bearer Token occur during script progress, Terraform loads the Bearer Token from the hard drive.

You can also use PowerShell to request a Bearer Token - therefore you need a valid Secure Client stored in Citrix Cloud:

asnp Citrix*
$key= "f4eXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
$secret= "VJCXXXXXXXXXXXXXX"
$customer= "uXXXXXXXX"
$XDStoredCredentials = Set-XDCredentials -StoreAs default -ProfileType CloudApi -CustomerId $customer -APIKey $key -SecretKey $secret
$auth = Get-XDAuthentication
$BT = $GLOBAL:XDAuthToken | Out-File "<Path where to store the Token\BT.txt" 

 

Module 1: Create the initially needed Resources on Amazon EC2

This module is split into the following configuration parts:

  • Creating the initially needed Resources on Amazon EC2:
    • Creating all needed IAM roles on Amazon EC2
    • Creating all needed IAM Instance profiles on Amazon EC2
    • Creating all needed IAM policies on Amazon EC2
    • Creating all needed Secret Manager configurations on Amazon EC2
    • Creating all needed DHCP configurations on Amazon EC2
    • Creating a Windows Server 2022-based Master Image VM used for deploying the Machine Catalog in step 3
    • Creating two Windows Server 2022-based VMs which will be used as Cloud Connector VMs in step 2
    • Creating a Windows Server 2022-based VM acting as an Administrative workstation for running the Terraform steps 2 and 3 - this is necessary because of using WinRM for further configuration and deployment in steps 2 and 3!
    • Creating all necessary scripts for joining the VMs to the existing sub-domain
    • Putting the VMs into the existing subdomain
    • Fetching and saving a valid Bearer Token

All these steps are automatically done by Terraform.

NOTE: This first part is separated from the next steps as we assume that there is no Admin-VM installed in the corresponding VPC/Subnet. The Admin-VM is created now in Module 1 and all further modules must be run from it. Working with WinRM calls over the Internet would pose a security threat and would significantly reduce the performance of the Terraform-based deployment. These are the reasons for the split approach!

Please make sure you have configured the variables according to your needs.

The configuration can be started by following the normal Terraform workflow:
terraform init,
terraform plan
and if no errors occur

terraform apply

PS C:\TACG\_CCOnAWS\_CCOnAWS-Creation> terraform init


Initializing the backend...

Initializing provider plugins...
- terraform.io/builtin/terraform is built in to Terraform
- Finding mastercard/restapi versions matching "1.18.2"...
- Finding citrix/citrix versions matching ">= 0.5.0"...
- Finding hashicorp/aws versions matching ">= 5.4.0"...
- Finding latest version of hashicorp/local...
- Finding latest version of hashicorp/template...
- Installing hashicorp/local v2.5.1...
- Installed hashicorp/local v2.5.1 (signed by HashiCorp)
- Installing hashicorp/template v2.2.0...
- Installed hashicorp/template v2.2.0 (signed by HashiCorp)
- Installing mastercard/restapi v1.18.2...
- Installed mastercard/restapi v1.18.2 (self-signed, key ID DCB8C431D71C30AB)
- Installing citrix/citrix v0.5.2...
- Installed citrix/citrix v0.5.2 (signed by a HashiCorp partner, key ID 25D62DD8407EA386)
- Installing hashicorp/aws v5.41.0...
- Installed hashicorp/aws v5.41.0 (signed by HashiCorp)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

PS C:\TACG\_CCOnAWS\_CCOnAWS-Creation>

PS C:\TACG\_CCOnAWS\_CCOnAWS-Creation> terraform plan
data.template_file.Add-EC2InstanceToDomainScriptCC2: Reading...
data.template_file.Add-EC2InstanceToDomainScriptWMI: Reading...
data.template_file.Add-EC2InstanceToDomainScriptAdminVM: Reading...
data.template_file.Add-EC2InstanceToDomainScriptCC1: Reading...
data.template_file.Add-EC2InstanceToDomainScriptWMI: Read complete after 0s [id=85de6bac9e35231cbd60a4c1636a554940abb789938916a626a5193f27f22498]
data.template_file.Add-EC2InstanceToDomainScriptCC1: Read complete after 0s [id=24ee722eca6982b33be472de4f84edbae000d0bff0a139dec2ce97c8ea14a0ca]
data.template_file.Add-EC2InstanceToDomainScriptAdminVM: Read complete after 0s [id=91b3ae99f8d4a2effb377f35dda69a583de194739c8191ee665c96e663ad8615]
data.template_file.Add-EC2InstanceToDomainScriptCC2: Read complete after 0s [id=15075f0d18ca3e200ab603e397339245a8ff055fd688facfc5165dd5e455d151]
data.aws_iam_policy_document.ec2_assume_role: Reading...
data.aws_iam_policy_document.ec2_assume_role: Read complete after 0s [id=2851119427]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # data.local_file.Retrieve_BT will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "local_file" "Retrieve_BT" {
      + content              = (known after apply)
      + content_base64       = (known after apply)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + filename             = "./GetBT.txt"
      + id                   = (known after apply)
    }

  # aws_iam_instance_profile.ec2_profile will be created
  + resource "aws_iam_instance_profile" "ec2_profile" {
      + arn         = (known after apply)
      + create_date = (known after apply)
      + id          = (known after apply)
      + name        = "ec2-profile"
      + name_prefix = (known after apply)
      + path        = "/"
      + role        = "ec2-iam-role"
      + tags_all    = (known after apply)
      + unique_id   = (known after apply)
    }

  # aws_iam_policy.secret_manager_ec2_policy will be created
  + resource "aws_iam_policy" "secret_manager_ec2_policy" {
      + arn         = (known after apply)
      + description = "Secret Manager EC2 policy"
      + id          = (known after apply)
      + name        = "secret-manager-ec2-policy"
      + name_prefix = (known after apply)
      + path        = "/"
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "secretsmanager:*",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + policy_id   = (known after apply)
      + tags_all    = (known after apply)
    }

  # aws_iam_policy_attachment.api_secret_manager_ec2_attach will be created
  + resource "aws_iam_policy_attachment" "api_secret_manager_ec2_attach" {
      + id         = (known after apply)
      + name       = "secret-manager-ec2-attachment"
      + policy_arn = (known after apply)
      + roles      = (known after apply)
    }

  # aws_iam_policy_attachment.ec2_attach1 will be created
  + resource "aws_iam_policy_attachment" "ec2_attach1" {
      + id         = (known after apply)
      + name       = "ec2-iam-attachment"
      + policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
      + roles      = (known after apply)
    }

  # aws_iam_policy_attachment.ec2_attach2 will be created
  + resource "aws_iam_policy_attachment" "ec2_attach2" {
      + id         = (known after apply)
      + name       = "ec2-iam-attachment"
      + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
      + roles      = (known after apply)
    }

  # aws_iam_role.ec2_iam_role will be created
  + resource "aws_iam_role" "ec2_iam_role" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ec2.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "ec2-iam-role"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)
    }

  # aws_instance.AdminVM will be created
  + resource "aws_instance" "AdminVM" {
      + ami                                  = "ami-0ad8b6fa068e0299a"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.large"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (sensitive value)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = "172.31.22.107"
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = "subnet-07e1XXXXXXXXXX"
      + tags                                 = {
          + "Name" = "TACG-AWS-AVM"
        }
      + tags_all                             = {
          + "Name" = "TACG-AWS-AVM"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "975296c878XXXXXXXXXX"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = [
          + "sg-072eXXXXXXXXXX",
        ]
    }

  # aws_instance.CC1 will be created
  + resource "aws_instance" "CC1" {
      + ami                                  = "ami-0ad8b6fa068e0299a"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.medium"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (sensitive value)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = "172.31.22.104"
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = "subnet-07e1XXXXXXXXXX"
      + tags                                 = {
          + "Name" = "TACG-AWS-CC1"
        }
      + tags_all                             = {
          + "Name" = "TACG-AWS-CC1"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "5daf6ab616e8eXXXXXXXXXX"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = [
          + "sg-072eXXXXXXXXXX",
        ]
    }

  # aws_instance.CC2 will be created
  + resource "aws_instance" "CC2" {
      + ami                                  = "ami-0ad8b6fa068e0299a"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.medium"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (sensitive value)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = "172.31.22.105"
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = "subnet-07e1XXXXXXXXXX"
      + tags                                 = {
          + "Name" = "TACG-AWS-CC2"
        }
      + tags_all                             = {
          + "Name" = "TACG-AWS-CC2"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "71b8c58dcf57XXXXXXXXXX"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = [
          + "sg-072eXXXXXXXXXX",
        ]
    }

  # aws_instance.WMI will be created
  + resource "aws_instance" "WMI" {
      + ami                                  = "ami-0ad8b6fa068e0299a"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.medium"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (sensitive value)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = "172.31.22.106"
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = "subnet-07e168f0c2a28edf3"
      + tags                                 = {
          + "Name" = "TACG-AWS-WMI"
        }
      + tags_all                             = {
          + "Name" = "TACG-AWS-WMI"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "bd599dcdaa3dXXXXXXXXXXX"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = [
          + "sg-072eXXXXXXXXXX",
        ]
    }

  # aws_vpc_dhcp_options.vpc-dhcp-options will be created
  + resource "aws_vpc_dhcp_options" "vpc-dhcp-options" {
      + arn                 = (known after apply)
      + domain_name_servers = [
          + "172.31.22.103",
        ]
      + id                  = (known after apply)
      + owner_id            = (known after apply)
      + tags_all            = (known after apply)
    }

  # aws_vpc_dhcp_options_association.dns_resolver will be created
  + resource "aws_vpc_dhcp_options_association" "dns_resolver" {
      + dhcp_options_id = (known after apply)
      + id              = (known after apply)
      + vpc_id          = "vpc-0f9aXXXXXXXXXX"
    }

  # local_file.GetBearerToken will be created
  + resource "local_file" "GetBearerToken" {
      + content              = (sensitive value)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./GetBT.ps1"
      + id                   = (known after apply)
    }

  # terraform_data.GetBT will be created
  + resource "terraform_data" "GetBT" {
      + id = (known after apply)
    }

Plan: 14 to add, 0 to change, 0 to destroy.

PS C:\TACG\_CCOnAWS\_CCOnAWS-Creation>

PS C:\TACG\_CCOnAWS\_CCOnAWS-Creation> terraform apply

data.template_file.Add-EC2InstanceToDomainScriptCC2: Reading...
data.template_file.Add-EC2InstanceToDomainScriptWMI: Reading...
data.template_file.Add-EC2InstanceToDomainScriptAdminVM: Reading...
data.template_file.Add-EC2InstanceToDomainScriptCC1: Reading...
data.template_file.Add-EC2InstanceToDomainScriptWMI: Read complete after 0s [id=85de6bac9e35231cbd60a4c1636a554940abb789938916a626a5193f27f22498]
data.template_file.Add-EC2InstanceToDomainScriptCC1: Read complete after 0s [id=24ee722eca6982b33be472de4f84edbae000d0bff0a139dec2ce97c8ea14a0ca]
data.template_file.Add-EC2InstanceToDomainScriptAdminVM: Read complete after 0s [id=91b3ae99f8d4a2effb377f35dda69a583de194739c8191ee665c96e663ad8615]
data.template_file.Add-EC2InstanceToDomainScriptCC2: Read complete after 0s [id=15075f0d18ca3e200ab603e397339245a8ff055fd688facfc5165dd5e455d151]
data.aws_iam_policy_document.ec2_assume_role: Reading...
data.aws_iam_policy_document.ec2_assume_role: Read complete after 0s [id=2851119427]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # data.local_file.Retrieve_BT will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "local_file" "Retrieve_BT" {
      + content              = (known after apply)
      + content_base64       = (known after apply)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + filename             = "./GetBT.txt"
      + id                   = (known after apply)
    }

... ** Output shortened **... 

  # terraform_data.GetBT will be created
  + resource "terraform_data" "GetBT" {
      + id = (known after apply)
    }

Plan: 14 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.AdminVM: Creating...
aws_instance.AdminVM: Still creating... [10s elapsed]
aws_instance.AdminVM: Still creating... [20s elapsed]
aws_instance.AdminVM: Creation complete after 22s [id=i-0ad3352d673db8068]

... ** Output shortened **... 

aws_instance.WMI: Creating...
aws_instance.WMI: Still creating... [10s elapsed]
aws_instance.WMI: Still creating... [20s elapsed]
aws_instance.WMI: Still creating... [30s elapsed]
aws_instance.WMI: Creation complete after 34s [id=i-0ad3352d673db8068]
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.

PS C:\TACG\_CCOnAWS\_CCOnAWS-Creation>

 

As no errors occurred, Terraform has completed the creation and partial configuration of the relevant prerequisites on Amazon EC2.

Example of successful creation:
All VMs were successfully created and registered on the Domain Controller:

deployment-guides-CCOnAWS-PreReqs-AllVMsCreated.png

deployment-guides-CCOnAWS-PreReqs-AllVMsRegistered.png

Now the next step can be started.

Module 2: Install and Configure all Resources in Amazon EC2

IMPORTANT: This module can only be run on the previously created Administrative VM as the deployment of steps 2 and 3 relies heavily on WinRM! Please install Terraform on the Administrative VM before trying to run the scripts!

This module is split into the following configuration parts:

  • Configuring the three previously created Virtual Machines on Amazon EC2:

    • Installing the needed software on the CCs
    • Installing the needed software on the Admin-VM
  • Creating the necessary Resources in Citrix Cloud:

    • Creating a Resource Location in Citrix Cloud
    • Configuring the 2 CCs as Cloud Connectors
    • Registering the 2 CCs in the newly created Resource Location

NOTE: This module has some complexity as many automated actions and many different entities are created on Amazon EC2 and run on the VMs. It contains a mixture of PowerShell scripts, REST-API calls, and Terraform scripts to achieve a working deployment.

Our provider currently does not support creating a Resource Location on Citrix Cloud. Therefore we use a PowerShell script to create it using a REST-API call.

Please make sure you have configured the variables according to your needs by using the corresponding .auto.tfvars.json file.

Terraform runs various scripts before creating the configuration of the CCs to determine needed information like the Site-ID, the Zone-ID, and the Resource Location-ID.
These IDs are used in other scripts or files - for example the parameter file for deploying the Cloud Connector needs the Resource Location ID of the Resource Location which Terraform creates automatically. Unfortunately the REST-API provider does not return the ID of the newly created Resource Location, so we need to run PowerShell after the creation of the Resource Location:

Examples of necessary scripts:
At first, Terraform writes the configuration file without the Resource Location ID:

#### Create CWC-Installer configuration file based on variables and save it into Transfer directory
resource "local_file" "CWC-Configuration" {
  depends_on = [restapi_object.CreateRL]
  content  = jsonencode(
        {
        "customerName" = "${var.CC_CustomerID}",
        "clientId" = "${var.CC_APIKey-ClientID}",
        "clientSecret" = "${var.CC_APIKey-ClientSecret}",
        "resourceLocationId" = "XXXXXXXXXX",
        "acceptTermsOfService" = true
        }
      )
  filename = "${var.CC_Install_LogPath}/DATA/cwc.json"
 
}

 

IMPORTANT
The Terraform script will pause for 600 seconds after creation of the Resource Location! This is because of time constraints in the back-end - the creation of the Zone related to the Resource Location needs some time - we have seen delays up to 8 minutes before the Zone was created. If the script would proceed too fast, the Zone ID readout would fail and the Terraform script would not be able to continue successfully!


After installing further pre-requisites, Terraform runs a PowerShell script to get the needed ID and updates the configuration file for the CWC installer:

#### Create PowerShell file for determining the correct RL-ID
resource "local_file" "InstallPreReqsOnAVM2-ps1" {
content  = <<-EOT
#### Need to invoke PowerShell as Domain User as the provisioner does not allow to be run in a Domain Users-context
$PSUsername = '${var.Provisioner_DomainAdmin-Username}'
$PSPassword = '${var.Provisioner_DomainAdmin-Password}'
$PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
$PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
$path = "${var.CC_Install_LogPath}"
# Correct the Resource Location ID in cwc.json file
$requestUri = "https://api-eu.cloud.com/resourcelocations"
$headers = @{ "Accept"="application/json"; "Authorization" = "${var.CC_APIKey-Bearer}"; "Citrix-CustomerId" = "${var.CC_CustomerID}"}
$response = Invoke-RestMethod -Uri $requestUri -Method GET -Headers $headers | Convertto-Json
$RLs = ConvertFrom-Json $response
$RLFiltered = $RLs.items | Where-Object name -in "${var.CC_RestRLName}"
Add-Content ${var.CC_Install_LogPath}/log.txt $RLFiltered
$RLID = $RLFiltered.id
$OrigContent = Get-Content ${var.CC_Install_LogPath}/DATA/cwc.json
Add-Content ${var.CC_Install_LogPath}/log.txt $RLID
Add-Content ${var.CC_Install_LogPath}/log.txt $OrigContent
$CorrContent = $OrigCOntent.Replace('XXXXXXXXXX', $RLID) | Out-File -FilePath ${var.CC_Install_LogPath}/DATA/cwc.json
Add-Content ${var.CC_Install_LogPath}/DATA/GetRLID.txt $RLID
Add-Content ${var.CC_Install_LogPath}/log.txt "`ncwc.json corrected."
Add-Content ${var.CC_Install_LogPath}/log.txt "`nScript completed."
}
EOT
filename = "${path.module}/DATA/InstallPreReqsOnAVM2.ps1"
}

The Terraform configuration contains some idle time slots to make sure that background operations on Amazon EC2 or on the VMs can be completed before the next configuration steps occur.
We have seen different elapsed configuration times related to different loads on the Amazon EC2 systems!

Before running Terraform, we cannot see the Resource Location:

 

The configuration can be started by following the normal Terraform workflow:
terraform init,
terraform plan
and if no errors occur

terraform apply

PS C:\TACG\_CCOnAWS\_CCOnAWS-Install> terraform init

Initializing the backend...

Initializing provider plugins...
- terraform.io/builtin/terraform is built in to Terraform
- Finding latest version of hashicorp/random...
- Finding latest version of hashicorp/time...
- Finding latest version of hashicorp/local...
- Finding latest version of hashicorp/null...
- Finding hashicorp/aws versions matching ">= 5.4.0"...
- Finding mastercard/restapi versions matching "1.18.2"...
- Finding citrix/citrix versions matching ">= 0.5.2"...
- Installing citrix/citrix v0.5.2...
- Installed citrix/citrix v0.5.2 (signed by a HashiCorp partner, key ID 25D62DD8407EA386)
- Installing hashicorp/random v3.6.0...
- Installed hashicorp/random v3.6.0 (signed by HashiCorp)
- Installing hashicorp/time v0.11.1...
- Installed hashicorp/time v0.11.1 (signed by HashiCorp)
- Installing hashicorp/local v2.5.1...
- Installed hashicorp/local v2.5.1 (signed by HashiCorp)
- Installing hashicorp/null v3.2.2...
- Installed hashicorp/null v3.2.2 (signed by HashiCorp)
- Installing hashicorp/aws v5.41.0...
- Installed hashicorp/aws v5.41.0 (signed by HashiCorp)
- Installing mastercard/restapi v1.18.2...
- Installed mastercard/restapi v1.18.2 (self-signed, key ID DCB8C431D71C30AB)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

PS C:\TACG\_CCOnAWS\_CCOnAWS-Install>

PS C:\TACG\_CCOnAWS\_CCOnAWS-Install> terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # data.local_file.input_site will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "local_file" "input_site" {
      + content              = (known after apply)
      + content_base64       = (known after apply)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + filename             = "c:/temp/xdinst/DATA/GetSiteID.txt"
      + id                   = (known after apply)
    }

  ... ** Output shortened **... 

  # terraform_data.SiteID will be created
  + resource "terraform_data" "SiteID" {
      + id = (known after apply)
    }

  # terraform_data.ZoneID will be created
  + resource "terraform_data" "ZoneID" {
      + id = (known after apply)
    }

  # time_sleep.wait_300_seconds will be created
  + resource "time_sleep" "wait_300_seconds" {
      + create_duration = "300s"
      + id              = (known after apply)
    }

Plan: 18 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
PS C:\TACG\_CCOnAWS\_CCOnAWS-Install>

PS C:\TACG\_CCOnAWS\_CCOnAWS-Install> terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # data.local_file.input_site will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "local_file" "input_site" {
      + content              = (known after apply)
      + content_base64       = (known after apply)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + filename             = "c:/temp/xdinst/DATA/GetSiteID.txt"
      + id                   = (known after apply)
    }

  # local_file.CWC-Configuration will be created
  + resource "local_file" "CWC-Configuration" {
      + content              = (sensitive value)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "c:/temp/xdinst/DATA/cwc.json"
      + id                   = (known after apply)
    }

... ** Output shortened **... 

  # terraform_data.SiteID will be created
  + resource "terraform_data" "SiteID" {
      + id = (known after apply)
    }

  # terraform_data.ZoneID will be created
  + resource "terraform_data" "ZoneID" {
      + id = (known after apply)
    }

  # time_sleep.wait_300_seconds will be created
  + resource "time_sleep" "wait_300_seconds" {
      + create_duration = "300s"
      + id              = (known after apply)
    }

Plan: 18 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

time_sleep.wait_300_seconds: Creating...
random_uuid.IDforCCRL: Creating...
random_uuid.IDforCCRL: Creation complete after 0s [id=76ef126a-4b14-cc24-e067-62dbf8c98d5c]
local_file.InstallPreReqsOnCC-ps1: Creating...
local_file.InstallPreReqsOnAVM1-ps1: Creating...
local_file.InstallPreReqsOnAVM2-ps1: Creating...
local_file.InstallPreReqsOnAVM1-ps1: Creation complete after 0s [id=c4e0ae63ee7a4c5ce89827fcf741942c19ae7aa0]
local_file.InstallPreReqsOnCC-ps1: Creation complete after 0s [id=1927ce7666e1be3a10049619e515d97c2f1e031d]
restapi_object.CreateRL: Creating...
local_file.InstallPreReqsOnAVM2-ps1: Creation complete after 0s [id=dccb6ef781887e459e04d6c3866871fbc11d9868]
restapi_object.CreateRL: Creation complete after 1s [id=76ef126a-4b14-cc24-e067-62dbf8c98d5c]
local_file.CWC-Configuration: Creating...
local_file.CWC-Configuration: Creation complete after 0s [id=0257d2b92f197fa4d043b6cd4c4959be284dddc2]
time_sleep.wait_300_seconds: Still creating... [10s elapsed]
time_sleep.wait_300_seconds: Still creating... [20s elapsed]
time_sleep.wait_300_seconds: Still creating... [30s elapsed]
time_sleep.wait_300_seconds: Still creating... [40s elapsed]
time_sleep.wait_300_seconds: Still creating... [50s elapsed]

... ** Output shortened **... 

time_sleep.wait_300_seconds: Still creating... [4m31s elapsed]
time_sleep.wait_300_seconds: Still creating... [4m41s elapsed]
time_sleep.wait_300_seconds: Still creating... [4m51s elapsed]
time_sleep.wait_300_seconds: Creation complete after 5m0s [id=2024-03-15T09:29:54Z]
local_file.GetSiteIDScript: Creating...
local_file.GetSiteIDScript: Creation complete after 0s [id=11e3d863bb343b8e10beca1d1b8d2e1918aff757]
terraform_data.SiteID: Creating...
terraform_data.SiteID: Provisioning with 'local-exec'...
terraform_data.SiteID (local-exec): Executing: ["PowerShell" "-File" "GetSiteID.ps1"]
null_resource.UploadRequiredComponentsToAVM: Creating...
null_resource.UploadRequiredComponentsToAVM: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>terraform_data.SiteID: Creation complete after 2s [id=d8069268-d023-dc1f-b6e3-5eb4a96d7e34]
data.local_file.input_site: Reading...
data.local_file.input_site: Read complete after 0s [id=f684114a2b93cc095c4ac5f81999ee1a111d53b9]
local_file.GetZoneIDScript: Creating...
local_file.GetZoneIDScript: Creation complete after 0s [id=acf533cb047cc8f963f8bf53b792f236eb8d9cd3]
terraform_data.ZoneID: Creating...
terraform_data.ZoneID: Provisioning with 'local-exec'...
terraform_data.ZoneID (local-exec): Executing: ["PowerShell" "-File" "GetZoneID.ps1"]
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToAVM: Provisioning with 'file'...
terraform_data.ZoneID: Creation complete after 0s [id=560905f8-976a-56ff-a73a-95f287a69761]
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToAVM: Creation complete after 3s [id=1331150174844471895]
null_resource.CallRequiredScriptsOnAVM1: Creating...
null_resource.CallRequiredScriptsOnAVM1: Provisioning with 'remote-exec'...
null_resource.CallRequiredScriptsOnAVM1 (remote-exec): Connecting to remote host via WinRM...
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   Host: 172.31.22.107
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   Port: 5985
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   User: administrator
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   Password: true
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   HTTPS: false
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   Insecure: false
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   NTLM: false
null_resource.CallRequiredScriptsOnAVM1 (remote-exec):   CACert: false
null_resource.CallRequiredScriptsOnAVM1 (remote-exec): Connected!
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
null_resource.CallRequiredScriptsOnAVM1 (remote-exec): C:\Users\Administrator>powershell -File c:/temp/xdinst/DATA/InstallPreReqsOnAVM1.ps1
null_resource.CallRequiredScriptsOnAVM1: Still creating... [10s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [20s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [30s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [40s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [50s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [1m0s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [1m11s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [1m21s elapsed]
null_resource.CallRequiredScriptsOnAVM1: Still creating... [1m31s elapsed]
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.CallRequiredScriptsOnAVM1: Creation complete after 1m32s [id=1765564400293269918]
null_resource.CallRequiredScriptsOnAVM2: Creating...
null_resource.CallRequiredScriptsOnAVM2: Provisioning with 'remote-exec'...
null_resource.CallRequiredScriptsOnAVM2 (remote-exec): Connecting to remote host via WinRM...
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   Host: 172.31.22.107
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   Port: 5985
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   User: administrator
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   Password: true
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   HTTPS: false
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   Insecure: false
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   NTLM: false
null_resource.CallRequiredScriptsOnAVM2 (remote-exec):   CACert: false
null_resource.CallRequiredScriptsOnAVM2 (remote-exec): Connected!
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
null_resource.CallRequiredScriptsOnAVM2 (remote-exec): C:\Users\Administrator>powershell -File c:/temp/xdinst/DATA/InstallPreReqsOnAVM2.ps1
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.CallRequiredScriptsOnAVM2: Creation complete after 3s [id=1571484748961023525]
null_resource.UploadRequiredComponentsToCC1: Creating...
null_resource.UploadRequiredComponentsToCC2: Creating...
null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
null_resource.UploadRequiredComponentsToCC2: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Provisioning with 'file'...

... ** Output shortened **... 

#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Creation complete after 8s [id=2593060114553604983]
null_resource.CallRequiredScriptsOnCC2: Creating...
null_resource.CallRequiredScriptsOnCC2: Provisioning with 'remote-exec'...
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Connecting to remote host via WinRM...
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Host: 172.31.22.107
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Port: 5985
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   User: administrator
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Password: true
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   HTTPS: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Insecure: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   NTLM: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   CACert: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Connected!
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj><Obj S="progress" RefId="1"><TNRef RefId="0" /><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
null_resource.CallRequiredScriptsOnCC2 (remote-exec): C:\Users\Administrator>powershell -File c:/temp/xdinst/InstallPreReqsOnCC.ps1}
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Windows PowerShell
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Processing -File 'c:/temp/xdinst/InstallPreReqsOnCC.ps1}'
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Copyright (C) Microsoft Corporation. All rights reserved.

null_resource.CallRequiredScriptsOnCC2 (remote-exec): Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows

null_resource.UploadRequiredComponentsToCC1: Still creating... [10s elapsed]
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Creation complete after 15s [id=2911410724639395293]
null_resource.CallRequiredScriptsOnCC1: Creating...
null_resource.CallRequiredScriptsOnCC1: Provisioning with 'remote-exec'...
null_resource.CallRequiredScriptsOnCC1 (remote-exec): Connecting to remote host via WinRM...
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Host: 172.31.22.107
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Port: 5985
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   User: administrator
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Password: true
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   HTTPS: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Insecure: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   NTLM: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   CACert: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec): Connected!
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Provisioning with 'file'...
null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...

... ** Output shortened **... 

#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Provisioning with 'file'...
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC1: Creation complete after 7s [id=8529594446213212779]
null_resource.CallRequiredScriptsOnCC1: Creating...
null_resource.CallRequiredScriptsOnCC1: Provisioning with 'remote-exec'...
null_resource.CallRequiredScriptsOnCC1 (remote-exec): Connecting to remote host via WinRM...
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Host: 172.31.22.107
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Port: 5985
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   User: administrator
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Password: true
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   HTTPS: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   Insecure: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   NTLM: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec):   CACert: false
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>null_resource.UploadRequiredComponentsToCC2: Creation complete after 8s [id=5071991036813727940]
null_resource.CallRequiredScriptsOnCC2: Creating...
null_resource.CallRequiredScriptsOnCC2: Provisioning with 'remote-exec'...
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Connecting to remote host via WinRM...
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Host: 172.31.22.107
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Port: 5985
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   User: administrator
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Password: true
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   HTTPS: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   Insecure: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   NTLM: false
null_resource.CallRequiredScriptsOnCC2 (remote-exec):   CACert: false
null_resource.CallRequiredScriptsOnCC1 (remote-exec): Connected!
null_resource.CallRequiredScriptsOnCC2 (remote-exec): Connected!
#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>#< CLIXML
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj S="progress" RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCustomObject</T><T>System.Object</T></TN><MS><I64 N="SourceId">1</I64><PR N="Record"><AV>Preparing modules for first use.</AV><AI>0</AI><Nil /><PI>-1</PI><PC>-1</PC><T>Completed</T><SR>-1</SR><SD> </SD></PR></MS></Obj></Objs>
null_resource.CallRequiredScriptsOnCC1 (remote-exec): C:\Users\Administrator>powershell -File c:/temp/xdinst/DATA/InstallPreReqsOnCC.ps1

... ** Output shortened **... 

Apply complete! Resources: 18 added, 0 changed, 0 destroyed.
PS C:\TACG\_CCOnAWS\_CCOnAWS-Install>

This configuration completes the creation and configuration of all initial resources:

  • Installing the needed software on the CCs
  • Creating a Resource Location in Citrix Cloud
  • Configuring the 2 CCs as Cloud Connectors
  • Registering the 2 CCs in the newly created Resource Location

deployment-guides-CCOnAWS-PreReqs-CWCIsInstalling.png

deployment-guides-CCOnAWS-PreReqs-CWCIsComplete.png

After successful runs of all needed scripts we can see the new Resource Location in Citrix Cloud and the 2 Cloud Connectors bound to the Resource Location:

deployment-guides-CCOnAWS-CC-RLs-Created.png

deployment-guides-CCOnAWS-PreReqs-CWCUp.png

The environment is now ready to deploy a Machine Catalog and a Delivery Group using Module 3.

Module 3: Create all Resources in Amazon EC2 and Citrix Cloud

This module is split into the following configuration parts:

  1. Creating a Hypervisor Connection to Amazon EC2 and a Hypervisor Pool
  2. Creating a Machine Catalog (MC) in the newly created Resource Location
  3. Creating a Delivery Group (DG) based on the MC in the newly created Resource Location
  4. Deploying some example policies using Terraform

The Terraform configuration contains some idle time slots to make sure that background operations on Amazon EC2 or the VMs can be completed before the next configuration steps occur.
We have seen different elapsed configuration times related to different loads on the Amazon EC2 systems! Before Terraform can create the Hypervisor Connection and the Hypervisor Pool, Terraform needs to retrieve the Site-ID and Zone-ID of the newly created Resource Location. As the Citrix Terraform Provider currently has no Cloud-level functionalities implemented, Terraform needs PowerShell scripts to retrieve the IDs. It created the necessary scripts with all the needed variables, saved the scripts, and ran them in Module 2.

NOTE: The Citrix Remote PowerShell SDK must be installed on the machine running Terraform as Terraform relies on the SDK!

After retrieving the IDs, Terraform configures a Hypervisor Connection to Amazon EC2 and a Hypervisor Resource Pool associated with the Hypervisor Connection. When these prerequisites are completed, the Machine Catalog is created. After the successful creation of the Hypervisor Connection, the Hypervisor Resource Pool, and the Machine Catalog the last step of the deployment process starts - the creation of the Delivery Group.

The Terraform configuration assumes that all machines in the created Machine Catalog are used in the Delivery Group and that Autoscale will be configured for this Delivery Group.
More information about Autoscale can be found here: https://docs.citrix.com/en-us/tech-zone/learn/tech-briefs/autoscale.html

NOTE: This module has some complexity as many automated actions and many different entities are created. The entities can be configured using the corresponding .auto.tfvars.json file.

The deployment of Citrix Policies is a new feature that was built-in in version 0.5.2.
We need to know the internal policy name as localized policy names and descriptions are not usable.
Therefore we need to use a PowerShell script to determine all internal names - some pre-requisites are necessary for the script to work.
You can need any machine but the Cloud Connectors!

Import-Module "C:\TACG\Supportability Pack\Tools\Scout\Current\Utilities\Citrix.GroupPolicy.commands.psm1" -force

new-psdrive -name LocalFarmGpo -psprovider CitrixGroupPolicy -controller localhost \
Get-PSDrive
cd LocalFarmGpo:
Get-CtxGroupPolicyConfiguration 

Type:  User
ProfileLoadTimeMonitoring_Threshold      
ICALatencyMonitoring_Enable              
ICALatencyMonitoring_Period              
ICALatencyMonitoring_Threshold           
EnableLossless                           
ProGraphics                              
FRVideos_Part                            
FRVideosPath_Part                        
FRStartMenu_Part                         
FRStartMenuPath_Part                     
FRSearches_Part                          
FRSearchesPath_Part                      
FRSavedGames_Part                        
FRSavedGamesPath_Part                    
FRPictures_Part                          
FRPicturesPath_Part                      
FRMusic_Part                             
FRMusicPath_Part                         
FRLinks_Part                             
FRLinksPath_Part                         
FRFavorites_Part                         
FRFavoritesPath_Part                     
FRDownloads_Part                         
FRDownloadsPath_Part                     
FRDocuments_Part                         
FRDocumentsPath_Part                     
FRDesktop_Part                           
FRDesktopPath_Part                       
FRContacts_Part                          
FRContactsPath_Part                      
FRAdminAccess_Part                       
FRIncDomainName_Part                     
FRAppData_Part                           
FRAppDataPath_Part                       
StorefrontAccountsList                   
AllowFidoRedirection                     
AllowWIARedirection                      
ClientClipboardWriteAllowedFormats       
ClipboardRedirection                     
ClipboardSelectionUpdateMode             
DesktopLaunchForNonAdmins                
DragDrop                                 
LimitClipboardTransferC2H                
LimitClipboardTransferH2C                
LossTolerantModeAvailable                
NonPublishedProgramLaunching             
PrimarySelectionUpdateMode               
ReadonlyClipboard                        
RestrictClientClipboardWrite             
RestrictSessionClipboardWrite            
SessionClipboardWriteAllowedFormats      
FramesPerSecond                          
PreferredColorDepthForSimpleGraphics     
VisualQuality                            
ExtraColorCompression                    
ExtraColorCompressionThreshold           
LossyCompressionLevel                    
LossyCompressionThreshold                
ProgressiveHeavyweightCompression        
MinimumAdaptiveDisplayJpegQuality        
MovingImageCompressionConfiguration      
ProgressiveCompressionLevel              
ProgressiveCompressionThreshold          
TargetedMinimumFramesPerSecond           
ClientUsbDeviceOptimizationRules         
UsbConnectExistingDevices                
UsbConnectNewDevices                     
UsbDeviceRedirection                     
UsbDeviceRedirectionRules                
USBDeviceRulesV2                         
UsbPlugAndPlayRedirection                
TwainCompressionLevel                    
TwainRedirection                         
LocalTimeEstimation                      
RestoreServerTime                        
SessionTimeZone                          
EnableSessionWatermark                   
WatermarkStyle                           
WatermarkTransparency                    
WatermarkCustomText                      
WatermarkIncludeClientIPAddress          
WatermarkIncludeConnectTime              
WatermarkIncludeLogonUsername            
WatermarkIncludeVDAHostName              
WatermarkIncludeVDAIPAddress             
EnableRemotePCDisconnectTimer            
SessionConnectionTimer                   
SessionConnectionTimerInterval           
SessionDisconnectTimer                   
SessionDisconnectTimerInterval           
SessionIdleTimer                         
SessionIdleTimerInterval                 
LossTolerantThresholds                   
EnableServerConnectionTimer              
EnableServerDisconnectionTimer           
EnableServerIdleTimer                    
ServerConnectionTimerInterval            
ServerDisconnectionTimerInterval         
ServerIdleTimerInterval                  
MinimumEncryptionLevel                   
AutoCreationEventLogPreference           
ClientPrinterRedirection                 
DefaultClientPrinter                     
PrinterAssignments                       
SessionPrinters                          
WaitForPrintersToBeCreated               
UpsPrintStreamInputBandwidthLimit        
DPILimit                                 
EMFProcessingMode                        
ImageCompressionLimit                    
UniversalPrintingPreviewPreference       
UPDCompressionDefaults                                        
InboxDriverAutoInstallation              
UniversalDriverPriority                  
UniversalPrintDriverUsage                
AutoCreatePDFPrinter                     
ClientPrinterAutoCreation                
ClientPrinterNames                       
DirectConnectionsToPrintServers          
GenericUniversalPrinterAutoCreation      
PrinterDriverMappings                    
PrinterPropertiesRetention               
ClientComPortRedirection                 
ClientComPortsAutoConnection             
ClientLptPortRedirection                 
ClientLptPortsAutoConnection             
MaxSpeexQuality                          
MSTeamsRedirection                       
MultimediaOptimization                   
UseGPUForMultimediaOptimization          
VideoLoadManagement                      
VideoQuality                             
WebBrowserRedirectionAcl                 
WebBrowserRedirectionAuthenticationSites 
WebBrowserRedirectionBlacklist           
WebBrowserRedirectionIwaSupport          
WebBrowserRedirectionProxy               
WebBrowserRedirectionProxyAuth           
MultiStream                              
AutoKeyboardPopUp                        
ComboboxRemoting                         
MobileDesktop                            
TabletModeToggle                         
ClientKeyboardLayoutSyncAndIME           
EnableUnicodeKeyboardLayoutMapping       
HideKeyboardLayoutSwitchPopupMessageBox  
AllowVisuallyLosslessCompression         
DisplayLosslessIndicator                 
OptimizeFor3dWorkload                    
ScreenSharing                            
UseHardwareEncodingForVideoCodec         
UseVideoCodecForCompression              
EnableFramehawkDisplayChannel            
AllowFileDownload                        
AllowFileTransfer                        
AllowFileUpload                          
AsynchronousWrites                       
AutoConnectDrives                        
ClientDriveLetterPreservation            
ClientDriveRedirection                   
ClientFixedDrives                        
ClientFloppyDrives                       
ClientNetworkDrives                      
ClientOpticalDrives                      
ClientRemoveableDrives                   
HostToClientRedirection                  
ReadOnlyMappedDrive                      
SpecialFolderRedirection                 
AeroRedirection                          
DesktopWallpaper                         
GraphicsQuality                          
MenuAnimation                            
WindowContentsVisibleWhileDragging       
AllowLocationServices                    
AllowBidirectionalContentRedirection     
BidirectionalRedirectionConfig           
ClientURLs                               
VDAURLs                                  
AudioBandwidthLimit                      
AudioBandwidthPercent                    
ClipboardBandwidthLimit                  
ClipboardBandwidthPercent                
ComPortBandwidthLimit                    
ComPortBandwidthPercent                  
FileRedirectionBandwidthLimit            
FileRedirectionBandwidthPercent          
HDXMultimediaBandwidthLimit              
HDXMultimediaBandwidthPercent            
LptBandwidthLimit                        
LptBandwidthLimitPercent                 
OverallBandwidthLimit                    
PrinterBandwidthLimit                    
PrinterBandwidthPercent                  
TwainBandwidthLimit                      
TwainBandwidthPercent                    
USBBandwidthLimit                        
USBBandwidthPercent                      
AllowRtpAudio                            
AudioPlugNPlay                           
AudioQuality                             
ClientAudioRedirection                   
EnableAdaptiveAudio                      
MicrophoneRedirection                    
FlashAcceleration                        
FlashBackwardsCompatibility              
FlashDefaultBehavior                     
FlashEventLogging                        
FlashIntelligentFallback                 
FlashLatencyThreshold                    
FlashServerSideContentFetchingWhitelist  
FlashUrlColorList                        
FlashUrlCompatibilityList                
HDXFlashLoadManagement                   
HDXFlashLoadManagementErrorSwf           

Type:  Computer
WemCloudConnectorList                        
VirtualLoopbackPrograms                      
VirtualLoopbackSupport                       
EnableAutoUpdateOfControllers                
AppFailureExclusionList                      
EnableProcessMonitoring                      
EnableResourceMonitoring                     
EnableWorkstationVDAFaultMonitoring          
SelectedFailureLevel                         
CPUUsageMonitoring_Enable                    
CPUUsageMonitoring_Period                    
CPUUsageMonitoring_Threshold                 
VdcPolicyEnable                              
EnableClipboardMetadataCollection            
EnableVdaDiagnosticsCollection               
XenAppOptimizationDefinitionPathData         
XenAppOptimizationEnabled                    
ExclusionList_Part                           
IncludeListRegistry_Part                     
LastKnownGoodRegistry                        
DefaultExclusionList                         
ExclusionDefaultReg01                        
ExclusionDefaultReg02                        
ExclusionDefaultReg03                        
PSAlwaysCache                                
PSAlwaysCache_Part                           
PSEnabled                                    
PSForFoldersEnabled                          
PSForPendingAreaEnabled                      
PSPendingLockTimeout                         
PSUserGroups_Part                            
StreamingExclusionList_Part                  
ApplicationProfilesAutoMigration             
DeleteCachedProfilesOnLogoff                 
LocalProfileConflictHandling_Part            
MigrateWindowsProfilesToUserStore_Part       
ProfileDeleteDelay_Part                      
TemplateProfileIsMandatory                   
TemplateProfileOverridesLocalProfile         
TemplateProfileOverridesRoamingProfile       
TemplateProfilePath                          
DisableConcurrentAccessToOneDriveContainer   
DisableConcurrentAccessToProfileContainer    
EnableVHDAutoExtend                          
EnableVHDDiskCompaction                      
GroupsToAccessProfileContainer_Part          
PreventLoginWhenMountFailed_Part             
ProfileContainerExclusionListDir_Part        
ProfileContainerExclusionListFile_Part       
ProfileContainerInclusionListDir_Part        
ProfileContainerInclusionListFile_Part       
ProfileContainerLocalCache                   
DebugFilePath_Part                           
DebugMode                                    
LogLevel_ActiveDirectoryActions              
LogLevel_FileSystemActions                   
LogLevel_FileSystemNotification              
LogLevel_Information                         
LogLevel_Logoff                              
LogLevel_Logon                               
LogLevel_PolicyUserLogon                     
LogLevel_RegistryActions                     
LogLevel_RegistryDifference                  
LogLevel_UserName                            
LogLevel_Warnings                            
MaxLogSize_Part                              
LargeFileHandlingList_Part                   
LogonExclusionCheck_Part                     
AccelerateFolderMirroring                    
MirrorFoldersList_Part                       
ProfileContainer_Part                        
SyncDirList_Part                             
SyncFileList_Part                            
ExclusionListSyncDir_Part                    
ExclusionListSyncFiles_Part                  
DefaultExclusionListSyncDir                  
ExclusionDefaultDir01                        
ExclusionDefaultDir02                        
ExclusionDefaultDir03                        
ExclusionDefaultDir04                        
ExclusionDefaultDir05                        
ExclusionDefaultDir06                        
ExclusionDefaultDir07                        
ExclusionDefaultDir08                        
ExclusionDefaultDir09                        
ExclusionDefaultDir10                        
ExclusionDefaultDir11                        
ExclusionDefaultDir12                        
ExclusionDefaultDir13                        
ExclusionDefaultDir14                        
ExclusionDefaultDir15                        
ExclusionDefaultDir16                        
ExclusionDefaultDir17                        
ExclusionDefaultDir18                        
ExclusionDefaultDir19                        
ExclusionDefaultDir20                        
ExclusionDefaultDir21                        
ExclusionDefaultDir22                        
ExclusionDefaultDir23                        
ExclusionDefaultDir24                        
ExclusionDefaultDir25                        
ExclusionDefaultDir26                        
ExclusionDefaultDir27                        
ExclusionDefaultDir28                        
ExclusionDefaultDir29                        
ExclusionDefaultDir30                        
SharedStoreFileExclusionList_Part            
SharedStoreFileInclusionList_Part            
SharedStoreProfileContainerFileSizeLimit_Part
CPEnable                                     
CPMigrationFromBaseProfileToCPStore          
CPPathData                                   
CPSchemaPathData                             
CPUserGroups_Part                            
DATPath_Part                                 
ExcludedGroups_Part                          
MigrateUserStore_Part                        
OfflineSupport                               
ProcessAdmins                                
ProcessedGroups_Part                         
PSMidSessionWriteBack                        
PSMidSessionWriteBackReg                     
PSMidSessionWriteBackSessionLock             
ServiceActive                                
AppAccessControl_Part                        
CEIPEnabled                                  
CredBasedAccessEnabled                       
DisableDynamicConfig                         
EnableVolumeReattach                         
FreeRatio4Compaction_Part                    
FSLogixProfileContainerSupport               
LoadRetries_Part                             
LogoffRatherThanTempProfile                  
MultiSiteReplication_Part                    
NDefrag4Compaction                           
NLogoffs4Compaction_Part                     
OneDriveContainer_Part                       
OrderedGroups_Part                           
OutlookEdbBackupEnabled                      
OutlookSearchRoamingConcurrentSession        
OutlookSearchRoamingConcurrentSession_Part   
OutlookSearchRoamingEnabled                  
ProcessCookieFiles                           
SyncGpoStateEnabled                          
UserGroupLevelConfigEnabled                  
UserStoreSelection_Part                      
UwpAppsRoaming                               
VhdAutoExpansionIncrement_Part               
VhdAutoExpansionLimit_Part                   
VhdAutoExpansionThreshold_Part               
VhdContainerCapacity_Part                    
VhdStorePath_Part                            
UplCustomizedUserLayerSizeInGb               
UplGroupsUsingCustomizedUserLayerSize        
UplRepositoryPath                            
UplUserExclusions                            
UplUserLayerSizeInGb                         
ConcurrentLogonsTolerance                    
CPUUsage                                     
CPUUsageExcludedProcessPriority              
DiskUsage                                    
MaximumNumberOfSessions                      
MemoryUsage                                  
MemoryUsageBaseLoad                          
ApplicationLaunchWaitTimeout                 
HDXAdaptiveTransport                         
HDXDirect                                    
HDXDirectMode                                
HDXDirectPortRange                           
IcaListenerPortNumber                        
IcaListenerTimeout                           
LogoffCheckerStartupDelay                    
RemoteCredentialGuard                        
RendezvousProtocol                           
RendezvousProxy                              
SecureHDX                                    
VdaUpgradeProxy                              
VirtualChannelWhiteList                      
VirtualChannelWhiteListLogging               
VirtualChannelWhiteListLogThrottling         
AcceptWebSocketsConnections                  
WebSocketsPort                               
WSTrustedOriginServerList                    
SessionReliabilityConnections                
SessionReliabilityPort                       
SessionReliabilityTimeout                    
IdleTimerInterval                            
LoadBalancedPrintServers                     
PrintServersOutOfServiceThreshold            
UpcHttpConnectTimeout                        
UpcHttpReceiveTimeout                        
UpcHttpSendTimeout                           
UpcSslCgpPort                                
UpcSslCipherSuite                            
UpcSslComplianceMode                         
UpcSslEnable                                 
UpcSslFips                                   
UpcSslHttpsPort                              
UpcSslProtocolVersion                        
UpsCgpPort                                   
UpsEnable                                    
UpsHttpPort                                  
HTML5VideoRedirection                        
MultimediaAcceleration                       
MultimediaAccelerationDefaultBufferSize      
MultimediaAccelerationEnableCSF              
MultimediaAccelerationUseDefaultBufferSize   
MultimediaConferencing                       
WebBrowserRedirection                        
MultiPortPolicy                              
MultiStreamAssignment                                                          
MultiStreamPolicy                            
RtpAudioPortRange                            
UDPAudioOnServer                             
AllowLocalAppAccess                          
URLRedirectionBlackList                      
URLRedirectionWhiteList                      
IcaKeepAlives                                
IcaKeepAliveTimeout                          
DisplayDegradePreference                     
DisplayDegradeUserNotification               
DisplayMemoryLimit                           
DynamicPreview                               
ImageCaching                                 
LegacyGraphicsMode                           
MaximumColorDepth                            
QueueingAndTossing                           
FramehawkDisplayChannelPortRange             
PersistentCache                              
EnhancedDesktopExperience                    
IcaRoundTripCalculation                      
IcaRoundTripCalculationInterval              
IcaRoundTripCalculationWhenIdle              
ACRTimeout                                   
AutoClientReconnect                          
AutoClientReconnectAuthenticationRequired    
AutoClientReconnectLogging                   
ReconnectionUiTransparencyLevel              
AppProtectionPostureCheck                    
AdvanceWarningFrequency                      
AdvanceWarningMessageTitle                   
AdvanceWarningPeriod                         
AgentTaskInterval                            
FinalForceLogoffMessageBody                  
FinalForceLogoffMessageTitle                 
ForceLogoffGracePeriod                       
ForceLogoffMessageTitle                      
ImageProviderIntegrationEnabled              
RebootMessageBody        


Using these names allows the deployment of policies by using the Terraform provider.

NOTE: Currently it is only supported to deploy policies using Terraform on-premises with CVAD 2402 or higher. Trying to deploy policies on a DaaS-based environment does not work yet, as the needed back-end configurations are not generally available yet. We update this guide when the Cloud back-end has all modifications rolled out.

Caution:

Be sure that your subscription has no quota limitation on the chosen VM type and you have enough resources on Amazon EC2 to create all the Virtual Machines planned to put into the Machine Catalog by checking quotas - otherwise the creation of the Machine Catalog will fail if there are not enough compute resources available!

Before running Terraform no Terraform-related entities are available:

deployment-guides-CCOnAWS-CC-NoHypConn.png

deployment-guides-CCOnAWS-CC-NoMC.png

deployment-guides-CCOnAWS-CC-NoDG.png

The configuration can be started by following the normal Terraform workflow:
terraform init,
terraform plan
and if no errors occur

terraform apply

PS C:\TACG\_CCOnAWS\_CCOnAWS-CCStuff> terraform init

Initializing the backend...

Initializing provider plugins...
- Finding citrix/citrix versions matching ">= 0.5.2"...
- Finding hashicorp/aws versions matching ">= 5.4.0"...
- Finding mastercard/restapi versions matching "1.18.2"...
- Finding latest version of hashicorp/local...
- Installing hashicorp/aws v5.41.0...
- Installed hashicorp/aws v5.41.0 (signed by HashiCorp)
- Installing mastercard/restapi v1.18.2...
- Installed mastercard/restapi v1.18.2 (self-signed, key ID DCB8C431D71C30AB)
- Installing hashicorp/local v2.5.1...
- Installed hashicorp/local v2.5.1 (signed by HashiCorp)
- Installing citrix/citrix v0.5.2...
- Installed citrix/citrix v0.5.2 (signed by a HashiCorp partner, key ID 25D62DD8407EA386)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

PS C:\TACG\_CCOnAWS\_CCOnAWS-CCStuff>

PS C:\TACG\_CCOnAWS\_CCOnAWS-CCStuff> terraform plan
data.local_file.LoadZoneID: Reading...
data.local_file.LoadZoneID: Read complete after 0s [id=a7592ebe91057eab80084fc014fa06ca52453732]
data.aws_vpc.AWSAZ: Reading...
data.aws_vpc.AWSVPC: Reading...
data.aws_subnet.AWSSubnet: Reading...
data.aws_subnet.AWSSubnet: Read complete after 0s [id=subnet-07e168f0c2a28edf3]
data.aws_vpc.AWSVPC: Read complete after 0s [id=vpc-0f9ac384f3bf8cb3a]
data.aws_vpc.AWSAZ: Read complete after 0s [id=vpc-0f9ac384f3bf8cb3a]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_ami_from_instance.CreateAMIFromWMI will be created
  + resource "aws_ami_from_instance" "CreateAMIFromWMI" {
      + architecture         = (known after apply)
      + arn                  = (known after apply)
      + boot_mode            = (known after apply)
      + ena_support          = (known after apply)
      + hypervisor           = (known after apply)
      + id                   = (known after apply)
      + image_location       = (known after apply)
      + image_owner_alias    = (known after apply)
      + image_type           = (known after apply)
      + imds_support         = (known after apply)
      + kernel_id            = (known after apply)
      + manage_ebs_snapshots = (known after apply)
      + name                 = "TACG-AWS-TF-AMIFromWMI"
      + owner_id             = (known after apply)
      + platform             = (known after apply)
      + platform_details     = (known after apply)
      + public               = (known after apply)
      + ramdisk_id           = (known after apply)
      + root_device_name     = (known after apply)
      + root_snapshot_id     = (known after apply)
      + source_instance_id   = "i-024f77470f3f63c08"
      + sriov_net_support    = (known after apply)
      + tags_all             = (known after apply)
      + tpm_support          = (known after apply)
      + usage_operation      = (known after apply)
      + virtualization_type  = (known after apply)

      + timeouts {
          + create = "45m"
        }
    }

  # citrix_aws_hypervisor.CreateHypervisorConnection will be created
  + resource "citrix_aws_hypervisor" "CreateHypervisorConnection" {
      + api_key    = (sensitive value)
      + id         = (known after apply)
      + name       = "TACG-AWS-TF-HypConn"
      + region     = (sensitive value)
      + secret_key = (sensitive value)
      + zone       = "8d5dXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
    }

  # citrix_aws_hypervisor_resource_pool.CreateHypervisorPool will be created
  + resource "citrix_aws_hypervisor_resource_pool" "CreateHypervisorPool" {
      + availability_zone = "eu-central-1a"
      + hypervisor        = (known after apply)
      + id                = (known after apply)
      + name              = "TACG-AWS-TF-HypConnPool"
      + subnets           = [
          + "172.31.16.0/20",
        ]
      + vpc               = "TACG-VPC"
    }

  # citrix_machine_catalog.CreateMCSCatalog will be created
  + resource "citrix_machine_catalog" "CreateMCSCatalog" {
      + allocation_type     = "Random"
      + description         = "Terraform-based Machine Catalog"
      + id                  = (known after apply)
      + is_power_managed    = true
      + is_remote_pc        = false
      + name                = "MC-TACG-AWS-TF"
      + provisioning_scheme = {
          + aws_machine_config             = {
              + image_ami        = (known after apply)
              + master_image     = "TACG-AWS-TF-AMIFromWMI"
              + service_offering = "T2 Large Instance"
            }
          + hypervisor                     = (known after apply)
          + hypervisor_resource_pool       = (known after apply)
          + identity_type                  = "ActiveDirectory"
          + machine_account_creation_rules = {
              + naming_scheme      = "TACG-AWS-WM-#"
              + naming_scheme_type = "Numeric"
            }
          + machine_domain_identity        = {
              + domain                   = "aws.the-austrian-citrix-guy.at"
              + domain_ou                = "CN=Computers,DC=aws,DC=the-austrian-citrix-guy,DC=at"
              + service_account          = (sensitive value)
              + service_account_password = (sensitive value)
            }
          + network_mapping                = {
              + network        = "172.31.16.0/20"
              + network_device = "0"
            }
          + number_of_total_machines       = 1
        }
      + provisioning_type        = "MCS"
      + session_support          = "MultiSession"
      + zone                     = "8d5dXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
      + minimum_functional_level = "L7_20"
    }

     # citrix_delivery_group.CreateDG will be created
  + resource "citrix_delivery_group" "CreateDG" {
      + associated_machine_catalogs = [
          + {
              + machine_catalog = "f4e34a11-6e31-421f-8cb4-060bc4a13fef"
              + machine_count   = 1
            },
        ]
      + autoscale_settings          = {
          + autoscale_enabled                                   = true
          + disconnect_off_peak_idle_session_after_seconds      = 0
          + disconnect_peak_idle_session_after_seconds          = 300
          + log_off_off_peak_disconnected_session_after_seconds = 0
          + log_off_peak_disconnected_session_after_seconds     = 300
          + off_peak_buffer_size_percent                        = 0
          + off_peak_disconnect_action                          = "Nothing"
          + off_peak_disconnect_timeout_minutes                 = 0
          + off_peak_extended_disconnect_action                 = "Nothing"
          + off_peak_extended_disconnect_timeout_minutes        = 0
          + off_peak_log_off_action                             = "Nothing"
          + peak_buffer_size_percent                            = 0
          + peak_disconnect_action                              = "Nothing"
          + peak_disconnect_timeout_minutes                     = 0
          + peak_extended_disconnect_action                     = "Nothing"
          + peak_extended_disconnect_timeout_minutes            = 0
          + peak_log_off_action                                 = "Nothing"
          + power_off_delay_minutes                             = 30
          + power_time_schemes                                  = [
              + {
                  + days_of_week          = [
                      + "Monday",
                      + "Tuesday",
                      + "Wednesday",
                      + "Thursday",
                      + "Friday",
                    ]
                  + display_name          = "TACG-AWS-TF-AS-Weekdays"
                  + peak_time_ranges      = [
                      + "09:00-17:00",
                    ]
                  + pool_size_schedules   = [
                      + {
                          + pool_size  = 1
                          + time_range = "09:00-17:00"
                        },
                    ]
                  + pool_using_percentage = false
                },
            ]
        }
      + desktops                    = [
          + {
              + description             = "Terraform-based Delivery Group running on AWS EC2"
              + enable_session_roaming  = true
              + enabled                 = true
              + published_name          = "DG-TF-TACG-AWS"
              + restricted_access_users = {
                  + allow_list = [
                      + "TACG-AWS\\vdaallowed",
                    ]
                }
            },
        ]
      + id                          = (known after apply)
      + name                        = "DG-TF-TACG-AWS"
      + reboot_schedules            = [
          + {
              + days_in_week            = [
                  + "Sunday",
                ]
              + frequency               = "Weekly"
              + frequency_factor        = 1
              + ignore_maintenance_mode = true
              + name                    = "TACG-AWS-Reboot Schedule"
              + natural_reboot_schedule = false
              + reboot_duration_minutes = 0
              + reboot_schedule_enabled = true
              + start_date              = "2024-01-01"
              + start_time              = "02:00"
            },
        ]
      + restricted_access_users     = {
          + allow_list = [
              + "TACG-AWS\\vdaallowed",
            ]
        }
      + total_machines              = (known after apply)
    }

  # time_sleep.Wait_60_Seconds_2 will be created
  + resource "time_sleep" "Wait_60_Seconds_2" {
      + create_duration = "60s"
      + id              = (known after apply)
    }

  # time_sleep.wait_60_seconds_1 will be created
  + resource "time_sleep" "wait_60_seconds_1" {
      + create_duration = "60s"
      + id              = (known after apply)
    }

Plan: 8 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

PS C:\TACG\_CCOnAWS\_CCOnAWS-CCStuff>

PS C:\TACG\_CCOnAWS\_CCOnAWS-CCStuff> terraform apply
data.local_file.LoadZoneID: Reading...
data.local_file.LoadZoneID: Read complete after 0s [id=a7592ebe91057eab80084fc014fa06ca52453732]
data.aws_subnet.AWSSubnet: Reading...
data.aws_vpc.AWSVPC: Reading...
data.aws_vpc.AWSAZ: Reading...
data.aws_subnet.AWSSubnet: Read complete after 0s [id=subnet-07e168f0c2a28edf3]
data.aws_vpc.AWSAZ: Read complete after 0s [id=vpc-0f9ac384f3bf8cb3a]
data.aws_vpc.AWSVPC: Read complete after 0s [id=vpc-0f9ac384f3bf8cb3a]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_ami_from_instance.CreateAMIFromWMI will be created
  + resource "aws_ami_from_instance" "CreateAMIFromWMI" {
      + architecture         = (known after apply)
      + arn                  = (known after apply)
      + boot_mode            = (known after apply)
      + ena_support          = (known after apply)
      + hypervisor           = (known after apply)
      + id                   = (known after apply)
      + image_location       = (known after apply)
      + image_owner_alias    = (known after apply)
      + image_type           = (known after apply)
      + imds_support         = (known after apply)
      + kernel_id            = (known after apply)
      + manage_ebs_snapshots = (known after apply)
      + name                 = "TACG-AWS-TF-AMIFromWMI"
      + owner_id             = (known after apply)
      + platform             = (known after apply)
      + platform_details     = (known after apply)
      + public               = (known after apply)
      + ramdisk_id           = (known after apply)
      + root_device_name     = (known after apply)
      + root_snapshot_id     = (known after apply)
      + source_instance_id   = "i-024f77470f3f63c08"
      + sriov_net_support    = (known after apply)
      + tags_all             = (known after apply)
      + tpm_support          = (known after apply)
      + usage_operation      = (known after apply)
      + virtualization_type  = (known after apply)

      + timeouts {
          + create = "45m"
        }
    }

  # citrix_aws_hypervisor.CreateHypervisorConnection will be created
  + resource "citrix_aws_hypervisor" "CreateHypervisorConnection" {
      + api_key    = (sensitive value)
      + id         = (known after apply)
      + name       = "TACG-AWS-TF-HypConn"
      + region     = (sensitive value)
      + secret_key = (sensitive value)
      + zone       = "8d5d77ba-4803-4b71-9a6b-6e28071304c1"
    }

  # citrix_aws_hypervisor_resource_pool.CreateHypervisorPool will be created
  + resource "citrix_aws_hypervisor_resource_pool" "CreateHypervisorPool" {
      + availability_zone = "eu-central-1a"
      + hypervisor        = (known after apply)
      + id                = (known after apply)
      + name              = "TACG-AWS-TF-HypConnPool"
      + subnets           = [
          + "172.31.16.0/20",
        ]
      + vpc               = "TACG-VPC"
    }

  # citrix_machine_catalog.CreateMCSCatalog will be created
  + resource "citrix_machine_catalog" "CreateMCSCatalog" {
      + allocation_type     = "Random"
      + description         = "Terraform-based Machine Catalog"
      + id                  = (known after apply)
      + is_power_managed    = true
      + is_remote_pc        = false
      + name                = "MC-TACG-AWS-TF"
      + provisioning_scheme = {
          + aws_machine_config             = {
              + image_ami        = (known after apply)
              + master_image     = "TACG-AWS-TF-AMIFromWMI"
              + service_offering = "T2 Large Instance"
            }
          + hypervisor                     = (known after apply)
          + hypervisor_resource_pool       = (known after apply)
          + identity_type                  = "ActiveDirectory"
          + machine_account_creation_rules = {
              + naming_scheme      = "TACG-AWS-WM-#"
              + naming_scheme_type = "Numeric"
            }
          + machine_domain_identity        = {
              + domain                   = "aws.the-austrian-citrix-guy.at"
              + domain_ou                = "CN=Computers,DC=aws,DC=the-austrian-citrix-guy,DC=at"
              + service_account          = (sensitive value)
              + service_account_password = (sensitive value)
            }
          + network_mapping                = {
              + network        = "172.31.16.0/20"
              + network_device = "0"
            }
          + number_of_total_machines       = 1
        }
      + provisioning_type   = "MCS"
      + session_support     = "MultiSession"
      + zone                = "8d5dXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
    }
  # citrix_delivery_group.CreateDG will be created
  + resource "citrix_delivery_group" "CreateDG" {
      + associated_machine_catalogs = [
          + {
              + machine_catalog = "f4e3XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
              + machine_count   = 1
            },
        ]
      + autoscale_settings          = {
          + autoscale_enabled                                   = true
          + disconnect_off_peak_idle_session_after_seconds      = 0
          + disconnect_peak_idle_session_after_seconds          = 300
          + log_off_off_peak_disconnected_session_after_seconds = 0
          + log_off_peak_disconnected_session_after_seconds     = 300
          + off_peak_buffer_size_percent                        = 0
          + off_peak_disconnect_action                          = "Nothing"
          + off_peak_disconnect_timeout_minutes                 = 0
          + off_peak_extended_disconnect_action                 = "Nothing"
          + off_peak_extended_disconnect_timeout_minutes        = 0
          + off_peak_log_off_action                             = "Nothing"
          + peak_buffer_size_percent                            = 0
          + peak_disconnect_action                              = "Nothing"
          + peak_disconnect_timeout_minutes                     = 0
          + peak_extended_disconnect_action                     = "Nothing"
          + peak_extended_disconnect_timeout_minutes            = 0
          + peak_log_off_action                                 = "Nothing"
          + power_off_delay_minutes                             = 30
          + power_time_schemes                                  = [
              + {
                  + days_of_week          = [
                      + "Monday",
                      + "Tuesday",
                      + "Wednesday",
                      + "Thursday",
                      + "Friday",
                    ]
                  + display_name          = "TACG-AWS-TF-AS-Weekdays"
                  + peak_time_ranges      = [
                      + "09:00-17:00",
                    ]
                  + pool_size_schedules   = [
                      + {
                          + pool_size  = 1
                          + time_range = "09:00-17:00"
                        },
                    ]
                  + pool_using_percentage = false
                },
            ]
        }
      + desktops                    = [
          + {
              + description             = "Terraform-based Delivery Group running on AWS EC2"
              + enable_session_roaming  = true
              + enabled                 = true
              + published_name          = "DG-TF-TACG-AWS"
              + restricted_access_users = {
                  + allow_list = [
                      + "TACG-AWS\\vdaallowed",
                    ]
                }
            },
        ]
      + id                          = (known after apply)
      + name                        = "DG-TF-TACG-AWS"
      + reboot_schedules            = [
          + {
              + days_in_week            = [
                  + "Sunday",
                ]
              + frequency               = "Weekly"
              + frequency_factor        = 1
              + ignore_maintenance_mode = true
              + name                    = "TACG-AWS-Reboot Schedule"
              + natural_reboot_schedule = false
              + reboot_duration_minutes = 0
              + reboot_schedule_enabled = true
              + start_date              = "2024-01-01"
              + start_time              = "02:00"
            },
        ]
      + restricted_access_users     = {
          + allow_list = [
              + "TACG-AWS\\vdaallowed",
            ]
        }
      + total_machines              = (known after apply)
    }

  # time_sleep.Wait_60_Seconds_2 will be created
  + resource "time_sleep" "Wait_60_Seconds_2" {
      + create_duration = "60s"
      + id              = (known after apply)
    }

  # time_sleep.wait_60_seconds_1 will be created
  + resource "time_sleep" "wait_60_seconds_1" {
      + create_duration = "60s"
      + id              = (known after apply)
    }

Plan: 8 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_ami_from_instance.CreateAMIFromWMI: Creating...
citrix_aws_hypervisor.CreateHypervisorConnection: Creating...
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [10s elapsed]
citrix_aws_hypervisor.CreateHypervisorConnection: Still creating... [10s elapsed]
citrix_aws_hypervisor.CreateHypervisorConnection: Creation complete after 10s [id=706c408a-6eed-42b1-8102-93888db8a0eb]
citrix_aws_hypervisor_resource_pool.CreateHypervisorPool: Creating...
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [20s elapsed]
citrix_aws_hypervisor_resource_pool.CreateHypervisorPool: Still creating... [10s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [30s elapsed]
citrix_aws_hypervisor_resource_pool.CreateHypervisorPool: Still creating... [20s elapsed]
citrix_aws_hypervisor_resource_pool.CreateHypervisorPool: Creation complete after 22s [id=b460dfc2-f760-4b52-bc94-fad9c85a0b8f]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [40s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [50s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [1m0s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [1m10s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [1m20s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [1m30s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [1m40s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [1m50s elapsed]

... ** Output shortened **... 

aws_ami_from_instance.CreateAMIFromWMI: Still creating... [6m10s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [6m20s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [6m30s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [6m40s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [6m50s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Still creating... [7m0s elapsed]
aws_ami_from_instance.CreateAMIFromWMI: Creation complete after 7m7s [id=ami-0e01b8c8d09a5fbe5]
time_sleep.wait_30_seconds: Creating...
time_sleep.wait_30_seconds: Still creating... [10s elapsed]
time_sleep.wait_30_seconds: Still creating... [20s elapsed]
time_sleep.wait_30_seconds: Creation complete after 30s [id=2024-03-15T17:40:18Z]
citrix_machine_catalog.CreateMCSCatalog: Creating...
citrix_machine_catalog.CreateMCSCatalog: Still creating... [10s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [20s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [30s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [40s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [50s elapsed]

... ** Output shortened **... 

citrix_machine_catalog.CreateMCSCatalog: Still creating... [16m1s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [16m11s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [16m21s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [16m31s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [16m41s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [16m51s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Still creating... [17m1s elapsed]
citrix_machine_catalog.CreateMCSCatalog: Creation complete after 17m4s [id=f4e34a11-6e31-421f-8cb4-060bc4a13fef]
time_sleep.wait_60_seconds_1: Creating...
time_sleep.wait_60_seconds_1: Still creating... [10s elapsed]
time_sleep.wait_60_seconds_1: Still creating... [20s elapsed]
time_sleep.wait_60_seconds_1: Still creating... [30s elapsed]
time_sleep.wait_60_seconds_1: Still creating... [40s elapsed]
time_sleep.wait_60_seconds_1: Still creating... [50s elapsed]
time_sleep.wait_60_seconds_1: Creation complete after 1m0s [id=2024-03-20T08:06:45Z]
time_sleep.Wait_60_Seconds_2: Creating...
time_sleep.Wait_60_Seconds_2: Still creating... [10s elapsed]
time_sleep.Wait_60_Seconds_2: Still creating... [20s elapsed]
time_sleep.Wait_60_Seconds_2: Still creating... [30s elapsed]
time_sleep.Wait_60_Seconds_2: Still creating... [40s elapsed]
time_sleep.Wait_60_Seconds_2: Still creating... [50s elapsed]
time_sleep.Wait_60_Seconds_2: Creation complete after 1m0s [id=2024-03-20T08:07:45Z]
citrix_delivery_group.CreateDG: Creating...
citrix_delivery_group.CreateDG: Still creating... [10s elapsed]
citrix_delivery_group.CreateDG: Creation complete after 12s [id=7e2c73bf-f8b1-4e37-8cd8-efa1338304dc]

Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
PS C:\TACG\_CCOnAWS\_CCOnAWS-CCStuff>


This configuration completes the full deployment of a Citrix Cloud Resource Location in Microsoft Amazon EC2.

The environment created by Terraform is now ready for usage. All entities are in place:

The Resource Location:

deployment-guides-CCOnAWS-PreReqs-CWCUp.png


The Hypervisor Connection and the Hypervisor Pool:

deployment-guides-CCOnAWS-CC-HypReady.png


The Machine Catalog:

deployment-guides-CCOnAWS-CC-MCReady.png


The  Worker VM in the Machine Catalog:

deployment-guides-CCOnAWS-CC-WorkerReady.png


The Delivery Group:

deployment-guides-CCOnAWS-CC-DGReady.png


The AutoScale settings of the Delivery Group:

deployment-guides-CCOnAWS-CC-AutoScaleReady.png


The Desktop in the Library:

deployment-guides-CCOnAWS-CC-LibraryReady.png


The Desktop in the Library:

deployment-guides-CCOnAWS-Workspace-DesktopReady.png


Connection to the Worker VM´s Desktop:

deployment-guides-CCOnAWS-Workspace-Connected.png


Appendix

Examples of the Terraform scripts

Module 1: CConAWS-Creation

These are the Terraform configuration files for Module 1 (excerpts):

_CCOnAWS-Creation-Provider.tf

# Terraform deployment of Citrix DaaS on Amazon AWS EC2
## Definition of all required Terraform providers
 
terraform {
    required_version = ">= 1.4.0"
 
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.4.0"
    }
 
    restapi = {
      source  = "Mastercard/restapi"
      version = "1.18.2"
    }
 
    citrix = {
      source  = "citrix/citrix"
      version = ">=0.5.3"
    }
  }
}
 
# Configure the AWS Provider
provider "aws" {
  region     = "${var.AWSEC2_Region}"
  access_key = "${var.AWSEC2_AccessKey}"
  secret_key = "${var.AWSEC2_AccessKeySecret}"
}
 
# Configure the Citrix Provider
provider "citrix" {
  customer_id   = "${var.CC_CustomerID}"  
  client_id     = "${var.CC_APIKey-ClientID}"  
  client_secret = "${var.CC_APIKey-ClientSecret}"  
}
 
# Configure the REST-API provider
provider "restapi" {
  alias                 = "restapi_rl"
  uri                   = "${var.CC_RestAPIURI}"
  create_method         = "POST"
   write_returns_object = true
  debug                 = true
  headers               = {
                            "Content-Type"      = "application/json",
                            "Citrix-CustomerId" = "${var.CC_CustomerID}",
                            "Accept"            = "application/json",
                            "Authorization"     = "${var.CC_APIKey-Bearer}"
                          }
}


_CCOnAWS-Creation-Create.tf

# Terraform deployment of Citrix DaaS on Amazon AWS EC2
## Creation of all required VMs - two Cloud Connectors and one Worker Master image
 
locals {
 
}


 
### Create needed IAM roles
#### IAM EC2 Policy with Assume Role
 data "aws_iam_policy_document" "ec2_assume_role" {
   statement {
     actions = ["sts:AssumeRole"]
     principals {
       type        = "Service"
       identifiers = ["ec2.amazonaws.com"]
     }
   }
 }
 
#### Create EC2 IAM Role
resource "aws_iam_role" "ec2_iam_role" {
   name                = "ec2-iam-role"
   path                = "/"
   assume_role_policy  = data.aws_iam_policy_document.ec2_assume_role.json
 }
 
#### Create EC2 IAM Instance Profile
resource "aws_iam_instance_profile" "ec2_profile" {
  name = "ec2-profile"
  role = aws_iam_role.ec2_iam_role.name
}
 
#### Attach Policies to Instance Role
resource "aws_iam_policy_attachment" "ec2_attach1" {
  name       = "ec2-iam-attachment"
  roles      = [aws_iam_role.ec2_iam_role.id]
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
 
resource "aws_iam_policy_attachment" "ec2_attach2" {
  name       = "ec2-iam-attachment"
  roles      = [aws_iam_role.ec2_iam_role.id]
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
}
 
#### Create Secret Manager IAM Policy
resource "aws_iam_policy" "secret_manager_ec2_policy" {
  name        = "secret-manager-ec2-policy"
  description = "Secret Manager EC2 policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "secretsmanager:*"
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}
 
#### Attach Secret Manager Policies to Instance Role
resource "aws_iam_policy_attachment" "api_secret_manager_ec2_attach" {
  name       = "secret-manager-ec2-attachment"
  roles      = [aws_iam_role.ec2_iam_role.id]
  policy_arn = aws_iam_policy.secret_manager_ec2_policy.arn
}
 
data "template_file" "Add-EC2InstanceToDomainScriptCC1" {
  template = file("${path.module}/Add-EC2InstanceToDomainCC1.ps1")
  vars = {
    ad_secret_id = "AD/SA/DomainJoin"
    ad_domain = "aws.the-austrian.citrix.guy.at"
  }
}
 
data "template_file" "Add-EC2InstanceToDomainScriptCC2" {
  template = file("${path.module}/Add-EC2InstanceToDomainCC2.ps1")
  vars = {
    ad_secret_id = "AD/SA/DomainJoin"
    ad_domain = "aws.the-austrian.citrix.guy.at"
  }
}
 
data "template_file" "Add-EC2InstanceToDomainScriptWMI" {
  template = file("${path.module}/Add-EC2InstanceToDomainWMI.ps1")
  vars = {
    ad_secret_id = "AD/SA/DomainJoin"
    ad_domain = "aws.the-austrian.citrix.guy.at"
  }
}
 
data "template_file" "Add-EC2InstanceToDomainScriptAdminVM" {
  template = file("${path.module}/Add-EC2InstanceToDomainAdminVM.ps1")
  vars = {
    ad_secret_id = "AD/SA/DomainJoin"
    ad_domain = "aws.the-austrian.citrix.guy.at"
  }
}
 
#### Create DHCP settings
resource "aws_vpc_dhcp_options" "vpc-dhcp-options" {
  depends_on = [ data.template_file.Add-EC2InstanceToDomainScriptCC1 ]
  domain_name_servers     = [ var.AWSEC2_DC-IP ]
 
}
resource "aws_vpc_dhcp_options_association" "dns_resolver" {
   vpc_id                 = var.AWSEC2_VPC-ID
   dhcp_options_id        = aws_vpc_dhcp_options.vpc-dhcp-options.id
}
 
### Create CC1-VM
resource "aws_instance" "CC1" {
  depends_on = [ data.template_file.Add-EC2InstanceToDomainScriptCC1 ]
  ami                     = var.AWSEC2_AMI
  subnet_id               = var.AWSEC2_Subnet-ID
  private_ip              = var.AWSEC2_PrivIP-CC1
  instance_type           = var.AWSEC2_Instance-Type
  key_name                = var.AWSEC2_AMI-KeyPairName
  vpc_security_group_ids  = [ var.AWSEC2_SecurityGroup ]
 
 
  tags                    = {
                               Name = var.AWSEC2_InstanceName-CC1
                            }
 
  user_data               = data.template_file.Add-EC2InstanceToDomainScriptCC1.rendered
  iam_instance_profile    = aws_iam_instance_profile.ec2_profile.id
 
}
 
### Create CC2-VM
resource "aws_instance" "CC2" {
    depends_on = [ data.template_file.Add-EC2InstanceToDomainScriptCC2 ]
  ami                     = var.AWSEC2_AMI
  subnet_id               = var.AWSEC2_Subnet-ID
  private_ip              = var.AWSEC2_PrivIP-CC2
  instance_type           = var.AWSEC2_Instance-Type
  key_name                = var.AWSEC2_AMI-KeyPairName
  vpc_security_group_ids  = [ var.AWSEC2_SecurityGroup ]
 
 
  tags                    = {
                               Name = var.AWSEC2_InstanceName-CC2
                            }
 
  user_data               = data.template_file.Add-EC2InstanceToDomainScriptCC2.rendered
  iam_instance_profile    = aws_iam_instance_profile.ec2_profile.id
 
}
 
### Create Admin-VM
resource "aws_instance" "AdminVM" {
    depends_on = [ data.template_file.Add-EC2InstanceToDomainScriptAdminVM ]
  ami                     = var.AWSEC2_AMI
  subnet_id               = var.AWSEC2_Subnet-ID
  private_ip              = var.AWSEC2_PrivIP-AdminVM
  instance_type           = var.AWSEC2_Instance-Type-Worker
  key_name                = var.AWSEC2_AMI-KeyPairName
  vpc_security_group_ids  = [ var.AWSEC2_SecurityGroup ]
 
 
  tags                    = {
                               Name = var.AWSEC2_InstanceName-AdminVM
                            }
 
  user_data               = data.template_file.Add-EC2InstanceToDomainScriptAdminVM.rendered
  iam_instance_profile    = aws_iam_instance_profile.ec2_profile.id
 
}
 
### Create WMI-VM
resource "aws_instance" "WMI" {
    depends_on = [ data.template_file.Add-EC2InstanceToDomainScriptWMI ]
  ami                     = var.AWSEC2_AMI
  subnet_id               = var.AWSEC2_Subnet-ID
  private_ip              = var.AWSEC2_PrivIP-WMI
  instance_type           = var.AWSEC2_Instance-Type
  key_name                = var.AWSEC2_AMI-KeyPairName
  vpc_security_group_ids  = [ var.AWSEC2_SecurityGroup ]
 
 
  tags                    = {
                               Name = var.AWSEC2_InstanceName-WMI
                            }
 
  user_data               = data.template_file.Add-EC2InstanceToDomainScriptWMI.rendered
  iam_instance_profile    = aws_iam_instance_profile.ec2_profile.id
 
}

 

_CCOnAWS-Creation-GetBearerToken.tf

### Create PowerShell file for retrieving the Bearer Token
resource "local_file" "GetBearerToken" {
content  = <<-EOT
 asnp Citrix*
 $key= "${var.CC_APIKey-ClientID}"
 $secret= "${var.CC_APIKey-ClientSecret}"
 $customer= "${var.CC_CustomerID}"
 $XDStoredCredentials = Set-XDCredentials -StoreAs default -ProfileType CloudApi -CustomerId $customer -APIKey $key -SecretKey $secret
 $auth = Get-XDAuthentication
 $BT = $GLOBAL:XDAuthToken | Out-File "${path.module}/GetBT.txt"
EOT
filename = "${path.module}/GetBT.ps1"
}
 
### Running GetBearertoken-Script to retrieve the Bearer Token
resource "terraform_data" "GetBT" {
  depends_on = [ local_file.GetBearerToken ]
  provisioner "local-exec" {
     command = "${path.module}/GetBT.ps1"
    interpreter = ["PowerShell", "-File"]
 
  }
}
 
### Retrieving the Bearer Token
data "local_file" "Retrieve_BT" {
  depends_on = [ terraform_data.GetBT ]
  filename = "${path.module}/GetBT.txt"
}
 
output "terraform_data_BR_Read" {
  value = data.local_file.Retrieve_BT.content
}

 

Module 2: CConAWS-Install

These are the Terraform configuration files for Module 2 (excerpts):

_CCOnAWS-Install-CreatePreReqs.tf

# Terraform deployment of Citrix DaaS on Amazon AWS EC2
## Creating a dedicated Resource Location on Citrix Cloud
 
resource "random_uuid" "IDforCCRL" {
}
 
### Create local directory
resource "local_file" "Log" {
  content  = "Directory created."
  filename = "${var.CC_Install_LogPath}/log.txt"
}
 
resource "local_file" "LogData" {
  depends_on = [ local_file.Log ]  
  content  = "Directory created."
  filename = "${var.CC_Install_LogPath}/DATA/log.txt"
}
 
### Create PowerShell command to be run on the CC machines
locals {
 randomuuid = random_uuid.IDforCCRL.result
  }
 
### Create a dedicated Resource Location in Citrix Cloud
resource "restapi_object" "CreateRL" {
    depends_on = [ local_file.log ]
    provider = restapi.restapi_rl
    path="/resourcelocations"
      data = jsonencode(
        {
         "id" = "${local.randomuuid}",
        "name" = "${var.CC_RestRLName}",
        "internalOnly" = false,
        "timeZone" = "GMT Standard Time",
        "readOnly" = false
        }
      )
}
 
### Create PowerShell files with configuration and next steps and save it into Transfer directory
#### Create CWC-Installer configuration file based on variables and save it into Transfer directory
resource "local_file" "CWC-Configuration" {
  depends_on = [restapi_object.CreateRL]
  content  = jsonencode(
        {
        "customerName" = "${var.CC_CustomerID}",
        "clientId" = "${var.CC_APIKey-ClientID}",
        "clientSecret" = "${var.CC_APIKey-ClientSecret}",
        "resourceLocationId" = "XXXXXXXXXX",
        "acceptTermsOfService" = true
        }
      )
  filename = "${var.CC_Install_LogPath}/DATA/cwc.json"
 
}
#### Wait 5 mins after RL creation to settle Zone creation
resource "time_sleep" "wait_300_seconds" {
  create_duration = "300s"
}
 
### Create PowerShell file for determining the SiteID
resource "local_file" "GetSiteIDScript" {
  depends_on = [restapi_object.CreateRL, time_sleep.wait_300_seconds]
  content  = <<-EOT
$requestUri = "https://api-eu.cloud.com/cvad/manage/me"
$headers = @{ "Accept"="application/json"; "Authorization" = "${var.CC_APIKey-Bearer}"; "Citrix-CustomerId" = "${var.CC_CustomerID}" }
$response = Invoke-RestMethod -Uri $requestUri -Method GET -Headers $headers | Select-Object Customers
$responsetojson = $response | Convertto-Json -Depth 3
$responsekorr = $responsetojson -replace("null","""empty""")
$responsefromjson = $responsekorr | Convertfrom-json
$SitesObj=$responsefromjson.Customers[0].Sites[0]
$Export1 = $SitesObj -replace("@{Id=","")
$SplittedString = $Export1.Split(";")
$SiteID= $SplittedString[0]
$PathCompl = "${var.CC_Install_LogPath}/DATA/GetSiteID.txt"
Set-Content -Path $PathCompl -Value $SiteID
  EOT
  filename = "${path.module}/GetSiteID.ps1"
}
 
### Running the SiteID-Script to generate the SiteID
resource "terraform_data" "SiteID" {
  depends_on = [ local_file.GetSiteIDScript ]
  provisioner "local-exec" {
     command = "GetSiteID.ps1"
    interpreter = ["PowerShell", "-File"]
 
  }
}
 
### Retrieving the SiteID
data "local_file" "input_site" {
  depends_on = [ terraform_data.SiteID ]
  filename = "${var.CC_Install_LogPath}/DATA/GetSiteID.txt"
}
 
### Create PowerShell file for determining the ZoneID
resource "local_file" "GetZoneIDScript" {
  depends_on = [ data.local_file.input_site ]
  content  = <<-EOT
$requestUri = "https://api-eu.cloud.com/cvad/manage/Zones"
$headers = @{ "Accept"="application/json"; "Authorization" = "${var.CC_APIKey-Bearer}"; "Citrix-CustomerId" = "${var.CC_CustomerID}"; "Citrix-InstanceId" = "${data.local_file.input_site.content}" }
$response = Invoke-RestMethod -Uri $requestUri -Method GET -Headers $headers | Convertto-Json
$responsedejson = $response | ConvertFrom-Json
$ZoneId = $responsedejson.Items | Where-Object { $_.Name -eq "${var.CC_RestRLName}" } | Select-Object id
$Export1 = $ZoneId -replace("@{Id=","")
$ZoneID = $Export1 -replace("}","")
$PathCompl = "${var.CC_Install_LogPath}/DATA/GetZoneID.txt"
Set-Content -Path $PathCompl -Value $ZoneID
  EOT
  filename = "${path.module}/GetZoneID.ps1"
}
 
### Running the ZoneID-Script to generate the ZoneID
resource "terraform_data" "ZoneID" {
  depends_on = [ local_file.GetZoneIDScript ]
  provisioner "local-exec" {
     command = "GetZoneID.ps1"
    interpreter = ["PowerShell", "-File"]
 
  }
}
 
#### Create PowerShell file for installing the Citrix Cloud Connector - we need to determine the correct RL-ID
resource "local_file" "InstallPreReqsOnCC-ps1" {
  content  = <<-EOT
  #### Need to invoke PowerShell as Domain User as the provisioner does not allow to be run in a Domain Users-context
  $PSUsername = '${var.Provisioner_DomainAdmin-Username}'
  $PSPassword = '${var.Provisioner_DomainAdmin-Password}'
  $PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
  $PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
  Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
  $path = "${var.CC_Install_LogPath}"
  If(!(test-path -PathType container $path))
 {
      New-Item -ItemType Directory -Path $path
 }
 
  Add-Content ${var.CC_Install_LogPath}/log.txt "`nScript started."
  # Download the Citrix Cloud Connector-Software to CC
  Invoke-WebRequest ${var.CC_Install_CWCURI} -OutFile '${var.CC_Install_LogPath}/DATA/CWCConnector.exe'
  # Install Citrix Cloud Controller based on the cwc.json configuration file
  Add-Content ${var.CC_Install_LogPath}/log.txt "`nInstalling Cloud Connector."
  Start-Process -Filepath "${var.CC_Install_LogPath}/DATA/CWCConnector.exe" -ArgumentList "/q /ParametersFilePath:${var.CC_Install_LogPath}/DATA/cwc.json"
  Add-Content ${var.CC_Install_LogPath}/log.txt "`nInstalled Cloud Connector."
  Restart-Computer -Force -Timeout 1800
  }
  EOT
  filename = "${path.module}/DATA/InstallPreReqsOnCC.ps1"
}
 
#### Create PowerShell file for installing the Citrix Remote PoSH SDK on AVM - we need to determine the correct RL-ID
resource "local_file" "InstallPreReqsOnAVM1-ps1" {
content  = <<-EOT
#### Need to invoke PowerShell as Domain User as the provisioner does not allow to be run in a Domain Users-context
$PSUsername = '${var.Provisioner_DomainAdmin-Username}'
$PSPassword = '${var.Provisioner_DomainAdmin-Password}'
$PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
$PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
$path = "${var.CC_Install_LogPath}"
If(!(test-path -PathType container $path))
{
    New-Item -ItemType Directory -Path $path
}
Add-Content ${var.CC_Install_LogPath}/log.txt "`nScript started."
# Download Citrix Remote PowerShell SDK
Invoke-WebRequest '${var.CC_Install_RPoSHURI}' -OutFile '${var.CC_Install_LogPath}/DATA/CitrixPoshSdk.exe'
Add-Content ${var.CC_Install_LogPath}/log.txt "`nPowerShell SDK downloaded."
# Install Citrix Remote PowerShell SDK
Start-Process -Filepath "${var.CC_Install_LogPath}/DATA/CitrixPoshSdk.exe" -ArgumentList "-quiet"
Add-Content ${var.CC_Install_LogPath}/log.txt "`nPowerShell SDK installed."
# Timeout to settle all processes
Start-Sleep -Seconds 60
Add-Content ${var.CC_Install_LogPath}/log.txt "`nTimeout elapsed."
}
EOT
filename = "${path.module}/DATA/InstallPreReqsOnAVM1.ps1"
}
 
#### Create PowerShell file for installing the Citrix Remote PoSH SDK on AVM - we need to determine the correct RL-ID
resource "local_file" "InstallPreReqsOnAVM2-ps1" {
content  = <<-EOT
#### Need to invoke PowerShell as Domain User as the provisioner does not allow to be run in a Domain Users-context
$PSUsername = '${var.Provisioner_DomainAdmin-Username}'
$PSPassword = '${var.Provisioner_DomainAdmin-Password}'
$PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
$PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
$path = "${var.CC_Install_LogPath}"
# Correct the Resource Location ID in cwc.json file
$requestUri = "https://api-eu.cloud.com/resourcelocations"
$headers = @{ "Accept"="application/json"; "Authorization" = "${var.CC_APIKey-Bearer}"; "Citrix-CustomerId" = "${var.CC_CustomerID}"}
$response = Invoke-RestMethod -Uri $requestUri -Method GET -Headers $headers | Convertto-Json
$RLs = ConvertFrom-Json $response
$RLFiltered = $RLs.items | Where-Object name -in "${var.CC_RestRLName}"
Add-Content ${var.CC_Install_LogPath}/log.txt $RLFiltered
$RLID = $RLFiltered.id
$OrigContent = Get-Content ${var.CC_Install_LogPath}/DATA/cwc.json
Add-Content ${var.CC_Install_LogPath}/log.txt $RLID
Add-Content ${var.CC_Install_LogPath}/log.txt $OrigContent
$CorrContent = $OrigCOntent.Replace('XXXXXXXXXX', $RLID) | Out-File -FilePath ${var.CC_Install_LogPath}/DATA/cwc.json
Add-Content ${var.CC_Install_LogPath}/DATA/GetRLID.txt $RLID
Add-Content ${var.CC_Install_LogPath}/log.txt "`ncwc.json corrected."
Add-Content ${var.CC_Install_LogPath}/log.txt "`nScript completed."
}
EOT
filename = "${path.module}/DATA/InstallPreReqsOnAVM2.ps1"
}
 
### Upload required components to AVM
#### Set the Provisioner-Connection
resource "null_resource" "UploadRequiredComponentsToAVM" {
 depends_on = [ local_file.InstallPreReqsOnAVM1-ps1, local_file.GetSiteIDScript ]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_AVM-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
###### Upload PreReqs script to AVM
  provisioner "file" {
    source      = "${path.module}/DATA/InstallPreReqsOnAVM1.ps1"
    destination = "${var.CC_Install_LogPath}/DATA/InstallPreReqsOnAVM1.ps1"
   
  }
 
  provisioner "file" {
    source      = "${path.module}/DATA/InstallPreReqsOnAVM2.ps1"
    destination = "${var.CC_Install_LogPath}/DATA/InstallPreReqsOnAVM2.ps1"
   
  }
}
 
### Call the required scripts on AVM
#### Set the Provisioner-Connection
resource "null_resource" "CallRequiredScriptsOnAVM1" {
 depends_on = [ null_resource.UploadRequiredComponentsToAVM ]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_AVM-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
###### Execute the PreReqs script on AVM
 provisioner "remote-exec" {
    inline = [
      "powershell -File ${var.CC_Install_LogPath}/DATA/InstallPreReqsOnAVM1.ps1"
    ]
  }
}  
 
resource "null_resource" "CallRequiredScriptsOnAVM2" {
 depends_on = [ null_resource.CallRequiredScriptsOnAVM1 ]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_AVM-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
###### Execute the PreReqs script on AVM
 provisioner "remote-exec" {
    inline = [
      "powershell -File ${var.CC_Install_LogPath}/DATA/InstallPreReqsOnAVM2.ps1"
    ]
  }
}  
 
##############################################################################################################################
 
### Upload required components to CC1
#### Set the Provisioner-Connection
resource "null_resource" "UploadRequiredComponentsToCC1" {
 depends_on = [ local_file.InstallPreReqsOnCC-ps1, null_resource.CallRequiredScriptsOnAVM2]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_DDC1-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
###### Upload Cloud Connector configuration file to CC1
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/cwc.json"
    destination = "${var.CC_Install_LogPath}/DATA/cwc.json"
   
  }
 
###### Upload SiteID file to CC1
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/GetSiteID.txt"
    destination = "${var.CC_Install_LogPath}/DATA/GetSiteID.txt"
   
  }
 
###### Upload ZoneID file to CC1
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/GetZoneID.txt"
    destination = "${var.CC_Install_LogPath}/DATA/GetZoneID.txt"
   
  }
 
###### Upload RLID file to CC1
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/GetRLID.txt"
    destination = "${var.CC_Install_LogPath}/DATA/GetRLID.txt"
   
  }
 
###### Upload PreReqs script to CC1
  provisioner "file" {
    source      = "${path.module}/DATA/InstallPreReqsOnCC.ps1"
    destination = "${var.CC_Install_LogPath}/DATA/InstallPreReqsOnCC.ps1"
   
  }
}
 
###### Execute the PreReqs script on CC1
resource "null_resource" "CallRequiredScriptsOnCC1" {
 depends_on = [ null_resource.UploadRequiredComponentsToCC1 ]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_AVM-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
  provisioner "remote-exec" {
    inline = [
      "powershell -File ${var.CC_Install_LogPath}/DATA/InstallPreReqsOnCC.ps1"
    ]
  }
}
 
### Upload required components to CC2
#### Set the Provisioner-Connection
resource "null_resource" "UploadRequiredComponentsToCC2" {
 depends_on = [ local_file.InstallPreReqsOnCC-ps1,null_resource.CallRequiredScriptsOnAVM2  ]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_DDC2-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
  ###### Upload Cloud Connector configuration file to CC2
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/cwc.json"
    destination = "${var.CC_Install_LogPath}/DATA/cwc.json"
   
  }
 
###### Upload SiteID file to CC2
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/GetSiteID.txt"
    destination = "${var.CC_Install_LogPath}/DATA/GetSiteID.txt"
   
  }
 
###### Upload ZoneID file to CC2
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/GetZoneID.txt"
    destination = "${var.CC_Install_LogPath}/DATA/GetZoneID.txt"
   
  }
 
###### Upload RLID file to CC2
  provisioner "file" {
    source      = "${var.CC_Install_LogPath}/DATA/GetRLID.txt"
    destination = "${var.CC_Install_LogPath}/DATA/GetRLID.txt"
   
  }
 
###### Upload PreReqs script to CC2
  provisioner "file" {
    source      = "${path.module}/DATA/InstallPreReqsOnCC.ps1"
    destination = "${var.CC_Install_LogPath}/DATA/InstallPreReqsOnCC.ps1"
   
  }
}
 
###### Execute the PreReqs script on CC2
resource "null_resource" "CallRequiredScriptsOnCC2" {
 depends_on = [ null_resource.UploadRequiredComponentsToCC2 ]
 connection {
    type            = var.Provisioner_Type
    user            = var.Provisioner_Admin-Username
    password        = var.Provisioner_Admin-Password
    host            = var.Provisioner_AVM-IP
    timeout         = var.Provisioner_Timeout
 
  }
 
  provisioner "remote-exec" {
    inline = [
      "powershell -File ${var.CC_Install_LogPath}/DATA/InstallPreReqsOnCC.ps1"
    ]
  }
}

 

Module 3: CConAWS-CCStuff

These are the Terraform configuration files for Module 3 (excerpts):

_CCOnAWS-CCStuff-CreateCCEntities.tf

# Terraform deployment of Citrix DaaS on Amazon AWS EC2
## Creating all Citrix Cloud-related entities
 
### Creating a Hypervisor Connection
#### Retrieving the ZoneID
data "local_file" "LoadZoneID" {
  filename = "${var.CC_Install_LogPath}/DATA/GetZoneID.txt"
}
 
#### Creating the Hypervisor Connection
resource "citrix_aws_hypervisor" "CreateHypervisorConnection" {
  depends_on = [ data.local_file.LoadZoneID ]
    name              = "${var.CC_AWSEC2-HypConn-Name}"
    zone              = data.local_file.LoadZoneID.content
    api_key           = "${var.AWSEC2_AccessKey}"
    secret_key        = "${var.AWSEC2_AccessKeySecret}"
    region            = "${var.AWSEC2_Region}"
}
 
### Creating a Hypervisor Resource Pool
#### Retrieving the VPC name based on the VPC ID
data "aws_vpc" "AWSVPC" {
  id = "${var.AWSEC2_VPC-ID}"
 
}
 
#### Retrieving the Availability Zone
data "aws_vpc" "AWSAZ" {
  id = "${var.AWSEC2_VPC-ID}"
}
 
#### Retrieving the Subnet Mask based on the Subnet ID
data "aws_subnet" "AWSSubnet" {
  id = "${var.AWSEC2_Subnet-ID}"
}
 
#### Create the Hypervisor Resource Pool
resource "citrix_aws_hypervisor_resource_pool" "CreateHypervisorPool" {
  depends_on            = [ citrix_aws_hypervisor.CreateHypervisorConnection ]
    name                = "${var.CC_AWSEC2-HypConnPool-Name}"
    hypervisor          = citrix_aws_hypervisor.CreateHypervisorConnection.id
    subnets             = [
                             "${data.aws_subnet.AWSSubnet.cidr_block}",
                          ]
    vpc                 = "${var.AWSEC2_VPC-Name}"
    availability_zone   = data.aws_subnet.AWSSubnet.availability_zone
}
 
#### Create AMI from WMI instance
resource "aws_ami_from_instance" "CreateAMIFromWMI" {
  name               = "TACG-AWS-TF-AMIFromWMI"
  source_instance_id = "${var.AWSEC2_AMI-ID}"
  timeouts {
    create = "45m"
  }
}
 
#### Sleep 60s to let AWS Background processes settle
resource "time_sleep" "wait_60_seconds" {
  depends_on = [ citrix_aws_hypervisor_resource_pool.CreateHypervisorPool, aws_ami_from_instance.CreateAMIFromWMI ]
  create_duration = "60s"
}
 
#### Create the Machine Catalog
resource "citrix_machine_catalog" "CreateMCSCatalog" {
  depends_on            = [ time_sleep.wait_60_seconds ]
    name                        = "${var.CC_AWSEC2-MC-Name}"
    description                 = "${var.CC_AWSEC2-MC-Description}"
    allocation_type             = "${var.CC_AWSEC2-MC-AllocationType}"
    session_support             = "${var.CC_AWSEC2-MC-SessionType}"
    is_power_managed            = true
    is_remote_pc                = false
    provisioning_type           = "MCS"
    zone                        = data.local_file.LoadZoneID.content
    provisioning_scheme         =   {
        hypervisor               = citrix_aws_hypervisor.CreateHypervisorConnection.id
        hypervisor_resource_pool = citrix_aws_hypervisor_resource_pool.CreateHypervisorPool.id
        identity_type            = "${var.CC_AWSEC2-MC-IDPType}"
        machine_domain_identity  = {
            domain                   = "${var.CC_AWSEC2-MC-Domain}"
           #domain_ou                = "${var.CC_AWSEC2-MC-DomainOU}"
            service_account          = "${var.Provisioner_DomainAdmin-Username-UPN}"
            service_account_password = "${var.Provisioner_DomainAdmin-Password}"
        }
        aws_machine_config = {
            image_ami        = aws_ami_from_instance.CreateAMIFromWMI.id
            master_image     = aws_ami_from_instance.CreateAMIFromWMI.name
            service_offering = "${var.CC_AWSEC2-MC-Service_Offering}"
        }
        number_of_total_machines =  "${var.CC_AWSEC2-MC-Machine_Count}"
        network_mapping = {
            network_device = "0"
            network        = "${data.aws_subnet.AWSSubnet.cidr_block}"
        }
        machine_account_creation_rules = {
            naming_scheme      = "${var.CC_AWSEC2-MC-Naming_Scheme_Name}"
            naming_scheme_type = "${var.CC_AWSEC2-MC-Naming_Scheme_Type}"
        }
    }
}
 
#### Sleep 60s to let CC Background processes settle
resource "time_sleep" "wait_60_seconds_1" {
  #depends_on = [ citrix_machine_catalog.CreateMCSCatalog ]
  create_duration = "60s"
}  
 
#### Create an Example-Policy Set
resource "citrix_policy_set" "SetPolicies" {
  count = var.CC_AWSEC2-Policy-IsNotDaaS ? 1 : 0
  depends_on                = [ time_sleep.wait_60_seconds_1 ]
    name                    = "${var.CC_AWSEC2-Policy-Name}"
    description             = "${var.CC_AWSEC2-Policy-Description}"
    type                    = "DeliveryGroupPolicies"
    scopes                  = [ "All" ]
 
    policies                = [
                              {
                                  name            = "TACG-AWS-TF-Pol1"
                                  description     = "Policy to enable use of Universal Printer"
                                  is_enabled      = true
                                  policy_settings = [
                                                      {
                                                          name = "UniversalPrintDriverUsage"
                                                          value = "Use universal printing only"
                                                          use_default = false
                                                      },
                                          ]
                                           policy_filters = [
                                                      {
                                                          type = "DesktopGroup"
                                                          is_enabled = true
                                                          is_allowed = true
                                                      },
                                          ]
                                 
                              },
                              {
                                  name            = "TACG-AWS-TF-Pol2"
                                  description     = "Policy to enable Client Drive Redirection"
                                  is_enabled      = true
                                     policy_settings = [
                                                      {
                                                          name = "UniversalPrintDriverUsage"
                                                          value = "Prohibited"
                                                          use_default = false
                                                      },
                                          ]
                                  policy_filters = [
                                                      {
                                                          type = "DesktopGroup"
                                                          is_enabled = true
                                                          is_allowed = true
                                                      },
                                          ]
                              }
                            ]
                  }
 
#### Sleep 60s to let CC Background processes settle
resource "time_sleep" "Wait_60_Seconds_2" {
  depends_on = [ citrix_policy_set.SetPolicies ]
  create_duration = "60s"
}
 
#### Create the Delivery Group based on the Machine Catalog
resource "citrix_delivery_group" "CreateDG" {
  depends_on = [ time_sleep.Wait_60_Seconds_2]
    name                                    = "${var.CC_AWSEC2-DG-Name}"
    associated_machine_catalogs             = [
        {
            #machine_catalog = citrix_machine_catalog.CreateMCSCatalog.id
            machine_catalog                 ="f4e34a11-6e31-421f-8cb4-060bc4a13fef"
            machine_count                   = "${var.CC_AWSEC2-MC-Machine_Count}"
        }
    ]
    desktops                                = [
        {
            published_name                  = "${var.CC_AWSEC2-DG-PublishedDesktopName}"
            description                     = "${var.CC_AWSEC2-DG-Description}"
            restricted_access_users         = {
                                               allow_list = [ "TACG-AWS\\vdaallowed" ]
                                              }
            enabled                         = true
            enable_session_roaming          = var.CC_AWSEC2-DG-SessionRoaming
        }
       
    ]
    autoscale_settings                      = {
            autoscale_enabled                               = true
            disconnect_peak_idle_session_after_seconds      = 300
            log_off_peak_disconnected_session_after_seconds = 300
            peak_log_off_action                             = "Nothing"
            power_time_schemes              = [
                                              {
                                               days_of_week = [
                                                              "Monday",
                                                              "Tuesday",
                                                              "Wednesday",
                                                              "Thursday",
                                                              "Friday"
                                                              ]
                name                        = "${var.CC_AWSEC2-DG-AS-Name}"
                display_name                = "${var.CC_AWSEC2-DG-AS-Name}"
                peak_time_ranges            = [
                                                "09:00-17:00"
                                              ]
                pool_size_schedules         = [
                                               {
                                                 time_range = "09:00-17:00",
                                                 pool_size = 1
                                               }
                                              ]
                pool_using_percentage       = false
            },
        ]
    }
    restricted_access_users                 = {
                                                    allow_list = [ "TACG-AWS\\vdaallowed" ]
                                              }
    reboot_schedules                        = [
                                               {
                                                 name = "TACG-AWS-Reboot Schedule"
                                                 reboot_schedule_enabled = true
                                                 frequency = "Weekly"
                                                 frequency_factor = 1
                                                 days_in_week = [
                                                   "Sunday",
                                                       ]
                                                 start_time = "02:00"
                                                 start_date = "2024-01-01"
                                                 reboot_duration_minutes = 0
                                                 ignore_maintenance_mode = true
                                                 natural_reboot_schedule = false
                                               }
  ]
    policy_set_id = citrix_policy_set.SetPolicies.id
}

 

 

 

 

 

 

 

 

 

 


User Feedback


There are no comments to display.



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...