Starting EC2 instances by tag & EC2 Filters
May 2019
Overview
I had previously written about shutting down Azure VMs with a PowerShell script using Azure Automation runbook and recently needed to fix a broken script at work that started certain EC2 instances. The broken script was storing all of the EC2 instances in a variable then filtering by tag, but when I rewrote the script I used the Format parameter of the Get-EC2Instance Cmdlet which filters the objects on the AWS side and testing on the dev account showed a large performance gain and also easier to read and understand. Below the script are a few helpful filters for EC2 Instances, Volumes and Snapshots.
All examples run on PowerShell Core installed on a Mac with the AWSPowerShell Core module:
PSVersion 6.1.1
PSEdition Core
OS Darwin 18.5.0
Platform Unix
AWSLambdaPSCore 1.2.0.0
AWSPowerShell.NetCore 3.3.485.0
Daily On script
The script has one parameter, the AWS region (set to eu-west-1 as the default as this is where the majority of the instances are).
Instances the are required to start up in the morning are tagged with the key pair: DailyOn = True.
Using the AWS filter to get instances with the specified tags, instances are added to the ec2List variable. The instances in the list are iterated over and any that are not in the state of running are started. Instances that are already running are written to the output (it’s currently run in TeamCity and the output appears in the ‘build’ log). That’s it, nice and simple and wouldn’t take much changing to shutdown instances too (it could shutdown all instances except those with a LeaveOn = True tag).
Using AWS EC2 Filters
As I wrote this script, I took a look again at the EC2 filter parameter.
The filter can be defined in two ways, as Filter object type or supplied directly to the parameter as hashtable or array of hashtables.
Filter Name and Value values are case sensitive!!
EC2 Filter Object
$filter = New-Object -TypeName Amazon.EC2.Model.Filter
$filter.Name = 'virtualization-type'
$filter.Value = 'hvm'
(Get-EC2Instance -Filter $filter).count
Hashtable filter
(Get-EC2Instance -Filter @{name = 'virtualization-type'; values = 'hvm' }).count
Array of Hashtables = multiple filter
# Multiple filters
(Get-EC2Instance -Filter @(@{name = 'availability-zone'; values = 'eu-west-1b' } ; @{name ='tag:DailyOn'; values = 'True'})).count
Examples of filters
EC2 Instances
Get instance by name tag value
Get-EC2Instance -Filter @{name = 'tag:Name'; values = 'AWS-Matt-Test'}
Count number of instances in each AZ
(Get-EC2Instance -Filter @{name = 'availability-zone'; values = 'eu-west-1a' }).count
Search by key
(Get-EC2Instance -Filter @{name ='tag-key'; values = 'LeaveOn'}).count
Wildcard search
(Get-EC2Instance -Filter @{name ='reason'; values = 'User*'}).count
(Get-EC2Instance -Filter @{name ='reason'; values = '*ser*'}).count
Search for a key with no value
(Get-EC2Instance -Filter @{name ='reason'; values = ''}).count
Platform type
(Get-EC2Instance -Filter @{name ='platform'; values = 'windows'}).count
Instance type
(Get-EC2Instance -Filter @{name ='instance-type'; values = 't2.medium'}).count
(Get-EC2Instance -Filter @{name ='instance-type'; values = '*'}).count
EC2 Volumes
# Get vol mounted at sda1 for an instance (normally O/S drive)
Get-EC2Volume -Filter @(@{ Name = 'attachment.instance-id' ; Values = "$($ec2Instance.Instances.instanceid)"} ;
@{Name = 'attachment.device' ; values = '/dev/sda1'})
Get-EC2Volume -Filter @( @{ Name = 'attachment.instance-id' ; Values = "$($ec2Instance.Instances.instanceid)"} ;
@{Name = 'attachment.device' ; values = '/dev/sda2'})
EC2 Images
# https://docs.aws.amazon.com/powershell/latest/reference/items/Get-EC2Image.html
# OwnerID '801119661308' = Amazon Windows
# OwnerID '099720109477' = Canonical
# OwnerID '137112412989' = Amazon linux
# Filter by image id - handy to get owner info, name details etc
Get-EC2Image -Filter @{ Name="image-id"; Values="ami-01ac8cd0e2853e2be" }
# Windows
#2019 Full
Get-EC2Image -Filter @(@{ Name="platform"; Values="windows" } ; @{Name='owner-id' ; Values = '801119661308'} ; @{Name='name'; Values = 'Windows_Server-2019-English-Full-Base-*'})
#2019 Core
Get-EC2Image -Filter @(@{ Name="platform"; Values="windows" } ; @{Name='owner-id' ; Values = '801119661308'} ; @{Name='name'; Values = 'Windows_Server-2019-English-Core-Base-*'})
# Ubuntu
Get-EC2Image -Filter @(@{Name='owner-id' ; Values = '099720109477'} ; @{Name='name'; Values = '*ubuntu-bionic-18.04-amd64-server-*'})
Get-EC2Image -Filter @(@{Name='owner-id' ; Values = '099720109477'} ; @{Name='name'; Values = '*ubuntu-xenial-16.04-amd64-server-*'})
# Amazon
Get-EC2Image -Filter @(@{Name='owner-id' ; Values = '137112412989'} ; @{Name='name'; Values = '*amzn2-ami-hvm-2.0.2019*'})
Time difference between a filter and getting all instances (only 68 instances in this case)
Summary
Updating the script to turn on EC2 instances was a fun exercise that didn’t take too long. The script is basic but does the job well. The AWS filters are handy to use to speed up the filtering of EC2 objects and very useful to find volumes and images. Before I would get all instances / volumes / images from AWS and use PowerShell to sort and filter etc but now I’ve learnt more about filtering and how filtering at the API makes manipulating with PowerShell quicker due to less objects being sent in the pipeline and to sort etc.