diff --git a/generator/test_case_generator.go b/generator/test_case_generator.go
index 655d1c8ee..5518f19d9 100644
--- a/generator/test_case_generator.go
+++ b/generator/test_case_generator.go
@@ -122,6 +122,10 @@ var testTypeToTestConfig = map[string][]testConfig{
 		{testDir: "../../../test/restart"},
 		{testDir: "../../../test/acceptance"},
 		{testDir: "../../../test/feature/windows/event_logs"},
+		{
+			testDir: "../../../test/feature/windows/userdata",
+			targets: map[string]map[string]struct{}{"os": {"win-2019": {}}},
+		},
 		// assume role test doesn't add much value, and it already being tested with linux
 		//{testDir: "../../../test/assume_role"},
 	},
diff --git a/terraform/ec2/win/install_and_start_agent.tpl b/terraform/ec2/win/install_and_start_agent.tpl
new file mode 100644
index 000000000..4e48a35bf
--- /dev/null
+++ b/terraform/ec2/win/install_and_start_agent.tpl
@@ -0,0 +1,22 @@
+<powershell>
+$installDirectory = "c:\temp\cw"
+$downloadDirectory = $installDirectory
+$logsDirectory = $installDirectory
+$cwAgentInstaller = "$downloadDirectory\amazon-cloudwatch-agent.msi"
+$cwAgentInstallPath = "C:\\Program Files\\Amazon\\AmazonCloudWatchAgent"
+
+New-Item -ItemType "directory" -Path $installDirectory
+
+Set-Location -Path $installDirectory
+
+Write-host "Installing Cloudwatch Agent"
+Install-PackageProvider NuGet -Force;
+Set-PSRepository PSGallery -InstallationPolicy Trusted
+Install-Module -Name AWS.Tools.EC2,AWS.Tools.S3 -AllowClobber
+${copy_object}
+Start-Process -FilePath msiexec -Args "/i $cwAgentInstaller /l*v $logsDirectory\installCWAgentLog.log /qn" -Verb RunAs -Wait
+
+Write-host "Load config"
+
+& "$cwAgentInstallPath\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c ssm:${agent_json_config}
+</powershell>
\ No newline at end of file
diff --git a/terraform/ec2/win/main.tf b/terraform/ec2/win/main.tf
index 3de3828c7..1be57d63d 100644
--- a/terraform/ec2/win/main.tf
+++ b/terraform/ec2/win/main.tf
@@ -62,6 +62,7 @@ resource "aws_instance" "cwagent" {
   vpc_security_group_ids               = [module.basic_components.security_group]
   associate_public_ip_address          = true
   instance_initiated_shutdown_behavior = "terminate"
+  user_data                            = length(regexall("/feature/windows/userdata", var.test_dir)) > 0 ? data.template_file.user_data.rendered : ""
   get_password_data                    = true
 
   metadata_options {
@@ -72,18 +73,20 @@ resource "aws_instance" "cwagent" {
   tags = {
     Name = "cwagent-integ-test-ec2-windows-${var.test_name}-${module.common.testing_id}"
   }
+  depends_on = [aws_ssm_parameter.upload_ssm]
 }
 
 # Size of windows json is too large thus can't use standard tier
 resource "aws_ssm_parameter" "upload_ssm" {
-  count = var.use_ssm == true && length(regexall("/feature/windows", var.test_dir)) > 0 ? 1 : 0
+  count = length(regexall("/feature/windows", var.test_dir)) > 0 ? 1 : 0
   name  = local.ssm_parameter_name
   type  = "String"
   tier  = "Advanced"
   value = file(module.validator.agent_config)
 }
 
-resource "null_resource" "integration_test_setup" {
+resource "null_resource" "integration_test_setup_agent" {
+  count = length(regexall("/feature/windows/userdata", var.test_dir)) > 0 ? 0 : 1
   depends_on = [aws_instance.cwagent, module.validator, aws_ssm_parameter.upload_ssm]
 
   # Install software
@@ -99,6 +102,24 @@ resource "null_resource" "integration_test_setup" {
     inline = [
       "aws s3 cp s3://${var.s3_bucket}/integration-test/packaging/${var.cwa_github_sha}/amazon-cloudwatch-agent.msi .",
       "start /wait msiexec /i amazon-cloudwatch-agent.msi /norestart /qb-",
+    ]
+  }
+}
+
+resource "null_resource" "integration_test_setup_validator" {
+  depends_on = [aws_instance.cwagent, module.validator, aws_ssm_parameter.upload_ssm]
+
+  # Install software
+  connection {
+    type     = "winrm"
+    user     = "Administrator"
+    password = rsadecrypt(aws_instance.cwagent.password_data, local.private_key_content)
+    host     = aws_instance.cwagent.public_dns
+  }
+
+  # Install agent binaries
+  provisioner "remote-exec" {
+    inline = [
       "aws s3 cp s3://${var.s3_bucket}/integration-test/validator/${var.cwa_github_sha}/windows/${var.arc}/validator.exe .",
     ]
   }
@@ -123,7 +144,8 @@ resource "null_resource" "integration_test_reboot" {
   }
 
   depends_on = [
-    null_resource.integration_test_setup,
+    null_resource.integration_test_setup_agent,
+    null_resource.integration_test_setup_validator,
   ]
 }
 
@@ -144,7 +166,8 @@ resource "null_resource" "integration_test_run" {
   # run go test when it's not feature test
   count = length(regexall("/feature/windows", var.test_dir)) < 1 ? 1 : 0
   depends_on = [
-    null_resource.integration_test_setup,
+    null_resource.integration_test_setup_agent,
+    null_resource.integration_test_setup_agent,
     null_resource.integration_test_wait,
   ]
 
@@ -170,9 +193,10 @@ resource "null_resource" "integration_test_run" {
 
 resource "null_resource" "integration_test_run_validator" {
   # run validator only when test_dir is not passed e.g. the default from variable.tf
-  count = length(regexall("/feature/windows", var.test_dir)) > 0 ? 1 : 0
+  count = length(regexall("/feature/windows", var.test_dir)) > 0 && length(regexall("/feature/windows/userdata", var.test_dir)) < 1 ? 1 : 0
   depends_on = [
-    null_resource.integration_test_setup,
+    null_resource.integration_test_setup_agent,
+    null_resource.integration_test_setup_validator,
     null_resource.integration_test_wait,
   ]
 
@@ -213,6 +237,42 @@ resource "null_resource" "integration_test_run_validator" {
   }
 }
 
+resource "null_resource" "integration_test_run_validator_userdata" {
+  # run validator only when test_dir is not passed e.g. the default from variable.tf
+  count = length(regexall("/feature/windows/userdata", var.test_dir)) > 0 ? 1 : 0
+  depends_on = [
+    null_resource.integration_test_setup_validator,
+    null_resource.integration_test_wait,
+  ]
+
+  connection {
+    type     = "winrm"
+    user     = "Administrator"
+    password = rsadecrypt(aws_instance.cwagent.password_data, local.private_key_content)
+    host     = aws_instance.cwagent.public_dns
+  }
+
+  provisioner "file" {
+    source      = module.validator.agent_config
+    destination = module.validator.instance_agent_config
+  }
+
+  provisioner "file" {
+    source      = module.validator.validator_config
+    destination = module.validator.instance_validator_config
+  }
+
+  //runs validator and sets up prometheus java agent
+  provisioner "remote-exec" {
+    inline = [
+      "set AWS_REGION=${var.region}",
+      "validator.exe --validator-config=${module.validator.instance_validator_config} --preparation-mode=true",
+      "powershell.exe \"& \"C:ProgramFiles\\Amazon\\AmazonCloudWatchAgent\\amazon-cloudwatch-agent-ctl.ps1\" -m ec2 -a status\"",
+      "validator.exe --validator-config=${module.validator.instance_validator_config} --preparation-mode=false"
+    ]
+  }
+}
+
 data "aws_ami" "latest" {
   most_recent = true
 
@@ -221,3 +281,19 @@ data "aws_ami" "latest" {
     values = [var.ami]
   }
 }
+
+#####################################################################
+# Generate template file for EC2 userdata script
+#####################################################################
+data "template_file" "user_data" {
+  template = file("install_and_start_agent.tpl")
+
+  vars = {
+    copy_object = "Copy-S3Object -BucketName ${var.s3_bucket} -Key integration-test/packaging/${var.cwa_github_sha}/amazon-cloudwatch-agent.msi -region ${var.region} -LocalFile $cwAgentInstaller"
+    agent_json_config = local.ssm_parameter_name
+  }
+}
+
+output "userdata" {
+  value = data.template_file.user_data.rendered
+}
diff --git a/terraform/ec2/win/sample_userdata.ps1 b/terraform/ec2/win/sample_userdata.ps1
new file mode 100644
index 000000000..28d321ea0
--- /dev/null
+++ b/terraform/ec2/win/sample_userdata.ps1
@@ -0,0 +1,22 @@
+<powershell>
+$installDirectory = "c:\temp\cw"
+$downloadDirectory = $installDirectory
+$logsDirectory = $installDirectory
+$cwAgentInstallPath = "C:\Program Files\Amazon\AmazonCloudWatchAgent"
+
+New-Item -ItemType "directory" -Path $installDirectory
+
+Set-Location -Path $installDirectory
+
+Write-host "Installing Cloudwatch Agent"
+$cwAgentInstaller = "$downloadDirectory\amazon-cloudwatch-agent.msi"
+Install-PackageProvider NuGet -Force;
+Set-PSRepository PSGallery -InstallationPolicy Trusted
+Install-Module -Name AWS.Tools.EC2,AWS.Tools.S3 -AllowClobber
+Copy-S3Object -BucketName cloudwatch-agent-integration-bucket -Key integration-test/packaging/66717c80cbb533b260b45de6694120f3450c67be/amazon-cloudwatch-agent.msi -region us-west-2 -LocalFile $cwAgentInstaller
+Start-Process -FilePath msiexec -Args "/i $cwAgentInstaller /l*v $logsDirectory\installCWAgentLog.log /qn" -Verb RunAs -Wait
+
+Write-host "Load config"
+
+& "$cwAgentInstallPath\amazon-cloudwatch-agent-ctl.ps1" -a fetch-config -m ec2 -s -c ssm:WindowsAgentConfigSSMTest
+</powershell>
\ No newline at end of file
diff --git a/test/feature/windows/userdata/agent_config.json b/test/feature/windows/userdata/agent_config.json
new file mode 100644
index 000000000..154989e58
--- /dev/null
+++ b/test/feature/windows/userdata/agent_config.json
@@ -0,0 +1,216 @@
+{
+  "agent": {
+    "debug": true
+  },
+  "metrics": {
+    "namespace": "CloudWatchAgentWinFeature",
+    "metrics_collected": {
+      "Processor": {
+        "measurement": [
+          {
+            "name":"% Idle Time",
+            "rename": "Idle_Time"
+          },
+          {
+            "name":"% Interrupt Time",
+            "rename": "Interrupt_Time"
+          },
+          {
+            "name":"% User Time",
+            "rename": "User_Time"
+          },
+          {
+            "name":"% Processor Time",
+            "rename": "Processor_Time"
+          }
+        ],
+        "resources": [
+          "*"
+        ],
+        "metrics_collection_interval": 1
+      },
+      "LogicalDisk": {
+        "measurement": [
+          {
+            "name":"% Free Space",
+            "rename":"Free_Space"
+          }
+        ],
+        "resources": [
+          "*"
+        ],
+        "metrics_collection_interval": 1
+      },
+      "PhysicalDisk": {
+        "measurement": [
+          {
+            "name":"% Disk Time",
+            "rename": "Disk_Time"
+          },
+          {
+            "name":"Disk Write Bytes/sec",
+            "rename": "Write_Bytes_Per_Sec"
+          },
+          {
+            "name":"Disk Read Bytes/sec",
+            "rename": "Read_Bytes_Per_Sec"
+          },
+          {
+            "name":"Disk Writes/sec",
+            "rename": "Write_Per_Sec"
+          },
+          {
+            "name":"Disk Reads/sec",
+            "rename": "Disk_Read_Per_Sec"
+          }
+        ],
+        "resources": [
+          "*"
+        ],
+        "metrics_collection_interval": 1
+      },
+      "Network Interface": {
+        "measurement": [
+          {
+            "name":"Bytes Sent/sec",
+            "rename": "Bytes_Sent_Per_Sec"
+          },
+          {
+            "name":"Bytes Received/sec",
+            "rename": "Bytes_Received_Per_Sec"
+          },
+          {
+            "name":"Packets Sent/sec",
+            "rename": "Packets_Sent_Per_Sec"
+          },
+          {
+            "name":"Packets Received/sec",
+            "rename": "Packets_Received_Per_Sec"
+          }
+        ],
+        "resources": [
+          "*"
+        ],
+        "metrics_collection_interval": 1
+      },
+      "Memory": {
+        "measurement": [
+          {
+            "name": "Available Bytes",
+            "rename": "Available_Bytes"
+          },
+          {
+            "name":"Cache Faults/sec",
+            "rename": "Cache_Faults_Per_Sec"
+          },
+          {
+            "name":"Page Faults/sec",
+            "rename": "Page_Faults_Per_sec"
+          },
+          {
+            "name":"Pages/sec",
+            "rename":"Page_Per_Sec"
+          }
+        ],
+        "metrics_collection_interval": 1
+      },
+      "System": {
+        "measurement": [
+          {
+            "name": "Processor Queue Length",
+            "rename": "Processor_Queue_Length"
+          }
+        ],
+        "metrics_collection_interval": 1
+      },
+      "TCPv4": {
+        "measurement": [
+          {
+            "name": "Connections Established",
+            "rename": "Connections_Established"
+          }
+        ],
+        "metrics_collection_interval": 1
+      },
+      "TCPv6": {
+        "measurement": [
+          {
+            "name": "Connections Established",
+            "rename": "Connections_Established"
+          }
+        ],
+        "metrics_collection_interval": 1
+      },
+      "procstat": [
+        {
+          "exe": "amazon-cloudwatch-agent",
+          "measurement": [
+            "cpu_usage",
+            "memory_rss"
+          ],
+          "metrics_collection_interval": 1
+        }
+      ]
+    },
+    "append_dimensions": {
+      "InstanceId": "${aws:InstanceId}"
+    },
+    "force_flush_interval": 30
+  },
+  "logs": {
+    "logs_collected": {
+      "windows_events": {
+        "collect_list": [
+          {
+            "event_name": "Security",
+            "event_levels": [
+              "INFORMATION",
+              "WARNING",
+              "ERROR",
+              "CRITICAL",
+              "VERBOSE"
+            ],
+            "log_group_name": "{instance_id}",
+            "log_stream_name": "SecurityEvent"
+          },
+          {
+            "event_name": "System",
+            "event_levels": [
+              "INFORMATION",
+              "WARNING",
+              "ERROR",
+              "CRITICAL",
+              "VERBOSE"
+            ],
+            "log_group_name": "{instance_id}",
+            "log_stream_name": "System"
+          },
+          {
+            "event_name": "Application",
+            "event_levels": [
+              "INFORMATION",
+              "WARNING",
+              "ERROR",
+              "CRITICAL",
+              "VERBOSE"
+            ],
+            "log_group_name": "{instance_id}",
+            "log_stream_name": "Application"
+          }
+        ]
+      },
+
+      "files": {
+        "collect_list": [
+          {
+            "file_path": "C:/Users/Administrator/AppData/Local/Temp/test1.log",
+            "log_group_name": "{instance_id}",
+            "log_stream_name": "test1.log",
+            "timezone": "UTC"
+          }
+        ]
+      }
+    },
+    "force_flush_interval": 5
+  }
+}
diff --git a/test/feature/windows/userdata/parameters.yml b/test/feature/windows/userdata/parameters.yml
new file mode 100644
index 000000000..4331804a2
--- /dev/null
+++ b/test/feature/windows/userdata/parameters.yml
@@ -0,0 +1,157 @@
+# Receivers that agent needs to tests
+receivers: ["system"]
+
+#Test case name
+test_case: "win_feature_userdata"
+validate_type: "feature"
+# Only support metrics/traces/logs, even in this case we validate more than logs,
+# we only make this data_type as a placeholder
+data_type: "metrics"
+
+# Number of metrics to be sent or number of log lines being written  each minute
+values_per_minute: "2"
+# Number of seconds the agent should run and collect the metrics. In this case, 1 minutes
+agent_collection_period: 60 
+
+cloudwatch_agent_config: "<cloudwatch_agent_config>"
+
+# Metric that the test needs to validate; moreover, the stress validation already has
+# InstanceID dimension; therefore, does not need to validate it
+# https://github.com/aws/amazon-cloudwatch-agent-test/pull/109/files#diff-47c87373e751dd9fd5ce504e44b320765c8b84d6cde524a4e8a32cfa34674165R124-R135
+metric_namespace: "CloudWatchAgentWinFeature"
+metric_validation:
+  # Validate Memory metrics
+  - metric_name: "Available_Bytes"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Memory"
+  - metric_name: "Cache_Faults_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Memory"
+  - metric_name: "Page_Faults_Per_sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Memory"
+  - metric_name: "Page_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Memory"
+# Validations for Logical Disks
+  - metric_name: "Free_Space"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "LogicalDisk"
+      - name: "instance"
+        value: "C:"
+# Validations for Physical Disks
+  - metric_name: "Disk_Time"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "PhysicalDisk"
+      - name: "instance"
+        value: "0 C:"
+  - metric_name: "Write_Bytes_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "PhysicalDisk"
+      - name: "instance"
+        value: "0 C:"
+  - metric_name: "Read_Bytes_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "PhysicalDisk"
+      - name: "instance"
+        value: "0 C:"
+  - metric_name: "Write_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "PhysicalDisk"
+      - name: "instance"
+        value: "0 C:"
+  - metric_name: "Disk_Read_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "PhysicalDisk"
+      - name: "instance"
+        value: "0 C:"
+
+# Validations for Processor
+  - metric_name: "Idle_Time"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Processor"
+      - name: "instance"
+        value: "0"
+  - metric_name: "Interrupt_Time"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Processor"
+      - name: "instance"
+        value: "0"
+  - metric_name: "User_Time"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Processor"
+      - name: "instance"
+        value: "0"
+  - metric_name: "Processor_Time"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Processor"
+      - name: "instance"
+        value: "0"
+# Validations for Network Interface 
+  - metric_name: "Bytes_Sent_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Network Interface"
+      - name: "instance"
+        value: "Amazon Elastic Network Adapter"
+  - metric_name: "Bytes_Received_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Network Interface"
+      - name: "instance"
+        value: "Amazon Elastic Network Adapter"
+  - metric_name: "Packets_Sent_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Network Interface"
+      - name: "instance"
+        value: "Amazon Elastic Network Adapter"
+  - metric_name: "Packets_Received_Per_Sec"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "Network Interface"
+      - name: "instance"
+        value: "Amazon Elastic Network Adapter"
+# Validations for TCPv4 and TCPv6
+  - metric_name: "Connections_Established"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "TCPv4"
+  - metric_name: "Connections_Established"
+    metric_sample_count: 60
+    metric_dimension: 
+      - name: "objectname"
+        value: "TCPv6"