green and yellow printed textile
AWS Terraform

Terraform Example of a Windows Instance using UserData

In this article, I’ve got two examples of using PowerShell in the user_Data. The first example shows using PowerShell code within the Terraform code, this is not the best way to go. The second example further down the page, shows an example of referring to a PowerShell file for the user_data:

resource "aws_key_pair" "example" {
  key_name   = "example_key"
  public_key = "REPLACE-WITH-YOUR-PUBLIC-KEY"
}

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  key_name      = aws_key_pair.example.key_name

  # Windows-specific settings
  user_data          = <<EOF
                        <powershell>
                          # Install IIS
                          Install-WindowsFeature -Name Web-Server -IncludeManagementTools

                          # Create a website
                          $SiteName = "MyWebsite"
                          $PhysicalPath = "C:\inetpub\${SiteName}"
                          New-Item -Path $PhysicalPath -ItemType Directory
                          New-Website -Name $SiteName -PhysicalPath $PhysicalPath -Port 80 -Force
                        </powershell>
                      EOF

  # Networking settings
  vpc_security_group_ids = [aws_security_group.example.id]
  subnet_id              = aws_subnet.example.id

  # Other settings
  tags = {
    Name = "example-instance"
  }
}

This example code launches an EC2 instance with the specified AMI and instance type, and associates it with a security group and subnet. The user_data field contains a PowerShell script that installs IIS and creates a website on the instance. The script is executed when the instance is launched, allowing for custom configuration during the instance bootstrap process.

Note that you’ll need to replace the AMI ID (ami-0c55b159cbfafe1f0 in this example) with the ID of the Windows AMI you want to use. You’ll also need to specify the ID of a security group and subnet in your VPC, and the name of your key pair.

Another way, instead of the PowerShell script being in the Terraform code, I’ve created a file called user_data.ps1 which contains the PowerShell code and I’m referring to it in Terraform.

data "template_file" "user_data" {
  template = file("${path.module}/user_data.ps1")
}
resource "aws_key_pair" "example" {
  key_name   = "example_key"
  public_key = "REPLACE-WITH-YOUR-PUBLIC-KEY"
}

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  key_name      = aws_key_pair_example.key_name

  # Windows-specific settings
  user_data          = data.template_file.user_data.rendered

  # Networking settings
  vpc_security_group_ids = [aws_security_group.example.id]
  subnet_id              = aws_subnet.example.id

  # Other settings
  tags = {
    Name = "example-instance"
  }
}

This code uses the template_file data source to read the contents of the user_data.ps1 file into a variable called data.template_file.user_data. The rendered attribute is used to obtain the rendered content of the file, which is then assigned to the user_data field of the aws_instance resource.

To use this code, create a file called user_data.ps1 in the same directory as your Terraform code, and put your PowerShell script in that file. For example:

# user_data.ps1

# Install IIS
Install-WindowsFeature -Name Web-Server -IncludeManagementTools

# Create a website
$SiteName = "MyWebsite"
$PhysicalPath = "C:\inetpub\${SiteName}"
New-Item -Path $PhysicalPath -ItemType Directory
New-Website -Name $SiteName -PhysicalPath $PhysicalPath -Port 80 -Force

When you run terraform apply, Terraform will read the PowerShell script from the user_data.ps1 file and pass it to the instance as user_data during launch.

Hope this helps!