Introduction to Terraform on Windows Server 2022

Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp that allows you to define, provision, and manage cloud and on-premises infrastructure using a declarative configuration language called HCL (HashiCorp Configuration Language). Running Terraform on Windows Server 2022 is fully supported and is common in enterprise environments where Windows-based CI/CD pipelines, Jenkins agents, or GitHub Actions self-hosted runners operate on Server 2022. This guide walks through installing Terraform, configuring PATH, understanding the core workflow, and working with the most common cloud providers from a Windows Server 2022 host.

Downloading the Terraform Binary for Windows

Terraform for Windows is distributed as a single ZIP file containing a single executable, terraform.exe. There is no installer — you extract the binary and place it somewhere on your system PATH. Visit the official Terraform releases page at https://releases.hashicorp.com/terraform/ and download the latest Windows AMD64 ZIP. As of Terraform 1.8, this is typically named something like terraform_1.8.x_windows_amd64.zip.

You can download it directly from PowerShell without using a browser:

$version = "1.8.5"
$url = "https://releases.hashicorp.com/terraform/$version/terraform_${version}_windows_amd64.zip"
Invoke-WebRequest -Uri $url -OutFile "C:Toolsterraform_${version}_windows_amd64.zip"

Once downloaded, extract the ZIP:

Expand-Archive -Path "C:Toolsterraform_${version}_windows_amd64.zip" -DestinationPath "C:ToolsTerraform"

This places terraform.exe into C:ToolsTerraform.

Adding Terraform to the System PATH

To run terraform from any directory in Command Prompt or PowerShell, you must add its location to the system-wide PATH environment variable. You can do this via the GUI (System Properties > Environment Variables) or through PowerShell with administrative privileges:

$currentPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine)
$newPath = $currentPath + ";C:ToolsTerraform"
[Environment]::SetEnvironmentVariable("Path", $newPath, [EnvironmentVariableTarget]::Machine)

Close and reopen your terminal, then verify the installation:

terraform version

You should see output similar to:

Terraform v1.8.5
on windows_amd64

Installing Terraform via Chocolatey

If your organization uses Chocolatey (the Windows package manager), installing and updating Terraform becomes much simpler. First ensure Chocolatey is installed, then run:

choco install terraform -y

Upgrading to the latest version later is equally straightforward:

choco upgrade terraform -y

Chocolatey manages the PATH entry automatically, so no manual steps are required after install.

The Core Terraform Workflow

Terraform operates on a three-phase workflow: write, plan, apply. You write configuration in .tf files, run terraform plan to see what changes Terraform will make, and then run terraform apply to execute those changes. The workflow always begins with terraform init, which downloads provider plugins and initializes the working directory.

Create a new working directory for your project and navigate to it:

mkdir C:Projectsmy-infra
cd C:Projectsmy-infra

Create a minimal main.tf file in that directory. For testing the workflow, you can use the null provider:

terraform {
  required_providers {
    null = {
      source  = "hashicorp/null"
      version = "~> 3.0"
    }
  }
}

resource "null_resource" "example" {
  triggers = {
    always_run = "${timestamp()}"
  }
}

Running terraform init

terraform init is always the first command you run in a new or cloned Terraform project directory. It downloads the provider plugins specified in your configuration, sets up the backend for state storage, and initializes modules. On Windows Server 2022, providers are downloaded into a .terraformproviders subdirectory of your working directory by default.

cd C:Projectsmy-infra
terraform init

Expected output:

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/null versions matching "~> 3.0"...
- Installing hashicorp/null v3.2.2...
- Installed hashicorp/null v3.2.2 (signed by HashiCorp)

Terraform has been successfully initialized!

Running terraform plan

terraform plan compares your configuration to the current state and produces an execution plan. It does not make any real changes. It is safe to run at any time and is a critical review step before applying changes. On Windows Server 2022, the output is the same as on Linux; Terraform renders it in the terminal:

terraform plan

You can also save the plan to a file for use in automated pipelines:

terraform plan -out=tfplan.binary

Running terraform apply and terraform destroy

terraform apply executes the changes described in the plan. When run interactively, it shows the plan and prompts for confirmation. To skip the interactive prompt in automated pipelines, pass the -auto-approve flag:

terraform apply -auto-approve

To apply a previously saved plan file (bypassing the new plan generation and prompt):

terraform apply tfplan.binary

To tear down all resources managed by a configuration, use terraform destroy:

terraform destroy -auto-approve

Configuring the Azure Provider (azurerm)

To manage Azure resources with Terraform from Windows Server 2022, you use the azurerm provider. Declare it in your main.tf:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.100"
    }
  }
}

provider "azurerm" {
  features {}
}

Authentication to Azure can be handled via Service Principal environment variables. Set these before running Terraform commands:

$env:ARM_CLIENT_ID     = "your-service-principal-app-id"
$env:ARM_CLIENT_SECRET = "your-service-principal-password"
$env:ARM_TENANT_ID     = "your-azure-tenant-id"
$env:ARM_SUBSCRIPTION_ID = "your-azure-subscription-id"

Alternatively, if the Azure CLI is installed on the Server 2022 host and you have logged in with az login, the azurerm provider can pick up credentials automatically without environment variables.

Configuring the AWS Provider

For AWS, declare the aws provider and supply credentials via environment variables (the recommended approach for server environments):

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

Set credentials as environment variables in PowerShell before running Terraform:

$env:AWS_ACCESS_KEY_ID     = "AKIAIOSFODNN7EXAMPLE"
$env:AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
$env:AWS_DEFAULT_REGION    = "us-east-1"

Windows-Specific Considerations: Paths and CRLF

When writing Terraform configurations on Windows, keep these considerations in mind. File paths in HCL use forward slashes even on Windows, or escaped backslashes. Prefer forward slashes for portability:

# Correct on all platforms including Windows
source = "C:/scripts/bootstrap.sh"

# Also works on Windows
source = "C:\scripts\bootstrap.sh"

Line endings (CRLF vs LF) can cause issues with templatefile() and heredoc strings if scripts are rendered and pushed to Linux targets. If your project is managed with Git on Windows, configure your .gitattributes to enforce LF line endings for .tf and .sh files:

*.tf   text eol=lf
*.sh   text eol=lf

Terraform State on Windows

Terraform tracks the state of managed infrastructure in a file called terraform.tfstate. By default, this is created in the local working directory. On Windows Server 2022, this file is created with standard Windows file permissions. The state file contains sensitive information (including resource IDs, IPs, and potentially secrets), so it must never be committed to source control.

Add the following to your .gitignore:

terraform.tfstate
terraform.tfstate.backup
.terraform/
*.tfplan
*.binary

Backend Configuration: Remote State with Azure Blob Storage

For team environments, store Terraform state in a remote backend. The Azure Blob Storage backend is a natural choice when working in Azure environments from Windows Server 2022:

terraform {
  backend "azurerm" {
    resource_group_name  = "rg-terraform-state"
    storage_account_name = "tfstatestorage01"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
  }
}

For AWS S3 backend:

terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-lock"
    encrypt        = true
  }
}

After adding or changing a backend configuration, run terraform init -reconfigure to migrate state to the new backend:

terraform init -reconfigure

Environment Variables for Credentials

Avoid hardcoding credentials in .tf files. Always use environment variables or a secrets manager. To set persistent environment variables for a service account on Windows Server 2022 (for a CI/CD agent account, for example), use the [Environment]::SetEnvironmentVariable method with the User or Machine target:

# Set for the current user persistently
[Environment]::SetEnvironmentVariable("ARM_CLIENT_ID", "your-app-id", [EnvironmentVariableTarget]::User)
[Environment]::SetEnvironmentVariable("ARM_CLIENT_SECRET", "your-secret", [EnvironmentVariableTarget]::User)

Alternatively, for Windows services and Jenkins agents, configure environment variables in the service account’s user profile, or inject them at pipeline runtime using your CI/CD system’s secrets management.

Summary

Terraform on Windows Server 2022 is a first-class experience. The single binary deployment model makes installation straightforward — download, extract, add to PATH, and you are ready to go. Chocolatey provides an even simpler managed installation path. The core workflow of init, plan, apply, and destroy is identical across all platforms. Remote backends for state storage, environment variable-based credential management, and careful attention to Windows-specific path and line ending conventions ensure that Terraform-based infrastructure management from Windows Server 2022 is reliable, secure, and enterprise-ready.