The Virtual Machine (VM) remains one of the most common resources in cloud environments. On AWS, if users want to deploy a Virtual Machine, the service to look at is called EC2 (short for Elastic Compute Cloud). In this article, we will deploy an AWS EC2 instance running Windows Server 2016.
Latest posts by David O´Brien (see all)


For this deployment to work, the following prerequisites must be met:

  • AWS PowerShell module installed
  • AWS VPC and Subnets created
    • See previous article in this series about VPC creation
    • Get the VpcId for the VPC into which you want to deploy the EC2
    • Get the Subnet ID for the private subnet in your VPC

Once you have these in place, we can get started.

Deploying an EC2 into a private subnet

We will be deploying this new VM into a private subnet, which means the VM will not have a public IP. As a best practice, VMs should be deployed into a private subnet without a public IP attached to its network interface card (ENI [Elastic Network Interface]). The resources we are going to deploy will all support the EC2 instance and secure access to it.

  • EC2 key pair
    • Required to decrypt the encrypted Windows administrator password
  • Elastic IP (public IP address)
  • EC2 instance
  • Security group (virtual firewall rule)

Creating an AWS EC2 Key Pair

AWS EC2 key pairs are required to access EC2 instances. AWS users either use an EC2 key pair to connect to Linux instances via SSH or to decrypt the automatically generated Windows administrator password. On instantiation of a Windows EC2 instance, the operating system creates a randomly generated password for the local administrator user, encrypts it, and reports it to the AWS console.

To create the key pair, run the following:

$keyPair = New-EC2KeyPair -KeyName ec2keypair
# Write the Key Pair to a local file
$keyPair.KeyMaterial | Set-Content -Path ./ec2-keypair.pem -Force

Creating an AWS Security Group

Every EC2 must also be attached to an AWS security group. Think of a security group as a virtual firewall rule attached directly to the instance. This is in addition to the operating system's firewall. A security group functions externally to the operating system. Security groups filter traffic based on source or destination IP and port.

$vpcId = Read-Host -Prompt "Enter Vpc Id"
$securityGroup = New-EC2SecurityGroup -GroupName "allow RDP inbound" -VpcId $vpcId -Description "This Security Group allows traffic inbound to port 3389."

We also need to create rules that allow ingress/egress communication and attach the rules to that security group. Remember, only allowing communication through the OS's firewall is not enough.

$ingress = @{ IpProtocol="tcp"; FromPort="3389"; ToPort="3389"; IpRanges="" }
Grant-EC2SecurityGroupIngress -GroupId $securityGroup -IpPermission @( $ingress )

If you followed the VPC deployment article mentioned above, then this rule will allow all resources in your VPC's private subnet to communicate with this EC2 resource on port 3389 (RDP).

Note: The EC2 we are deploying will be in the private subnet. This means even if you added an IP range of to the security group, communication would not work since the EC2 is not routable from outside the VPC.

If you want to enable communication to EC2 resources in private subnets, read up on topics such as “Bastion Hosts” and “AWS Systems Manager Port Forwarding.”

Creating an AWS EC2 Instance

The EC2 will be deployed in the VPC and subnet mentioned in the prerequisites. This has a few sub-steps that we need to execute.

$amiId = (Get-EC2ImageByName -Name WINDOWS_2016_BASE | Sort-Object CreationDate -Descending | Select-Object -First 1).ImageId

This will get us the AMI ID of the latest Windows Server 2016 base AMI available in the AWS marketplace for our region. AMI IDs are region-specific, so if you are deploying resources into multiple regions, you will need to get an AMI ID in each region.

$subnetId = Read-Host -Prompt "Enter subnet Id"
$instance = New-EC2Instance -ImageId $amiId -InstanceType t3a.medium -SubnetId $subnetId -KeyName ec2keypair -AssociatePublicIp $false -SecurityGroupId $securityGroup
Creating an AWS EC2

Creating an AWS EC2

A Windows deployment typically takes a couple of minutes to complete. You can either watch the progress in the AWS console or use PowerShell to poll the status from the AWS API.

Get-EC2Instance -InstanceId $instance.Instances.InstanceId

Once the status changes to Running, the instance is ready to accept connections. To connect to the instance, we require the password for the automatically created Administrator user. As mentioned before, we can decrypt the password using the EC2 key pair.

Subscribe to 4sysops newsletter!

$password = Get-EC2PasswordData -InstanceId $instance.Instances.InstanceId -Decrypt -PemFile ./ec2-keypair.pem

With this password and if we had network connectivity to the instance, we would be able to RDP into our new Windows instance.


Leave a reply

Your email address will not be published. Required fields are marked *


© 4sysops 2006 - 2023


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account