Jump to content

Deployment Guide: Using Terraform to deploy a Citrix Virtual Apps and Desktops 2402 LTSR CU1 site on XenServer 8

  • Contributed By: Gerhard Krenn

 

Using Terraform to deploy a Citrix Virtual Apps and Desktops 2402 LTSR CU1 site on XenServer 8
 

Overview

This guide will showcase the possibility of deploying a Citrix DaaS Virtual Apps and Desktops 2402 LTSR CU1 site on XenServer 8 using Terraform. We want to reduce manual interventions to the absolute minimum.

In the end, you will have created:

  • 2 Virtual Machines registered with the Domain for the deployment of the Delivery Controllers 
  • 1 Virtual Machine registered with the Domain for deploying all Terraform scripts (explanations follow later in this guide)
  • A complete CVAD 2402 deployment containing 2 Delivery Controllers, StoreFront, WebStudio, and the connection to a central License Server
  • A Hosting Connection to XenServer 8
  • A Machine Catalog containing 2 VDI machines based on a Master Image
  • A Delivery Group with full AutoScale support


Installation and Configuration of Terraform

Please find a description of installing Terraform and initial configurations in our Tech Zone Deployment Guide: Installing Terraform and Configuring the Citrix Terraform Provider.
All Terraform configuration files can be found later on GitHub.

Deployment overview

This guide uses an existing domain and will not deploy a new one. For further instructions on deploying a new domain, refer to the guide Citrix DaaS and Terraform - Automatic Deployment of a Resource Location on Microsoft Azure
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 primary Domain Controller using IPSec-based Site-to-Site VPNs. Each Resource Location has its subdomain.
 

Note:

We did not use loop-constructs or count keywords —each resource is created explicitly—for easier reading and understanding.
 

The Terraform flow is split into five different modules:

  • Module One - this part can be run on any computer where Terraform is installed :
    • Creating the initially needed Resources on XenServer 8:
      • Create two Windows Server 2022-based VMs used as Delivery Controller VMs in Module 2
      • Create a Windows Server 2022-based VM acting as an Administrative Workstation for running Terraform Modules 3 and 4.
        This workstation is necessary because WinRM is used for further configuration and deployment.
         

Important: 

The Image Template VM must be configured before Terraform uses it to create the Machine Catalog. Please ensure that WinRM is functioning even though the VM is NOT part of a Domain. Instructions are provided later in this guide.

The Administrative VM must have Terraform installed - use the Chocolately Guidance provided previously for installation.
 

  • Module Two—This part can be run on any computer where Terraform is installed but relies heavily on WinRM. It can only be run after Module One is completed.
    Due to the very early version of the Terraform provider for XenServer, the following essential steps must be done by calling PowerShell scripts on the three previously created VMs using WinRM:
    • Rename the VM names to meet the AD requirements
    • Set the correct IP addresses
    • Add the 3 VMs to the Domain
       
  • Module Three -  this part can only be run after completion of Module Two.
    It must be run on the previously created Administrative VM as the deployment relies heavily on WinRM:
    • Creating the needed databases
    • Installing Citrix Virtual Apps and Desktops on the Delivery Controller VMs
    • Creating the Citrix Virtual Apps and Desktops site
    • Installing Citrix StoreFront on the Delivery Controller VMs
    • Configuring a Citrix StoreFront site
       

Important: 

The Terraform Provider can only configure StoreFront on one StoreFront server/Delivery Controller (listed in the Provider configuration). Due to current limitations In PowerShell-Invoking, we cannot automatically add the second Delivery Controller/Storefront Server to the configured StoreFront Cluster.

Be aware that you must manually sync the configuration to the second StoreFront server/Delivery Controller.
 

stf-provider.png

  • Module Four - this part can only be run after completion of Module Three.
    It must be run on the previously created Administrative VM as the deployment relies heavily on WinRM:
    • Changing the SSL certificate on the Delivery Controllers/StoreFront servers to a publicly signed certificate to avoid certificate issues
    • Uploading a valid license file to a License Server locally installed on the Primary Delivery Controller (optional)
    • Setting the License Configuration of the site to point to a central License Server (optional)
       
  • Module Five - this part can only be run after the completion of Module Four.
    It must be run on the previously created Administrative VM as the deployment relies heavily on WinRM:
    • Creating all needed entities in the Citrix Virtual Apps and Desktops site:
  • Creating a dedicated Hypervisor Connection to XenServer 8
  • Creating a dedicated Hypervisor Resource Pool
  • Creating a Machine Catalog based on the referenced Master Image
  • Creating a Delivery Group
  • Creating AutoScale settings and applying these to the newly created Delivery Group
     

Important:

Make sure that all Terraform-related VMs can communicate using WinRM. The deployment fails if the Admin-VM cannot connect to the CCs using WinRM. Various configuration guides for WinRM can be found on the Internet. We rely on GPOs related to WinRM to configure all Domain Members accordingly.
 

Important:

Ensure that the VM planned to be the Master Image for the Worker VMs is installed and configured and that all the needed software is installed and configured.
It also needs to have the VDA installed and configured.
Providing a Worker-Master Image VM without a VDA breaks the Terraform flow.
 

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 wish 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 DDC1-VM is working as intended:

 

locals {

  #### Test the WinRM communication

  #### Need to invoke PowerShell as Domain User as the provisioner does not allow it 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 that must be set.
Some configuration settings are propagated throughout the whole Terraform configuration...

You must start each module 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.
 

Important:

Each module/step must be completed successfully before the next module can be started.
 

 

File System structure

Root-Directory

Module 1: _CVADOnXenServer-Creation:

Filename                                                                                                       

Purpose                                                

CVADOnXenServer-Create.tf

Resource configuration and primary flow definition

CVADOnXenServer-Create-variables.tf

Definition of Variables

CVADOnXenServer-Create.auto.tfvars.json

Setting the values of the Variables

CVADOnXenServer-Create-Provider.tf

Provider definition and configuration

CVADOnXenServer-Create-Provider-variables.tf

Definition of Variables

CVADOnXenServer-Create-Provider.auto.tfvars.json

Setting the values of the Variables



Module 2: _CVADOnXenServer-InitialConfiguration:

Filename                                                                                                        

Purpose                                               

CVADOnXenServer-InitialConfiguration.tf

Resource configuration and primary flow definition

CVADOnXenServer-InitialConfiguration-variables.tf

Definition of Variables

CVADOnXenServer-InitialConfiguration.auto.tfvars.json

Setting the values of the Variables

CVADOnXenServer-Provider.tf

Provider definition and configuration

CVADOnXenServer-Provider-variables.tf

Definition of Variables

CVADOnXenServer-Provider.auto.tfvars.json

Setting the values of the Variables

DATA Directory

Contains dynamically created scripts which will be uploaded and executed on the Cloud Connector VMs

 

Module 3: _CVADOnXenServer-InitialCVADConfiguration:

Filename                                                                                                        

Purpose                                               

CVADOnXenServer-InitialCVADConfiguration.tf

Resource configuration and primary flow definition

CVADOnXenServer-InitialCVADConfiguration-variables.tf

Definition of Variables

CVADOnXenServer-InitialCVADConfiguration.auto.tfvars.json

Setting the values of the Variables

CVADOnXenServer-Provider.tf

Provider definition and configuration

CVADOnXenServer-Provider-variables.tf

Definition of Variables

CVADOnXenServer-Provider.auto.tfvars.json

Setting the values of the Variables

terraform.tfvars

Setting the values of Variables that can not be set by a .json-based file

 

Module 4: _CVADOnXenServer-Configuration-AfterStorefront:

Filename                                                                                                        

Purpose                                               

CVADOnXenServer-Configuration-AfterStorefront-scripts.tf

Resource configuration and primary flow definition

CVADOnXenServer-Configuration-AfterStorefront-scripts-variables.tf

Definition of Variables

CVADOnXenServer-Configuration-AfterStorefront-scripts.auto.tfvars.json

Setting the values of the Variables

terraform.tvars

Setting the values of Variables that can not be set by a .json-based file

CVADOnXenServer-Provider.tf

Provider definition and configuration

CVADOnXenServer-Provider-variables.tf

Definition of Variables

CVADOnXenServer-Provider.auto.tfvars.json

Setting the values of the Variables

 

Module 5: _CVADOnXenServer-CVAD-Entities:

Filename                                                                                                        

Purpose                                               

CVADOnXenServer-CVAD-CreateEntities.tf

Resource configuration and primary flow definition

CVADOnXenServer-CVAD-CreateEntities-variables.tf

Definition of Variables

CVADOnXenServer-CVAD-CreateEntities.auto.tfvars.json

Setting the values of the Variables

terraform.tvars

Setting the values of Variables that can not be set by a .json-based file

CVADOnXenServer-Provider.tf

Provider definition and configuration

CVADOnXenServer-Provider-variables.tf

Definition of Variables

CVADOnXenServer-Provider.auto.tfvars.json

Setting the values of the Variables

 

Caution:

All Terraform-related directories and files (.terraform-terraform.lock.hclterraform.tfstateterraform.tfstatemust not be changed or deleted - doing so might break the deployment.
 

Change the settings in the .json or .tfvars files to match your needs.

To ensure a smooth and error-free build, the following prerequisites must be met before setting the corresponding settings or running the Terraform workflow.

 

 Software Components for Configuration and Deployment

Important:

Please ensure that the Delivery Controller VMs have the CVAD 2402 LTSR CU1-ISO mounted so Terraform can access it during the configuration run.
 

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

  • XenServer 8 PowerShell SDK. Download the XenServer 8 PowerShell SDK Installer
  • The CVAD 2402 CU1 installer. Terraform anticipates that the Installer ISO is mounted.
  • The StoreFront installer. Terraform anticipates that the Installer ISO is mounted.

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 to which all the required software is uploaded - or directly from the Internet.
The URIs of the Storage Repository can be set in the corresponding variables:

...

 "CVAD_Install_Source-Drive":"D:",

 "CVAD_Install_Source-Path":"x64/\"XenDesktop Setup\"/XenDesktopServerSetup.exe",

 "SF_Install_Source-Path":"x64/StoreFront/CitrixStoreFront-x64.exe -silent",

...

We must also determine various information outside the XenServer Cluster to correctly set specific variables, such as Network and Master Image names.

The XenServer Cmdlets are a PowerShell extension for accessing a XenServer 8 environment.
You must install the  XenServer PowerShell cmdlets to proceed with the following steps.

The first step is to connect to the XenServer-Cluster:

PS C:\_TACG> Connect-Xenserver -Url https://10.10.111.11 -Username ********** -Password !**********!

 

New Security Certificate

The certificate fingerprint of the server you have connected to is :

4B:89:BF:DA:B6:B4:20:71:D9:45:28:A8:FC:9E:60:12:96:0A:5F:C3

The certificate on this server is not trusted.

Do you wish to continue?

[J] Ja  [N] Nein  [H] Anhalten  [?] Hilfe (Standard ist "J"): J

 

PS C:\_TACG>

Now we need to get information about the available VM templates:

PS C:\_TACG> Import-Module XenServerPSModule
PS C:\_TACG> Connect-Xenserver -Url https://10.10.111.11 -Username ********** -Password !**********!
PS C:\_TACG> Get-XenVMWhere {$_.is_a_template -eq $True -and $_.domid -ne 0}  | select name_label | Sort-Object -Property name_label

name_label
----------
1
1
1
2
2
2
3
3
CentOS 7
CentOS Stream 9 (preview)
Citrix_XD_MC-TACG-TF-CVAD-XS8
Debian Bookworm 12 (preview)
Debian Bullseye 11
Debian Buster 10
Gooroom Platform 2.0
NeoKylin Linux Server 7
Oracle Linux 7
Oracle Linux 8
Other install media
Red Hat Enterprise Linux 7
Red Hat Enterprise Linux 8
Red Hat Enterprise Linux 9 (preview)
Rocky Linux 8
Rocky Linux 9 (preview)
Scientific Linux 7
SUSE Linux Enterprise 15 (64-bit)
SUSE Linux Enterprise Server 12 SP5 (64-bit)
TMPL-W11
TMPL-W11-VDA
TMPL-W2K22
TMPL-W2K22-WinRM
Ubuntu Focal Fossa 20.04
Ubuntu Jammy Jellyfish 22.04
Windows 10 (64-bit)
Windows 11
Windows Server 2016 (64-bit)
Windows Server 2019 (64-bit)
Windows Server 2022 (64-bit)


PS C:\_TACG>

We have determined all the values needed and can start the deployment.

Important: 

Remember to put all previously determined entity values in the corresponding .auto.tfvars.json variable files.
 

Module 1: Create the initially needed Resources on XenServer 8

This module is split into the following configuration parts:

  • Creating the initially needed Resources on XenServer 8:
    • Create two Windows Server 2022-based VMs used as Delivery Controller VMs in Module 2
    • Create a Windows Server 2022-based VM acting as an Administrative Workstation for running Terraform Modules 3 and 4.
      This is necessary because WinRM is used for further configuration and deployment.

Terraform automatically does all these steps.

Important:

The first and second modules are separated from the following steps as we assume no Admin-VM is installed in the corresponding environment on the XenServer cluster. 
The Admin-VM is created now in Module 1 and configured in Module 2, and all subsequent modules must be run from it. Working with WinRM calls over the Internet would pose a security threat and significantly reduce the performance of the Terraform-based deployment. 
These are the reasons for the split approach.
 

Important:

Before starting the Terraform workflow, please ensure you have configured the variables according to your needs using the corresponding .auto.tfvars.json and/or terraform.tfvars file.
 

The configuration can be started by following the standard Terraform workflow:

terraform init,
terraform plan
 

and if no errors occur

terraform apply

PS C:\_TACG\_CVADOnXenServer\_CVADOnXenServer-Creation> terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of xenserver/xenserver...
- Installing xenserver/xenserver v0.1.1...
- Installed xenserver/xenserver v0.1.1 (self-signed, key ID FABD99A0D7648275)
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\_CVADOnXenServer\_CVADOnXenServer-Creation> terraform plan
data.xenserver_sr.sr: Reading...
data.xenserver_network.network: Reading...
data.xenserver_network.network: Read complete after 0s
data.xenserver_sr.sr: Read complete after 0s

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:

  # xenserver_sr.local will be created
  + resource "xenserver_sr" "local" {
      + content_type     = "ISOs"
      + device_config    = {
          + "cifspassword" = "************"
          + "location"     = "\\\\tacg-dc.the-austrian-citrix-guy.at\\_sw"
          + "type"         = "cifs"
          + "username"     = "************@the-austrian-citrix-guy.at"
          + "vers"         = "1.0"
        }
      + host             = (known after apply)
      + id               = (known after apply)
      + name_description = "ISO repository on TACG-DC"
      + name_label       = "ISO on TACG-DC"
      + shared           = true
      + sm_config        = {
          + "iso_type" = "cifs"
        }
      + type             = "iso"
      + uuid             = (known after apply)
    }

  # xenserver_vm.vm["windows-vm"] will be created
  + resource "xenserver_vm" "vm" {
      + boot_mode         = (known after apply)
      + boot_order        = (known after apply)
      + cdrom             = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
      + check_ip_timeout  = 0
      + cores_per_socket  = 2
      + default_ip        = (known after apply)
      + dynamic_mem_max   = (known after apply)
      + dynamic_mem_min   = (known after apply)
      + hard_drive        = (known after apply)
      + id                = (known after apply)
      + name_description  = ""
      + name_label        = "TACG-XS-DDC1"
      + network_interface = [
          + {
              + device       = "0"
              + mac          = (known after apply)
              + network_uuid = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
              + other_config = (known after apply)
              + vif_ref      = (known after apply)
            },
        ]
      + other_config      = {}
      + static_mem_max    = 8589934592
      + static_mem_min    = (known after apply)
      + template_name     = "TMPL-W2K22-WinRM"
      + uuid              = (known after apply)
      + vcpus             = 2
    }

  # xenserver_vm.vm["windows-vm1"] will be created
  + resource "xenserver_vm" "vm" {
      + boot_mode         = (known after apply)
      + boot_order        = (known after apply)
      + cdrom             = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
      + check_ip_timeout  = 0
      + cores_per_socket  = 2
      + default_ip        = (known after apply)
      + dynamic_mem_max   = (known after apply)
      + dynamic_mem_min   = (known after apply)
      + hard_drive        = (known after apply)
      + id                = (known after apply)
      + name_description  = ""
      + name_label        = "TACG-XS-DDC2"
      + network_interface = [
          + {
              + device       = "0"
              + mac          = (known after apply)
              + network_uuid = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
              + other_config = (known after apply)
              + vif_ref      = (known after apply)
            },
        ]
      + other_config      = {}
      + static_mem_max    = 8589934592
      + static_mem_min    = (known after apply)
      + template_name     = "TMPL-W2K22-WinRM"
      + uuid              = (known after apply)
      + vcpus             = 2
    }

  # xenserver_vm.vm["windows-vm2"] will be created
  + resource "xenserver_vm" "vm" {
      + boot_mode         = (known after apply)
      + boot_order        = (known after apply)
      + cdrom             = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
      + check_ip_timeout  = 0
      + cores_per_socket  = 2
      + default_ip        = (known after apply)
      + dynamic_mem_max   = (known after apply)
      + dynamic_mem_min   = (known after apply)
      + hard_drive        = (known after apply)
      + id                = (known after apply)
      + name_description  = ""
      + name_label        = "TACG-XS-CVADAVM"
      + network_interface = [
          + {
              + device       = "0"
              + mac          = (known after apply)
              + network_uuid = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
              + other_config = (known after apply)
              + vif_ref      = (known after apply)
            },
        ]
      + other_config      = {}
      + static_mem_max    = 8589934592
      + static_mem_min    = (known after apply)
      + template_name     = "TMPL-W2K22-WinRM"
      + uuid              = (known after apply)
      + vcpus             = 2
    }

Plan: 4 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\_CVADOnXenServer\_CVADOnXenServer-Creation> terraform validate
Success! The configuration is valid.

PS C:\_TACG\_CVADOnXenServer\_CVADOnXenServer-Creation> terraform apply
data.xenserver_sr.sr: Reading...
data.xenserver_network.network: Reading...
data.xenserver_network.network: Read complete after 0s
data.xenserver_sr.sr: Read complete after 0s

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:

  # xenserver_sr.local will be created
  + resource "xenserver_sr" "local" {
      + content_type     = "ISOs"
      + device_config    = {
          + "cifspassword" = "************"
          + "location"     = "\\\\tacg-dc.the-austrian-citrix-guy.at\\_sw"
          + "type"         = "cifs"
          + "username"     = "************@the-austrian-citrix-guy.at"
          + "vers"         = "1.0"
        }
      + host             = (known after apply)
      + id               = (known after apply)
      + name_description = "ISO repository on TACG-DC"
      + name_label       = "ISO on TACG-DC"
      + shared           = true
      + sm_config        = {
          + "iso_type" = "cifs"
        }
      + type             = "iso"
      + uuid             = (known after apply)
    }
 

  # xenserver_vm.vm["windows-vm"] will be created
  + resource "xenserver_vm" "vm" {
      + boot_mode         = (known after apply)
      + boot_order        = (known after apply)
      + cdrom             = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
      + check_ip_timeout  = 0
      + cores_per_socket  = 2
      + default_ip        = (known after apply)
      + dynamic_mem_max   = (known after apply)
      + dynamic_mem_min   = (known after apply)
      + hard_drive        = (known after apply)
      + id                = (known after apply)
      + name_description  = ""
      + name_label        = "TACG-XS-DDC1"
      + network_interface = [
          + {
              + device       = "0"
              + mac          = (known after apply)
              + network_uuid = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
              + other_config = (known after apply)
              + vif_ref      = (known after apply)
            },
        ]
      + other_config      = {}
      + static_mem_max    = 8589934592
      + static_mem_min    = (known after apply)
      + template_name     = "TMPL-W2K22-WinRM"
      + uuid              = (known after apply)
      + vcpus             = 2
    }

  # xenserver_vm.vm["windows-vm1"] will be created
  + resource "xenserver_vm" "vm" {
      + boot_mode         = (known after apply)
      + boot_order        = (known after apply)
      + cdrom             = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
      + check_ip_timeout  = 0
      + cores_per_socket  = 2
      + default_ip        = (known after apply)
      + dynamic_mem_max   = (known after apply)
      + dynamic_mem_min   = (known after apply)
      + hard_drive        = (known after apply)
      + id                = (known after apply)
      + name_description  = ""
      + name_label        = "TACG-XS-DDC2"
      + network_interface = [
          + {
              + device       = "0"
              + mac          = (known after apply)
              + network_uuid = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
              + other_config = (known after apply)
              + vif_ref      = (known after apply)
            },
        ]
      + other_config      = {}
      + static_mem_max    = 8589934592
      + static_mem_min    = (known after apply)
      + template_name     = "TMPL-W2K22-WinRM"
      + uuid              = (known after apply)
      + vcpus             = 2
    }

  # xenserver_vm.vm["windows-vm2"] will be created
  + resource "xenserver_vm" "vm" {
      + boot_mode         = (known after apply)
      + boot_order        = (known after apply)
      + cdrom             = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
      + check_ip_timeout  = 0
      + cores_per_socket  = 2
      + default_ip        = (known after apply)
      + dynamic_mem_max   = (known after apply)
      + dynamic_mem_min   = (known after apply)
      + hard_drive        = (known after apply)
      + id                = (known after apply)
      + name_description  = ""
      + name_label        = "TACG-XS-CVADAVM"
      + network_interface = [
          + {
              + device       = "0"
              + mac          = (known after apply)
              + network_uuid = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
              + other_config = (known after apply)
              + vif_ref      = (known after apply)
            },
        ]
      + other_config      = {}
      + static_mem_max    = 8589934592
      + static_mem_min    = (known after apply)
      + template_name     = "TMPL-W2K22-WinRM"
      + uuid              = (known after apply)
      + vcpus             = 2
    }

Plan: 4 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

xenserver_sr.local: Creating...
xenserver_sr.local: Creation complete after 1s [id=3efad889-3928-09be-a321-9097264fed21]

xenserver_vm.vm["windows-vm"]: Creating...
xenserver_vm.vm["windows-vm1"]: Creating...
xenserver_vm.vm["windows-vm2"]: Creating...
xenserver_vm.vm["windows-vm1"]: Creation complete after 1s [id=46826138-236c-d683-73ba-5706dae7a4ee]
xenserver_vm.vm["windows-vm"]: Still creating... [10s elapsed]
xenserver_vm.vm["windows-vm2"]: Still creating... [10s elapsed]
xenserver_vm.vm["windows-vm"]: Creation complete after 14s [id=44bc72a7-0ce9-0c6c-442d-e5281a1c3814]
xenserver_vm.vm["windows-vm2"]: Creation complete after 19s [id=cfd97b84-1b3a-1454-afa4-95c64d6b9bd7]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

vm_out = {
  "TACG-XS-CVADAVM" = {
    "boot_mode" = "bios"
    "boot_order" = "cd"
    "cdrom" = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
    "check_ip_timeout" = 0
    "cores_per_socket" = 2
    "default_ip" = ""
    "dynamic_mem_max" = 8589934592
    "dynamic_mem_min" = 8589934592
    "hard_drive" = toset(null) /* of object */
    "id" = "cfd97b84-1b3a-1454-afa4-95c64d6b9bd7"
    "name_description" = ""
    "name_label" = "TACG-XS-CVADAVM"
    "network_interface" = toset([
      {
        "device" = "0"
        "mac" = "d2:12:40:7c:ae:1b"
        "network_uuid" = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
        "other_config" = tomap({})
        "vif_ref" = "OpaqueRef:e5f7b521-54a2-3a25-b7f3-29f5844ef148"
      },
    ])
    "other_config" = tomap({})
    "static_mem_max" = 8589934592
    "static_mem_min" = 8589934592
    "template_name" = "TMPL-W2K22-WinRM"
    "uuid" = "cfd97b84-1b3a-1454-afa4-95c64d6b9bd7"
    "vcpus" = 2
  }
  "TACG-XS-DDC1" = {
    "boot_mode" = "bios"
    "boot_order" = "cd"
    "cdrom" = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
    "check_ip_timeout" = 0
    "cores_per_socket" = 2
    "default_ip" = ""
    "dynamic_mem_max" = 8589934592
    "dynamic_mem_min" = 8589934592
    "hard_drive" = toset(null) /* of object */
    "id" = "44bc72a7-0ce9-0c6c-442d-e5281a1c3814"
    "name_description" = ""
    "name_label" = "TACG-XS-DDC1"
    "network_interface" = toset([
      {
        "device" = "0"
        "mac" = "d6:57:b5:9e:8a:46"
        "network_uuid" = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
        "other_config" = tomap({})
        "vif_ref" = "OpaqueRef:f9f7e8f8-0da2-209a-9571-78567d640395"
      },
    ])
    "other_config" = tomap({})
    "static_mem_max" = 8589934592
    "static_mem_min" = 8589934592
    "template_name" = "TMPL-W2K22-WinRM"
    "uuid" = "44bc72a7-0ce9-0c6c-442d-e5281a1c3814"
    "vcpus" = 2
  }
  "TACG-XS-DDC2" = {
    "boot_mode" = "bios"
    "boot_order" = "cd"
    "cdrom" = "Citrix_Virtual_Apps_and_Desktops_7_2402_LTSR_CU1_1100.iso"
    "check_ip_timeout" = 0
    "cores_per_socket" = 2
    "default_ip" = ""
    "dynamic_mem_max" = 8589934592
    "dynamic_mem_min" = 8589934592
    "hard_drive" = toset(null) /* of object */
    "id" = "46826138-236c-d683-73ba-5706dae7a4ee"
    "name_description" = ""
    "name_label" = "TACG-XS-DDC2"
    "network_interface" = toset([
      {
        "device" = "0"
        "mac" = "c2:4d:eb:72:c8:5d"
        "network_uuid" = "14c664c3-1d69-5baa-6e51-21f7059aec3a"
        "other_config" = tomap({})
        "vif_ref" = "OpaqueRef:14701b3b-5b60-5e30-63f6-c73a9ba2fea1"
      },
    ])
    "other_config" = tomap({})
    "static_mem_max" = 8589934592
    "static_mem_min" = 8589934592
    "template_name" = "TMPL-W2K22-WinRM"
    "uuid" = "46826138-236c-d683-73ba-5706dae7a4ee"
    "vcpus" = 2
  }
}
PS C:\_TACG\_CVADOnXenServer\_CVADOnXenServer-Creation>

XenCenter shows the created and running VMs:
xc-vms-ready1.png

The Terraform flow was completed successfully, and the next module can begin.

Module 2: Install and Configure all Resources needed on XenServer 8

Due to the very early version of the Terraform provider for XenServer, the following essential steps must be done by calling PowerShell scripts on the 3 previously created VMs using WinRM as the Terraform provider for XenServer 8 is not able to fulfill these:

  • Rename the VM names to meet the AD requirements

  • Set the correct IP addresses

  • Add the 3 VMs to the Domain

In the example below, the IP addresses during VM creation were the DHCP addresses 10.10.11.122-12, the VMs had not the needed names, and they were not part of the Domain:
vm-unconfigred.png

 

Important:

Before starting the Terraform workflow, please ensure you have configured the variables according to your needs using the corresponding .auto.tfvars.json and/or terraform.tfvars file.
 

The configuration can be started by following the standard Terraform workflow:

terraform init,
terraform plan
 

and if no errors occur

terraform apply

 

PS C:\TACG\_CVADOnXenServer\_CVADOnXenServer-InitialConfiguration> terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/null...
- Finding latest version of hashicorp/time...
- Finding latest version of hashicorp/local...
- Finding latest version of xenserver/xenserver...
- Installing hashicorp/local v2.5.1...
- Installed hashicorp/local v2.5.1 (signed by HashiCorp)
- Installing xenserver/xenserver v0.1.1...
- Installed xenserver/xenserver v0.1.1 (self-signed, key ID FABD99A0D7648275)
- Installing hashicorp/null v3.2.2...
- Installed hashicorp/null v3.2.2 (signed by HashiCorp)
- Installing hashicorp/time v0.12.0...
- Installed hashicorp/time v0.12.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\_CVADOnXenServer\_CVADOnXenServer-InitialConfiguration> terraform plan
data.xenserver_network.network: Reading...
data.xenserver_sr.sr: Reading...
data.xenserver_vm.vm_data: Reading...
data.xenserver_sr.sr: Read complete after 0s
data.xenserver_network.network: Read complete after 0s
data.xenserver_vm.vm_data: Read complete after 1s

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:

  # local_file.WriteAddToDomainScriptIntoDataDirectory will be created
  + resource "local_file" "WriteAddToDomainScriptIntoDataDirectory" {
      + 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             = "./data/AddToDomain-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteCVADAVMIPScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADAVMIPScriptIntoDataDirectory" {
      + 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             = "./data/CVADAVM-IP-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteDDC1IPScriptIntoDataDirectory will be created
  + resource "local_file" "WriteDDC1IPScriptIntoDataDirectory" {
      + 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             = "./data/DDC1-IP-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteDDC2IPScriptIntoDataDirectory will be created
  + resource "local_file" "WriteDDC2IPScriptIntoDataDirectory" {
      + 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             = "./data/DDC2-IP-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteInstallationScriptIntoDataDirectory will be created
  + resource "local_file" "WriteInstallationScriptIntoDataDirectory" {
      + content              = <<-EOT
            New-Item -Path C:/TEMP/XDINST -ItemType Directory
        EOT
      + 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             = "./data/InstallationLogPath-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRebootScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRebootScriptIntoDataDirectory" {
      + content              = <<-EOT
            Restart-Computer -Force
        EOT
      + 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             = "./data/Reboot-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRenameComputerCVADAVMScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRenameComputerCVADAVMScriptIntoDataDirectory" {
      + 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             = "./data/RenameComputer-CVADAVM-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRenameComputerDDC1ScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRenameComputerDDC1ScriptIntoDataDirectory" {
      + 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             = "./data/RenameComputer-DDC1-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRenameComputerDDC2ScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRenameComputerDDC2ScriptIntoDataDirectory" {
      + 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             = "./data/RenameComputer-DDC2-Script.ps1"
      + id                   = (known after apply)
    }

  # null_resource.UploadAndExecuteChangeIPScript-CVADAVM will be created
  + resource "null_resource" "UploadAndExecuteChangeIPScript-CVADAVM" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteChangeIPScript-DDC1 will be created
  + resource "null_resource" "UploadAndExecuteChangeIPScript-DDC1" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteChangeIPScript-DDC2 will be created
  + resource "null_resource" "UploadAndExecuteChangeIPScript-DDC2" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteRenameScripts-CVADAVM will be created
  + resource "null_resource" "UploadAndExecuteRenameScripts-CVADAVM" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteRenameScripts-DDC1 will be created
  + resource "null_resource" "UploadAndExecuteRenameScripts-DDC1" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteRenameScripts-DDC2 will be created
  + resource "null_resource" "UploadAndExecuteRenameScripts-DDC2" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteScripts-CVADAVM will be created
  + resource "null_resource" "UploadAndExecuteScripts-CVADAVM" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteScripts-DDC1 will be created
  + resource "null_resource" "UploadAndExecuteScripts-DDC1" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteScripts-DDC2 will be created
  + resource "null_resource" "UploadAndExecuteScripts-DDC2" {
      + id = (known after apply)
    }

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

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

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

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

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

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

Plan: 24 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\_CVADOnXenServer\_CVADOnXenServer-InitialConfiguration> terraform validate
Success! The configuration is valid.

PS C:\_TACG\_CVADOnXenServer\_CVADOnXenServer-InitialConfiguration> terraform apply
data.xenserver_sr.sr: Reading...
data.xenserver_vm.vm_data: Reading...
data.xenserver_network.network: Reading...
data.xenserver_sr.sr: Read complete after 0s
data.xenserver_network.network: Read complete after 0s
data.xenserver_vm.vm_data: Read complete after 0s

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:

  # local_file.WriteAddToDomainScriptIntoDataDirectory will be created
  + resource "local_file" "WriteAddToDomainScriptIntoDataDirectory" {
      + 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             = "./data/AddToDomain-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteCVADAVMIPScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADAVMIPScriptIntoDataDirectory" {
      + 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             = "./data/CVADAVM-IP-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteDDC1IPScriptIntoDataDirectory will be created
  + resource "local_file" "WriteDDC1IPScriptIntoDataDirectory" {
      + 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             = "./data/DDC1-IP-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteDDC2IPScriptIntoDataDirectory will be created
  + resource "local_file" "WriteDDC2IPScriptIntoDataDirectory" {
      + 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             = "./data/DDC2-IP-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteInstallationScriptIntoDataDirectory will be created
  + resource "local_file" "WriteInstallationScriptIntoDataDirectory" {
      + content              = <<-EOT
            New-Item -Path C:/TEMP/XDINST -ItemType Directory
        EOT
      + 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             = "./data/InstallationLogPath-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRebootScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRebootScriptIntoDataDirectory" {
      + content              = <<-EOT
            Restart-Computer -Force
        EOT
      + 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             = "./data/Reboot-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRenameComputerCVADAVMScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRenameComputerCVADAVMScriptIntoDataDirectory" {
      + 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             = "./data/RenameComputer-CVADAVM-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRenameComputerDDC1ScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRenameComputerDDC1ScriptIntoDataDirectory" {
      + 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             = "./data/RenameComputer-DDC1-Script.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRenameComputerDDC2ScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRenameComputerDDC2ScriptIntoDataDirectory" {
      + 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             = "./data/RenameComputer-DDC2-Script.ps1"
      + id                   = (known after apply)
    }

  # null_resource.UploadAndExecuteChangeIPScript-CVADAVM will be created
  + resource "null_resource" "UploadAndExecuteChangeIPScript-CVADAVM" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteChangeIPScript-DDC1 will be created
  + resource "null_resource" "UploadAndExecuteChangeIPScript-DDC1" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteChangeIPScript-DDC2 will be created
  + resource "null_resource" "UploadAndExecuteChangeIPScript-DDC2" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteRenameScripts-CVADAVM will be created
  + resource "null_resource" "UploadAndExecuteRenameScripts-CVADAVM" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteRenameScripts-DDC1 will be created
  + resource "null_resource" "UploadAndExecuteRenameScripts-DDC1" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteRenameScripts-DDC2 will be created
  + resource "null_resource" "UploadAndExecuteRenameScripts-DDC2" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteScripts-CVADAVM will be created
  + resource "null_resource" "UploadAndExecuteScripts-CVADAVM" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteScripts-DDC1 will be created
  + resource "null_resource" "UploadAndExecuteScripts-DDC1" {
      + id = (known after apply)
    }

  # null_resource.UploadAndExecuteScripts-DDC2 will be created
  + resource "null_resource" "UploadAndExecuteScripts-DDC2" {
      + id = (known after apply)
    }

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

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

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

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

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

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

Plan: 24 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

local_file.WriteRenameComputerDDC2ScriptIntoDataDirectory: Creating...
local_file.WriteAddToDomainScriptIntoDataDirectory: Creating...
local_file.WriteRenameComputerCVADAVMScriptIntoDataDirectory: Creating...
local_file.WriteInstallationScriptIntoDataDirectory: Creating...
local_file.WriteAddToDomainScriptIntoDataDirectory: Creation complete after 0s [id=d721c2c85f1b55f718484607eb4d908cd4117a89]
local_file.WriteRenameComputerDDC1ScriptIntoDataDirectory: Creating...
local_file.WriteDDC1IPScriptIntoDataDirectory: Creating...
local_file.WriteDDC2IPScriptIntoDataDirectory: Creating...
local_file.WriteRenameComputerDDC2ScriptIntoDataDirectory: Creation complete after 0s [id=e45f52cc5833ef6c95522d1dc76db06122b55325]
local_file.WriteRebootScriptIntoDataDirectory: Creating...
local_file.WriteCVADAVMIPScriptIntoDataDirectory: Creating...
local_file.WriteRenameComputerCVADAVMScriptIntoDataDirectory: Creation complete after 0s [id=05d0c11c3ed7b59e6f2f6b6477ac13efc1e0d745]
local_file.WriteInstallationScriptIntoDataDirectory: Creation complete after 1s [id=fc4ebc0269b8b4100c831a23c05d1851387a1259]
local_file.WriteDDC1IPScriptIntoDataDirectory: Creation complete after 1s [id=f806f929a4626994fe68e3d251c18052396d7787]
local_file.WriteRenameComputerDDC1ScriptIntoDataDirectory: Creation complete after 1s [id=29a62f39046e41393a3c0b33998a54e42e348122]
local_file.WriteDDC2IPScriptIntoDataDirectory: Creation complete after 1s [id=bb7c3a8db9c945a57450d43836d6da1b50998e11]
local_file.WriteRebootScriptIntoDataDirectory: Creation complete after 1s [id=2baf7fa209ad203f96017f90f5727642e5f44a03]
local_file.WriteCVADAVMIPScriptIntoDataDirectory: Creation complete after 1s [id=fa26e26dd3191bc0f9ba8ffe9622c847b327e881]
null_resource.UploadAndExecuteScripts-DDC2: Creating...
null_resource.UploadAndExecuteScripts-CVADAVM: Creating...
null_resource.UploadAndExecuteScripts-DDC1: Creating...
null_resource.UploadAndExecuteScripts-DDC1: Provisioning with 'file'...
null_resource.UploadAndExecuteScripts-DDC2: Provisioning with 'file'...
null_resource.UploadAndExecuteScripts-CVADAVM: 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.UploadAndExecuteScripts-CVADAVM: Provisioning with 'remote-exec'...
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec): Connecting to remote host via WinRM...
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   Host: 10.10.11.130
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   Port: 5985
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   User: administrator
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   Password: true
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   HTTPS: false
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   Insecure: false
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   NTLM: false
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):   CACert: false
null_resource.UploadAndExecuteScripts-CVADAVM (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.UploadAndExecuteScripts-DDC1: Provisioning with 'remote-exec'...
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec): Connecting to remote host via WinRM...
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   Host: 10.10.11.129
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   Port: 5985
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   User: administrator
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   Password: true
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   HTTPS: false
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   Insecure: false
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   NTLM: false
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):   CACert: false
null_resource.UploadAndExecuteScripts-DDC1 (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.UploadAndExecuteScripts-CVADAVM (remote-exec): C:\Users\Administrator>powershell -File C:/temp/InstallationLogPath-Script.ps1


null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec):     Directory: C:\TEMP


null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec): Mode                 LastWriteTime         Length Name
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec): ----                 -------------         ------ ----
null_resource.UploadAndExecuteScripts-CVADAVM (remote-exec): d-----        04.09.2024     15:03                XDINST


#< 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>
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec): C:\Users\Administrator>powershell -File C:/temp/InstallationLogPath-Script.ps1


null_resource.UploadAndExecuteScripts-DDC1 (remote-exec):     Directory: C:\TEMP


null_resource.UploadAndExecuteScripts-DDC1 (remote-exec): Mode                 LastWriteTime         Length Name
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec): ----                 -------------         ------ ----
null_resource.UploadAndExecuteScripts-DDC1 (remote-exec): d-----        04.09.2024     15:03                XDINST


#< 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.UploadAndExecuteScripts-CVADAVM: Creation complete after 2s [id=2757650365038078952]
null_resource.UploadAndExecuteRenameScripts-CVADAVM: Creating...
null_resource.UploadAndExecuteRenameScripts-CVADAVM: 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><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>#< 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.UploadAndExecuteScripts-DDC1: Creation complete after 2s [id=6398287523030180872]
null_resource.UploadAndExecuteRenameScripts-DDC1: Creating...
null_resource.UploadAndExecuteRenameScripts-DDC1: Provisioning with 'file'...
time_sleep.WaitToRebootDDC1AfterRename: Creating...
#< 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.UploadAndExecuteRenameScripts-CVADAVM: Provisioning with 'remote-exec'...
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec): Connecting to remote host via WinRM...
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   Host: 10.10.11.130
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   Port: 5985
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   User: administrator
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   Password: true
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   HTTPS: false
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   Insecure: false
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   NTLM: false
null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec):   CACert: false
null_resource.UploadAndExecuteRenameScripts-CVADAVM (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.UploadAndExecuteRenameScripts-DDC1: Provisioning with 'remote-exec'...
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec): Connecting to remote host via WinRM...
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   Host: 10.10.11.129
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   Port: 5985
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   User: administrator
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   Password: true
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   HTTPS: false
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   Insecure: false
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   NTLM: false
null_resource.UploadAndExecuteRenameScripts-DDC1 (remote-exec):   CACert: false
null_resource.UploadAndExecuteRenameScripts-DDC1 (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>null_resource.UploadAndExecuteRenameScripts-CVADAVM (remote-exec): C:\Users\Administrator>powershell -File C:/TEMP/XDINST/RenameComputer-CVADAVM-Script.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>#< 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.UploadAndExecuteRenameScripts-DDC1 (remote-exec): C:\Users\Administrator>powershell -File C:/TEMP/XDINST/RenameComputer-DDC1-Script.ps1
null_resource.UploadAndExecuteRenameScripts-CVADAVM: Creation complete after 2s [id=6103142682856145408]
time_sleep.WaitToRebootCVADAVMAfterRename: Creating...
null_resource.UploadAndExecuteRenameScripts-DDC1: Creation complete after 3s [id=5450718398756922027]
null_resource.UploadAndExecuteScripts-DDC2: Still creating... [10s elapsed]
time_sleep.WaitToRebootDDC1AfterRename: Still creating... [10s elapsed]
time_sleep.WaitToRebootCVADAVMAfterRename: Still creating... [10s elapsed]
null_resource.UploadAndExecuteScripts-DDC2: Still creating... [20s elapsed]
time_sleep.WaitToRebootDDC1AfterRename: Still creating... [20s elapsed]
time_sleep.WaitToRebootCVADAVMAfterRename: Still creating... [20s elapsed]
null_resource.UploadAndExecuteScripts-DDC2: Still creating... [30s elapsed]
time_sleep.WaitToRebootDDC1AfterRename: Still creating... [30s elapsed]
time_sleep.WaitToRebootCVADAVMAfterRename: Still creating... [30s elapsed]
time_sleep.WaitToRebootDDC1AfterRename: Still creating... [40s elapsed]
time_sleep.WaitToRebootCVADAVMAfterRename: Still creating... [40s elapsed]
time_sleep.WaitToRebootDDC1AfterRename: Still creating... [50s elapsed]
time_sleep.WaitToRebootCVADAVMAfterRename: Still creating... [50s elapsed]
time_sleep.WaitToRebootDDC1AfterRename: Creation complete after 1m0s [id=2024-09-04T13:04:54Z]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Creating...
null_resource.UploadAndExecuteChangeIPScript-DDC1: 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.UploadAndExecuteChangeIPScript-DDC1: Provisioning with 'remote-exec'...
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec): Connecting to remote host via WinRM...
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   Host: 10.10.11.129
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   Port: 5985
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   User: administrator
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   Password: true
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   HTTPS: false
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   Insecure: false
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   NTLM: false
null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec):   CACert: false
null_resource.UploadAndExecuteChangeIPScript-DDC1 (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>time_sleep.WaitToRebootCVADAVMAfterRename: Creation complete after 1m0s [id=2024-09-04T13:04:56Z]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Creating...
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Provisioning with 'file'...

null_resource.UploadAndExecuteChangeIPScript-DDC1 (remote-exec): C:\Users\Administrator>powershell -File C:/TEMP/XDINST/DDC1-IP-Script.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>#< 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.UploadAndExecuteChangeIPScript-CVADAVM: Provisioning with 'remote-exec'...
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec): Connecting to remote host via WinRM...
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   Host: 10.10.11.130
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   Port: 5985
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   User: administrator
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   Password: true
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   HTTPS: false
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   Insecure: false
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   NTLM: false
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec):   CACert: false
null_resource.UploadAndExecuteChangeIPScript-CVADAVM (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.UploadAndExecuteChangeIPScript-CVADAVM (remote-exec): C:\Users\Administrator>powershell -File C:/TEMP/XDINST/CVADAVM-IP-Script.ps1
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [10s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [10s elapsed]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [20s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [20s elapsed]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [30s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [30s elapsed]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [40s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [40s elapsed]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [50s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [50s elapsed]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [1m0s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [1m0s elapsed]
null_resource.UploadAndExecuteChangeIPScript-DDC1: Still creating... [1m10s elapsed]
null_resource.UploadAndExecuteChangeIPScript-CVADAVM: Still creating... [1m10s elapsed]

Error: file provisioner error

│   with null_resource.UploadAndExecuteScripts-DDC2,
│   on CVADOnXenServer-InitialConfiguration.tf line 235, in resource "null_resource" "UploadAndExecuteScripts-DDC2":
│  235:   provisioner "file" {

timeout - last error: unknown error Post "http://10.10.11.123:5985/wsman": dial tcp 10.10.11.123:5985: connectex: A connection attempt failed because the connected party did not properly respond
after a period of time, or established connection failed because connected host has failed to respond.


Error: remote-exec provisioner error

│   with null_resource.UploadAndExecuteChangeIPScript-DDC1,
│   on CVADOnXenServer-InitialConfiguration.tf line 399, in resource "null_resource" "UploadAndExecuteChangeIPScript-DDC1":
│  399:  provisioner "remote-exec" {

error executing "C:/Temp/terraform_808752596.cmd": unknown error Post "http://10.10.11.129:5985/wsman": net/http: timeout awaiting response headers


Error: remote-exec provisioner error

│   with null_resource.UploadAndExecuteChangeIPScript-CVADAVM,
│   on CVADOnXenServer-InitialConfiguration.tf line 455, in resource "null_resource" "UploadAndExecuteChangeIPScript-CVADAVM":
│  455:  provisioner "remote-exec" {

error executing "C:/Temp/terraform_2139075182.cmd": unknown error Post "http://10.10.11.130:5985/wsman": net/http: timeout awaiting response headers

PS D:\_PPMM\__TF\_CVADOnXenServer\_CVADOnXenServer-InitialConfiguration>

 

Important:

The errors shown above occur because Terraform changes the IP addresses of the VMs, and the provisioner can no longer connect to the previous IP address.
The provisioner runs in a timeout and produces these errors.
 


Looking into Server Manager on the VM after running the Terraform script shows the correct renaming of the VMs, the successful change of the IP address to the needed ones, and the successful registration in the Domain:
vm-configered.png

The Terraform flow was completed successfully.
The environment is now ready to install and configure Citrix Virtual Apps and Desktops and Citrix StoreFront.
 

Module 3: Installing and Configuring Citrix Virtual Apps and Desktops and Citrix StoreFront

 

In this Module, the following steps are done:

  • Creating the needed databases
  • Installing Citrix Virtual Apps and Desktops on the Delivery Controller VMs
  • Creating the Citrix Virtual Apps and Desktops site
  • Installing Citrix StoreFront on the Delivery Controller VMs
  • Configuring a Citrix StoreFront cluster on the primary Delivery Controller

After running Module 2, the VMs are prepared for Installation and Configuration of Citrix Virtual Apps and Desktops and Citrix StoreFront:
ddc-installerrunning.png

 

During the Installation process, the Installer also installs and configures StoreFront, but does not create a StoreFront cluster according to our needs: 

no-sf-farm.png

Because of that, the first script in Module 3 purges all existing StoreFront deployments on the 2 Delivery Controllers to have a clear environment for deploying the StoreFront cluster.

Important:

The current Citrix Terraform Provider version 1.0.1 has significant improvements built in. There is no need to run various scripts to create the needed entities and determine the required information, etc.
Compared to the previous versions, it dramatically simplifies the Terraform workflow.
 

Example of previous Terraform scripts needed to create and configure a StoreFront site:

 #### Create Storefront-Configuration script
  #### Need to invoke PowerShell as Domain User as the provisioner does not allow to be run in a Domain Users-context, but CVAD SDK needs to be run as a Domain User
  ConfigureStorefrontScriptcontent     = <<-EOT
  #$PSUsername = 'tacg\administrator'
#$PSPassword = 'XXXXXXXXXX'
#$PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
#$PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
#Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
Add-PSSnapin Citrix.*
 
#Clear-Existing StoreFront deployments
Clear-STFDeployment -Confirm:$false
Write-Output 'Existing Deployments deleted.'
 
#Add new StoreFront deployment
Add-STFDeployment -HostBaseUrl 'https://storefront.the-austrian-citrix-guy.at' -Confirm:$false
Write-Output 'New deployment created.'
 
#Add new Authentication Service
Add-STFAuthenticationService '/Citrix/Authentication'
$authentication = Get-STFAuthenticationService
Write-Output 'Authentication service created.'
 
Start-Sleep -Seconds 120
 
#Enable Access through a NetScaler Gateway
Enable-STFAuthenticationServiceProtocol -Name CitrixAGBasic -AuthenticationService ($authentication)
$protocols = Get-STFAuthenticationServiceProtocol -AuthenticationService ($authentication)
 
#Add NetScaler Gateway
Add-STFRoamingGateway -Name TACG-TF-NSGW -LogonType Domain -GatewayUrl 'https://ns.the-austrian-citrix-guy.at' -CallbackUrl 'https://ns.the-austrian-citrix-guy.at/CitrixAuthService/AuthService.asmx' -SessionReliability:$true -SecureTicketAuthorityUrls 'http://TACG-NTX-DDC1.the-austrian-citrix-guy.at/scripts/ctxsta.dll,http://TACG-NTX-DDC2.the-austrian-citrix-guy.at/scripts/ctxsta.dll' -IsCloudGateway:$false
Write-Output 'NSGW created.'
#Add Beacons for NetScaler Gateway
Set-STFRoamingBeacon -Internal 'http://TACG-NTX-DDC1.the-austrian-citrix-guy.at' -External https://ns.the-austrian-citrix-guy.at,https://news.orf.at
Write-Output 'Beacons created.'
 
#Add new Store Service
Add-STFStoreService -VirtualPath '/Citrix/Store' -AuthenticationService $authentication -FarmName 'TACG-SF' -FarmType 'XenDesktop' -Servers 'TACG-NTX-DDC1.the-austrian-citrix-guy.at' -FriendlyName 'TACG-SF' -TransportType HTTPS -Port 443
Write-Output 'Store service created.'
 
#Register NetScaler Gateway and Beacons
$store = Get-STFStoreService -VirtualPath '/Citrix/Store'
$gateway = Get-STFRoamingGateway -Name TACG-TF-NSGW
Register-STFStoreGateway -Gateway $gateway -StoreService $store -DefaultGateway -UseFullVpn:$false
Write-Output 'NSGW registered.'
 
#Enable WebReceiver
Add-STFWebReceiverService -VirtualPath '/Citrix/StoreWeb' -StoreService $store
$receiver = Get-STFWebReceiverService -VirtualPath '/Citrix/StoreWeb'
Write-Output 'Web Receiver site created.'
 
#Enable PNAGent site
Enable-STFStorePna -StoreService $store -AllowUserPasswordChange -DefaultPnaService
Write-Output 'PNA site created.'
 
#Enable HTML5Fallback
Set-STFWebReceiverPluginAssistant -WebReceiverService $receiver -Enabled $true -Html5Enabled "Fallback"
Write-Output 'HTML5 site created.'
Write-Output 'Storefront configuration complete.'
Write-Output 'Registering Storefront in CVAD Site configuration.'
 
$PSUsername = 'tacg\administrator'
$PSPassword = 'XXXXXXXXXX'
$PSSecurePassword = ConvertTo-SecureString $PSPassword -AsPlainText -Force
$PSCredential = New-Object System.Management.Automation.PSCredential ($PSUsername, $PSSecurePassword)
Invoke-Command -ComputerName localhost -Credential $PSCredential -ScriptBlock {
Add-PSSnapin Citrix.*
 
#Add StoreFront configuration to CVAD site
$configurationSlot = Get-BrokerConfigurationSlot -Name "RS"
$storefrontUrl = 'https://storefront.the-austrian-citrix-guy.at/Citrix/StoreWeb'
$configuration = New-BrokerStorefrontAddress -Description "Citrix Storefront Address" -Enabled $true -Name "Citrix StoreFront" -Url $storefrontUrl
New-BrokerMachineConfiguration -Policy $configuration -ConfigurationSlotUid $configurationSlot.Uid -Description "Citrix Storefront Address Configuration" -LeafName 'TACG-SF'
Write-Output 'Registration in CVAD Site complete.'
Write-Output 'Reboot needed...'
}
  EOT


The actual Terraform provider dramatically simplifies the process, and the code is much more structured:

resource "citrix_stf_deployment" "CreateSTFDeployment" {
  site_id                 = var.STF-SiteID
  host_base_url           = var.STF-BaseURL
}
 
resource "citrix_stf_authentication_service" "CreateSTFAuthenticationService" {
  depends_on          = [ citrix_stf_deployment.CreateSTFDeployment ]
  site_id                 = citrix_stf_deployment.CreateSTFDeployment.site_id
  friendly_name           = var.STF-Auth-FriendlyName
  virtual_path            = var.STF-Auth-VirtualPath
}
 
resource "citrix_stf_store_service" "CreateSTFStoreService" {
  depends_on        = [ citrix_stf_authentication_service.CreateSTFAuthenticationService ]
  site_id                             = citrix_stf_deployment.CreateSTFDeployment.site_id
  friendly_name                       = var.STF-Store-FriendlyName
  virtual_path                        = var.STF-Store-VirtualPath
  authentication_service_virtual_path = "${citrix_stf_authentication_service.CreateSTFAuthenticationService.virtual_path}"
 
  pna               = {
                          enable      = var.STF-EnablePNA
                      }
 
 farms             = [
               {
                          farm_name   = var.CVAD-SiteName
                          farm_type   = "XenDesktop"
                          servers     = var.STF-Farm-Servers
                          port        = var.STF-Port
               },
                      ]
}
 
resource "citrix_stf_webreceiver_service" "CreateSTFWebReceiverService"{
  depends_on          = [ citrix_stf_store_service.CreateSTFStoreService ]
  site_id             = citrix_stf_deployment.CreateSTFDeployment.site_id
  friendly_name       = var.STF-WebReceiver-FriendlyName
  virtual_path        = var.STF-WebReceiver-VirtualPath
  store_virtual_path  = "${citrix_stf_store_service.CreateSTFStoreService.virtual_path}"
}
 
resource "citrix_stf_roaming_beacon" "CreateSTFRoamingBeacon" {
  depends_on          = [ citrix_stf_store_service.CreateSTFStoreService ]
  internal_ip         = var.STF-BaseURL
  external_ips        = var.STF-External-Beacons
  site_id             = var.STF-SiteID
}
 
resource "citrix_stf_roaming_gateway" "CreateSTFRoamingGateway" {
  depends_on                     = [ citrix_stf_deployment.CreateSTFDeployment ]
  site_id                        = citrix_stf_deployment.CreateSTFDeployment.site_id
  name                           = var.STF-GW-Name
  logon_type                     = var.STF-GW-LogonType
  gateway_url                    = var.STF-GW-URL
  callback_url                   = var.STF-GW-CallbackURL
  version                        = var.STF-GW-Version
  subnet_ip_address              = var.STF-GW-SNIP
  stas_bypass_duration           = var.STF-GW-Bypass
  session_reliability            = var.STF-GW-SessionReliability
  request_ticket_two_stas        = var.STF-GW-Request2STAs
  stas_use_load_balancing        = var.STF-GW-UseSTALB
  is_cloud_gateway               = var.STF-GW-IsCloudGateway
  secure_ticket_authority_urls   = [
      {
      sta_url                    = var.STF-GW-STA1
      },
      {
      sta_url                    = var.STF-GW-STA2
      },
    ]
}
 
resource "citrix_stf_xenapp_default_store" "CreateSTFDefaultStore" {
  depends_on                     = [ citrix_stf_store_service.CreateSTFStoreService ]
  store_virtual_path             = citrix_stf_store_service.CreateSTFStoreService.virtual_path
  store_site_id                  = citrix_stf_store_service.CreateSTFStoreService.site_id
}

 

Important:

Before starting the Terraform workflow, please ensure you have configured the variables according to your needs using the corresponding .auto.tfvars.json and/or terraform.tfvars file.
 

The configuration can be started by following the standard Terraform workflow:

terraform init,
terraform plan
 

and if no errors occur

terraform apply

 

PS C:\_TACG\_CVADOnXenServer-InitialCVADConfiguration> terraform init
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/null...
- Finding latest version of hashicorp/time...
- Finding latest version of hashicorp/local...
- Finding citrix/citrix versions matching "1.0.1"...
- Finding latest version of xenserver/xenserver...
- Installing hashicorp/null v3.2.2...
- Installed hashicorp/null v3.2.2 (signed by HashiCorp)
- Installing hashicorp/time v0.12.0...
- Installed hashicorp/time v0.12.0 (signed by HashiCorp)
- Installing hashicorp/local v2.5.1...
- Installed hashicorp/local v2.5.1 (signed by HashiCorp)
- Installing citrix/citrix v1.0.1...
- Installed citrix/citrix v1.0.1 (self-signed, key ID BD4BD0E690CB7D88)
- Installing xenserver/xenserver v0.1.1...
- Installed xenserver/xenserver v0.1.1 (self-signed, key ID FABD99A0D7648275)
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\_CVADOnXenServer-InitialCVADConfiguration> terraform plan

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:

  # local_file.WriteCVADDBScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADDBScriptIntoDataDirectory" {
      + 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             = "./data/CVAD-DBs.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteCVADScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADScriptIntoDataDirectory" {
      + content              = <<-EOT
            if (!(Test-Path C:/TEMP/XDINST)){
                New-Item -Path 'C:/TEMP/XDINST' -ItemType Directory
            }
            D:/x64/"XenDesktop Setup"/XenDesktopServerSetup.exe /components controller,webstudio,licenseserver,desktopdirector /noreboot /configure_firewall /quiet /nosql /Logpath C:/TEMP/XDINST
            #Restart-Computer -Force
        EOT
      + 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             = "./data/CVAD-Install.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteCVADSiteScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADSiteScriptIntoDataDirectory" {
      + 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             = "./data/CVAD-Site.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteLicScriptIntoDataDirectory will be created
  + resource "local_file" "WriteLicScriptIntoDataDirectory" {
      + 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             = "./data/CVAD-CreateDNSARecordOnDC.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteRebootScriptIntoDataDirectory will be created
  + resource "local_file" "WriteRebootScriptIntoDataDirectory" {
      + content              = <<-EOT
            Restart-Computer -Force
        EOT
      + 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             = "./data/Reboot.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteSFScriptIntoDataDirectory will be created
  + resource "local_file" "WriteSFScriptIntoDataDirectory" {
      + content              = <<-EOT
            D:x64/StoreFront/CitrixStoreFront-x64.exe -silent
        EOT
      + 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             = "./data/SF-Install.ps1"
      + id                   = (known after apply)
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Plan: 25 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\_CVADOnXenServer-InitialCVADConfiguration> terraform validate
Success! The configuration is valid.

PS C:\_TACG\_CVADOnXenServer-InitialCVADConfiguration> terraform apply

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:

  # local_file.WriteCVADDBScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADDBScriptIntoDataDirectory" {
      + 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             = "./data/CVAD-DBs.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteCVADScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADScriptIntoDataDirectory" {
      + content              = <<-EOT
            if (!(Test-Path C:/TEMP/XDINST)){
                New-Item -Path 'C:/TEMP/XDINST' -ItemType Directory
            }
            D:/x64/"XenDesktop Setup"/XenDesktopServerSetup.exe /components controller,webstudio,licenseserver,desktopdirector /noreboot /configure_firewall /quiet /nosql /Logpath C:/TEMP/XDINST
            #Restart-Computer -Force
        EOT
      + 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             = "./data/CVAD-Install.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteCVADSiteScriptIntoDataDirectory will be created
  + resource "local_file" "WriteCVADSiteScriptIntoDataDirectory" {
      + 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             = "./data/CVAD-Site.ps1"
      + id                   = (known after apply)
    }

  # local_file.WriteLicScriptIntoDataDirectory will be created
  + resource "local_file" "WriteLicScriptIntoDataDirectory" {
      + content              = (sensitive value)
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)