© Brian Beach, Steven Armentrout, Rodney Bozo, Emmanuel Tsouris 2019
B. Beach et al.Pro PowerShell for Amazon Web Serviceshttps://doi.org/10.1007/978-1-4842-4850-8_3

3. Basic Instance Management

Brian Beach1 , Steven Armentrout2, Rodney Bozo3 and Emmanuel Tsouris4
(1)
Raleigh, NC, USA
(2)
Mountlake Terrace, WA, USA
(3)
Sterling, VA, USA
(4)
North Bend, WA, USA
 

Now that we’re done configuring our environment, we’ll jump right in and get started by creating an instance. An EC2 instance is, simply, a server running in the cloud. With a few quick clicks, we will have our first server up and running.

In this chapter, we will learn to create new instances and connect them. Then we will discuss how to start, stop, and terminate instances. We will learn various ways to access metadata and add custom metadata tags. In the exercises at the end of the chapter, we will build a PowerShell script to automate the launch process and customize the configuration of an instance.

Creating Instances

Let’s get started by creating a new instance. In this section we’ll launch a Windows Server 2019 instance. I’ll begin by using AWS Management Console. The console will give us a good overview of all the options available. Then, we will see how to do the same thing with a single line using PowerShell.

Launching an Instance with the Web Console

For this first exercise – launching an instance with the Web Console – we are going to include step-by-step instructions with figures. The Web Console changes often so don’t be surprised if the console screens look a bit different from the following figures.

We will sign in using the URL and IAM account we created in Chapter 2. Do not use the e-mail address we used to create the account. When we sign in, we will be taken to the AWS Management Console home page. The home page lists all of the AWS services available. Under the All services drop-down and Compute group, click the EC2 link (see Figure 3-1). Elastic Compute Cloud (EC2) is Amazon’s service for creating servers in the cloud.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig1_HTML.jpg
Figure 3-1

The home page

On the EC2 dashboard, make sure the region in the top right corner is the same one we used to create our key pair in the last chapter (e.g., Northern Virginia), as shown in Figure 3-2. Then click the Launch Instance button to start the wizard.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig2_HTML.jpg
Figure 3-2

EC2 dashboard

The first page of the wizard lists the Amazon Machine Images (AMI) . An AMI is a template image used to create a new instance. The Quick Start tab includes some of these images created by Amazon Web Services for public use. There are additional images available from the other tabs, currently more than 115,000. For now, we just need a basic version of Windows to get our feet wet. Find Microsoft Windows Server 2019 Base and click the Select button (see Figure 3-3).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig3_HTML.jpg
Figure 3-3

Choosing an AMI

On the instance details page, ensure that the instance type is set to t2 micro and click the button Next: Configure Instance Details (see Figure 3-4). The instance type is the virtual hardware we want to use. There are numerous combinations of processors, memory, network, and so on.

Only the micro instance is eligible for the free tier and will be labeled as such in the console. Read more about the free tier on the AWS web site. (An up-to-date description of the instance types are available at http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html .)
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig4_HTML.jpg
Figure 3-4

Choosing an Instance Type

Skip the page labeled as “Step 3: Configure Instance Details” by clicking Next: Add Storage. Skip the page labeled as “Step 4: Configure Instance Details” by clicking Next: Add Tags. We will review all of these advanced options in future chapters.

On the Tag Instance page, select the Add Tag button, and for Key field enter “Name” and for the Value field enter “My First Instance” and click Next: Configure Security Group (see Figure 3-5).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig5_HTML.jpg
Figure 3-5

Tagging the Instance

On the Configure Security Group screen, select the default group from the list of existing security groups (see Figure 3-6) and click the button that says Review and Launch. Security groups act like a firewall within AWS. We can use security groups to control what traffic is allowed to flow to and from the instance. (We will spend time looking at security groups in Chapter 6).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig6_HTML.jpg
Figure 3-6

Configure Security Group

Take a minute to review the options we selected on the next page and click Launch. This will load the key pair dialog box. Select the key pair we created in the previous chapter (see Figure 3-7). Remember that AWS uses this key to encrypt the Windows administrator password. Select the confirmation box and then click Launch Instances.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig7_HTML.jpg
Figure 3-7

Choosing our key pair

We just launched our first server in the cloud. Click the View Instances button, and we will be taken to the EC2 Instances page. We should see our new instance in the list with a state of pending.

It will take about 10 minutes for the instance to launch. While we are waiting, let’s discuss how we can do the same thing in PowerShell using a single line of code.

Launching an Instance with PowerShell

In PowerShell, we use the New-EC2Instance command to create instances. This is a really rich command that can do everything the wizard can do. For now we will focus on the basics of the New-EC2Instance command.

In the following example, we specify only the required parameters to successfully launch an instance.
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1
Let’s look at each parameter in turn, most of which are the same ones we saw when using the wizard in the preceding section:
  • An AMI is uniquely identified by an image ID value. The image IDs are different in each region. The ImageId parameter specifies which AMI we want to launch; therefore, the examples will use Get-EC2ImageByName to look up the correct ID in our currently defined default region. (We will discuss the Get-EC2ImageByName command in Chapter 7).

  • MinCount and MaxCount specify how many instances to launch. See the sidebar on reservations for details.

  • KeyName is the name of the key pair we created in the last chapter. It is used to encrypt the administrator password. Technically, this parameter is optional, but without it we will not be able to retrieve the administrator password.

  • InstanceType describes the hardware we wish to use, and again we will use the t2.micro.

Reservations

Let’s spend a minute talking about the MinCount and MaxCount parameters. New-EC2Instance always creates instances in batches called reservations. We are going to be using the reservation object in many of the scripts later in this chapter.

A reservation is a batch of instances launched at the same time. Even if we only want a single instance, we create a batch of size one. Every account has a limit on the number of runnable instances for each instance type per region. Some instance types support many dozens of launches by default, while some very powerful instance types may only allow one or two launches. Even Amazon has a finite number of instances available.

AWS will try to launch the number of instances specified in MaxCount. If it cannot launch the MaxCount due to account or regional capacity limits, Amazon will launch the largest possible number above MinCount. If the MinCount is more than Amazon EC2 will permit, no instances are launched and there will be a capacity or limit error.

Despite the name, New-EC2Instance actually returns a reservation object rather than an instance. If we want to check the individual instances, the reservation includes a list called RunningInstance.
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance –ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 2 -MaxCount 2
$Reservation.Instances
We can use a zero-based array syntax to read the individual instances. For example:
$Reservation.RunningInstance[0].InstanceId
$Reservation.RunningInstance[1].InstanceId
This will produce output similar to the following instance IDs:
i-05ebc32ffa7c0ed38
i-072bf9d8756b8c17d

By the way, although the attribute is called RunningInstance, it also contains instances that are in a stopped state.

Notice that we did not specify the security group (i.e., firewall). Unlike the Web Console wizard, the API will use the default group if we don’t specify one. There are numerous additional parameters to the New-EC2Instance command. These correspond to the options we skipped in the wizard. Don’t worry. We will talk about them all in later chapters.

Windows instances take about 10 minutes to launch regardless of how we create them. The instance(s) we launched with PowerShell are probably still launching, but the one we launched with the AWS Management Console is probably ready; let’s go check it now.

Checking the Instance Console Screenshot

Returning to the Web Console, let’s check on that instance we launched earlier. To view the running instances, select the services drop-down in the AWS Web Console. Either find and locate EC2 under the Compute group or use the find tool using EC2 as our search string and select EC2. When the EC2 dashboard console loads, select the Running Instances link.

We will now check on the instance using the Get Instance Screenshot tool. This tool will take a snapshot of our instances display output in its current state and show it to us. This can be a very useful for diagnosing instances that are not responding or are failing to launch. If a bug check occurred or service failed to start, we can usually find details by reviewing the instance screenshot.

On the instances page, select the instance, and right-click the instance and we will be presented with a drop-down menu. Alternatively, after selecting our instance we can select the Actions button at the top. In the drop-down menu, highlight Instance Settings and click Get Instance Screenshot (see Figure 3-8).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig8_HTML.jpg
Figure 3-8

Selecting the Instance Console Screenshot

A new page will load displaying a screenshot of our new instance. In our example we should see the login prompt (see Figure 3-9).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig9_HTML.jpg
Figure 3-9

Displaying the Instance Console Screenshot

Select Close on the bottom right corner of instance screenshot window to return back to the Instance Web Console.

Checking the Instance Console System Log

When an AWS provided image is launched, it performs some configurations and customizations at boot to prepare it for use. A summary log of these activities can be seen using the Get System Log tool.

To review our instance log, on the instances page, select the instance and right-click it and we will be presented with a drop-down menu. Alternatively, after selecting our instance we can select the Actions button at the top. In the drop-down menu, highlight Instance Settings and click Get System Log (see Figure 3-10).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig10_HTML.jpg
Figure 3-10

Selecting the Get System Log

A pop-up screen will load displaying the log output. If the instance was successfully configured at launch, we should see a “Windows is Ready to Use” message near the end of the System Log (see Figure 3-11).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig11_HTML.jpg
Figure 3-11

Displaying the System Log

Select Close on the bottom right corner of System Log window to return back to the Instance Web Console.

Connecting to an Instance

Remember, from the last chapter, that AWS will generate a new administrator password and encrypt it using our key pair. On the instances page, select the instance, and click the Connect button at the top of the screen. Then click the Get Password button (see Figure 3-12).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig12_HTML.jpg
Figure 3-12

Connect to Your Instance

Now, click the Choose File button (see Figure 3-13) and locate the private key we created in Chapter 2. Then click the Decrypt Password button.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig13_HTML.jpg
Figure 3-13

Decrypting the password

The dialog will now show the temporary password. Select the password and copy it to our clipboard and then click the Download Remote Desktop File link and run it (see Figure 3-14). This will launch a Remote Desktop session and prompt us for the password we just decrypted and copied to our clipboard. Paste the password in and click the Connect button.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig14_HTML.jpg
Figure 3-14

Downloading the Remote Desktop File

Great! Now we know how to create and connect to an instance using the Web Console.

Note

If the RDP connection fails, we may need to add a rule to the security group to allow Remote Desktop Protocol (RDP) access from our IP. Follow the following instructions. We will discuss security groups in detail in Chapter 6.

  1. 1.

    From the EC2 Web Console selections on the left under Network & Security, choose Security Groups.

     
  2. 2.

    Select the group named Default and choose the Inbound tab and select the Edit button.

     
  3. 3.

    In the Edit inbound rules window, choose the Add Rule button.

     
  4. 4.

    Under Type, select the drop-down and choose RDP.

     
  5. 5.

    Under Source, select the drop-down and choose My IP.

     
  6. 6.

    Finally, click the Save button.

    We can, of course, retrieve the password using PowerShell. The PowerShell command is Get-EC2PasswordData command. Get-EC2PasswordData takes an instance ID and the path to the private key and returns the password.

    Note that the instance ID will be different from these examples. Each instance has a different ID. We can get the ID from the instances page of the AWS Management Console.

     
Get-EC2PasswordData -InstanceId 'i-0824365ea545616fe' –PemFile 'c:awsMyKey.pem'

The preceding code will return an error if the password is not available yet. Remember, it takes about 10 minutes to launch a new instance. We will discuss how to test for password availability in the first exercise at the end of this chapter.

Now that we know how to launch and connect to an instance, let’s talk about starting, stopping, rebooting, and terminating instances.

Managing the Instance Life Cycle

Now that we have a few instances created, we will want to manage them. We can Start, Stop, Reboot, and Terminate (i.e., Delete) an instance by right-clicking it in the AWS Management Console and highlighting Instance State. Figure 3-15 shows the context menu.

Note

Stop - Hibernate is a new AWS feature that allows instances to be stopped in a powered down hibernation state instead of using a full shutdown. This can be helpful for customers who need scale their servers up and down quickly. As of this writing, Windows Servers are not yet supported and will not be selectable. The latest information and configuration requirements can be found at https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Hibernate.html .

../images/319650_2_En_3_Chapter/319650_2_En_3_Fig15_HTML.jpg
Figure 3-15

Instance Life-Cycle Menu Options

The equivalent PowerShell commands are pretty simple. They each have a parameter called Instance, which is the ID of the instance we want to start, stop, and so on.

To stop an instance, we use Stop-EC2Instance:
Stop-Ec2Instance -Instance i-0824365ea545616fe
To start an instance, we use Start-EC2Instance:
Start-Ec2Instance -Instance i-0824365ea545616fe
To reboot an instance, we use Restart-EC2Instance:
Restart-Ec2Instance -Instance i-0824365ea545616fe
To terminate an instance, we use Remove-EC2Instance. We will be asked to confirm the termination. We can add the force attribute to suppress the prompt.
Remove-EC2Instance -Instance i-0824365ea545616fe -Force

Listing Instances and Metadata

We have already seen the list of instances in the Web Console. We can use the Get-EC2Instance to list instances in PowerShell. The primary purpose of Get-EC2Instance is to return a list of all the instances in our account. In addition, we will use the Get-EC2Instance command to get metadata about the instance. Metadata includes information such as the IP address, drive configuration, and type of instance.
Get-EC2Instance
The preceding command returns the following results:
GroupNames    : {}
Groups        : {}
Instances     : {MyKey}
OwnerId       : 123456789012
RequesterId   :
ReservationId : r-0a585598e4c8ab8c4
GroupNames    : {}
Groups        : {}
Instances     : {MyKey, MyKey}
OwnerId       : 123456789012
RequesterId   :
ReservationId : r-0182baba42744a323
If we want a specific instance, use the Instance parameter, for example, reading the
Get-EC2Instance -Instance i-0824365ea545616fe
This command returns the following results:
GroupNames    : {}
Groups        : {}
Instances     : {MyKey}
OwnerId       : 123456789012
RequesterId   :
ReservationId : r-0a585598e4c8ab8c4

Note that Get-EC2Instance returns a reservation object. Remember that New-EC2Instance always creates a batch called a reservation. When we call Get-EC2Instance, AWS returns the reservation that includes its collection of instances.

The instances attribute contains the metadata of the instances we requested. Of course, we can dot source the AWS commands using PowerShell to get details of the instances object, for example, to get a list of all instances as a table.
(Get-EC2Instance).Instances
The preceding command returns the following results:
InstanceId          InstanceType     Platform     PrivateIpAddress PublicIpAddress     SecurityGroups     SubnetId           VpcId
----------          ------------     --------     ---------------- ---------------     --------------     --------           -----
i-0824365ea545616fe t2.micro         Windows      172.31.23.186    35.182.226.61       {default}          subnet-0433d96d    vpc-dd608bb4
i-072bf9d8756b8c17d t2.micro         Windows      172.31.1.36      99.79.67.159        {default}          subnet-bed9d3c6    vpc-dd608bb4
i-05ebc32ffa7c0ed38 t2.micro         Windows      172.31.4.75      35.183.48.244       {default}          subnet-bed9d3c6    vpc-dd608bb4
To access the instance metadata of a specific instance, we use the Instance parameter and dot source the instances output object. For example:
(Get-EC2Instance -Instance i-0824365ea545616fe).Instances
This command returns the following results:
InstanceId          InstanceType     Platform     PrivateIpAddress PublicIpAddress     SecurityGroups     SubnetId           VpcId
----------          ------------     --------     ----------------     ---------------     --------------     --------           -----
i-0824365ea545616fe t2.micro         Windows      172.31.23.186    35.182.226.61       {default}          subnet-0433d96d    vpc-dd608bb4
To see all the properties of a specific instance, we can pipe the output to either use format-list or select-object. For example:
(Get-EC2Instance -Instance i-0824365ea545616fe).Instances | Select-Object ∗
This results in
Tag                    : {Name}
AmiLaunchIndex         : 0
Architecture           : x86_64
BlockDeviceMappings    : {/dev/sda1}
ClientToken            :
CpuOptions             : Amazon.EC2.Model.CpuOptions
EbsOptimized           : False
ElasticGpuAssociations : {}
EnaSupport             : True
Hypervisor             : xen
IamInstanceProfile     :
ImageId                : ami-0f5c2aa18ff9af152
InstanceId             : i-0824365ea545616fe
InstanceLifecycle      :
InstanceType           : t2.micro
KernelId               :
KeyName                : MyKey
LaunchTime             : 3/3/2019 11:03:22 PM
Monitoring             : Amazon.EC2.Model.Monitoring
NetworkInterfaces      : {ip-172-31-23-186..compute.internal}
Placement              : Amazon.EC2.Model.Placement
Platform               : Windows
PrivateDnsName         : ip-172-31-23-186.compute.internal
PrivateIpAddress       : 172.31.23.186
ProductCodes           : {}
PublicDnsName          : ec2-35-182-226-61.compute.amazonaws.com
PublicIpAddress        : 35.182.226.61
RamdiskId              :
RootDeviceName         : /dev/sda1
RootDeviceType         : ebs
SecurityGroups         : {default}
SourceDestCheck        : True
SpotInstanceRequestId  :
SriovNetSupport        :
State                  : Amazon.EC2.Model.InstanceState
StateReason            :
StateTransitionReason  :
SubnetId               : subnet-0433d96d
Tags                   : {Name}
VirtualizationType     : hvm
VpcId                  : vpc-dd608bb4

This will give us a great deal of information about the instance including storage, network, and other details. We will use this information throughout the rest of the book. Before we get into that, let’s look at one other way to access some instance metadata using the metadata URL.

Using the Metadata URL

Get-EC2Instance is a great way to get information about an instance, but there is another way. The metadata URL returns much of the same information as Get-EC2Instance, but always returns information about the current instance.

The metadata URL is a web service that runs under each instance that returns metadata about the current instance. The URL is http://169.254.169.254/latest/meta-data .

Note the metadata service is only available from executing queries and scripts directly on the EC2 instance. We cannot use the API from a machine outside AWS, nor can we use the metadata service to get information about another instance.

Opening the metadata URL in Internet Explorer on an instance lists all of the options available (see Figure 3-16).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig16_HTML.jpg
Figure 3-16

Metadata URL

Navigating to any of the sub-URLs will return useful information about the instance. For example, navigating to http://169.254.169.254/latest/meta-data/instance-type will return the type of hardware we are running on (see Figure 3-17).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig17_HTML.jpg
Figure 3-17

Using the metadata URL

Of course, we can also access metadata from PowerShell using the Invoke-RestMethod command and passing the metadata URL.
Invoke-RestMethod 'http://169.254.169.254/latest/meta-data/instance-type'
This results in
t2.micro

A common use of the metadata URL is to discover the ID of the current instance and then use it to make calls to the AWS API. This way, we can write a generic script that will run on any EC2 instance.

The following script uses the metadata API to discover the instance ID and then calls Get-EC2Instance on it. Note that the instance ID was not known ahead of time. Instead, it was discovered by the script.
$InstanceID = Invoke-RestMethod 'http://169.254.169.254/latest/meta-data/instance-id'
Get-EC2Instance $InstanceID

Using User Data

One of the options we skipped over in the section on launching new instances was user data. User data is similar to metadata, but it allows us to include any custom data we want. The user data is available via a web service call, just like the metadata in the prior section.

One common use of user data is to include information needed to bootstrap the instance, or configure it after launch. We will do this in the second exercise at the end of this chapter.

To include user data, simply type whatever we want into the text box at the bottom of the third page under Advanced Details of the Launch Instance wizard (see Figure 3-18).

It is common, but not required, to use XML in the user data section. Using XML makes it easier to parse the data later. In the example in Figure 3-18, we are using a combination of free-form text and XML-formatted data.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig18_HTML.jpg
Figure 3-18

Setting User Data

Once the instance launches and we Remote Desktop in, we can retrieve the data using the user data URL http://169.254.169.254/latest/user-data (see Figure 3-19).
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig19_HTML.jpg
Figure 3-19

Retrieving User Data

Similar to the metadata URL, this URL will always return the user data for the running instance. Each instance has its own unique user data.

We can also include user data when calling New-EC2Instance from PowerShell using the UserData parameter. AWS anticipates that the user data will include XML. Remember that the API call is also a web service that may be formatted as XML. Therefore, to avoid confusion, we must base 64 encode the user data section. For example, the following code is equivalent to the console example shown earlier:
$UserData = @' This is a Test!!!
<TestValue>42</TestValue> '@
$UserData = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($UserData))
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1 -UserData $UserData

Note the @'...'@ syntax, this is just a convenient way to include a multiline string in PowerShell.

We can also use the Invoke-RestMethod command that we used in the previous section to retrieve the user data from PowerShell. For example:
Invoke-RestMethod 'http://169.254.169.254/latest/user-data'
This results in
This is a Test!!!
<TestValue>42</TestValue>

We can change the user data after launching an instance, but the instance must be in a stopped state. Let’s stop our instance and try replacing the user data with well-formed XML.

From the EC2 Instances Web Console, right-click our instance and highlight Instance State then select Stop. After a couple minutes, the instance should be in the stopped state.

Again, right-click the instance and highlight Instance Settings then select View/Change User Data. Clear the current user data and input the following XML into the user data box and save it. Start the instance again.
<documentation>
<document>
<name>GettingStarted</name> <url>http://awsdocs.s3.amazonaws.com/EC2/latest/ec2-gsg.pdf</url> </document> <document>
<name>UserGuide</name> <url>http://awsdocs.s3.amazonaws.com/EC2/latest/ec2-ug.pdf</url> </document> <document>
<name>APIReference</name> <url>http://awsdocs.s3.amazonaws.com/EC2/latest/ec2-api.pdf</url> </document> </documentation>
The benefit of using XML is that the Invoke-RestMethod command will parse the response. This means that we can interact with the response like any other object in PowerShell and we get IntelliSense in the IDE as well. Note how we can navigate the object hierarchy and format the response:
$Response = Invoke-RestMethod 'http://169.254.169.254/latest/user-data'
$Response.documentation.document | Format-Table
The preceding code results in the following output:
name           url
----           ---
GettingStarted http://awsdocs.s3.amazonaws.com/EC2/latest/ec2-gsg.pdf
UserGuide      http://awsdocs.s3.amazonaws.com/EC2/latest/ec2-ug.pdf
APIReference   http://awsdocs.s3.amazonaws.com/EC2/latest/ec2-api.pdf

There is one other really cool feature of user data. We can include scripts that we want to run when the instance boots the first time. We can include Windows command shell scripts inside <script>...</script> or PowerShell scripts inside <powershell>...</powershell> tags. We will do this in the second exercise at the end of this chapter.

Working with Tags

Every object in AWS supports tags. Tags are a great way to keep track of all our instances and other objects. A tag is simply a key/value pair used to describe the object. For example, we can use a tag to record the name of an instance or which department owns it. We can use tags to record any additional information we need.

Each object can have up to 50 tags. The key can be up to 128 characters, and the value can be up to 256 characters long. Note how we can access tags on the EC2 Web Console using the Tags tab when selecting an instance (see Figure 3-20). We can edit the tags using the Add/Edit Tags button.
../images/319650_2_En_3_Chapter/319650_2_En_3_Fig20_HTML.jpg
Figure 3-20

The Tags tab

In PowerShell we can read the tags from the tag collection of any object. To get the tags for an instance, just get a reference to the instance and read the Tag property:
$Reservation = Get-EC2Instance -Instance i-0824365ea545616fe
$Instance = $Reservation.Instances
$Instance.Tag
Here is the result:
Key        Value
---        -----
Department Information Technology
Name       My First Instance
If we want to retrieve a specific tag, use the where-object command to find it:
$Tag = $Instance.Tag | Where-Object {$_.Key -eq "Name"}
$Tag.Value

Creating tags is a bit harder. A tag is a .Net object so there is no PowerShell command to create an EC2 tag. Instead, we use the generic new-object command to create a .Net object of type Amazon.EC2.Model.Tag. Once we have the new tag object, we can use the New-EC2Tag PowerShell command to set the Key and Value properties.

Let’s add another descriptive tag to our instance:
$Tag = New-Object Amazon.EC2.Model.Tag
$Tag.Key ='Role'
$Tag.Value = 'File Server'
New-EC2Tag -ResourceId i-0824365ea545616fe -Tag $Tag

When there is only a few instances, it is relatively simple to keep track of everything. Once we launch ten or more, it quickly gets very confusing.

One trick is to tag everything. Each instance has at least one volume and one network interface attached. Whenever a new instance is created, tag the instance and all of the attached resources.

AWS makes it easy to tag multiple objects at once. We simply pass all the IDs to New-EC2Tag as an array. There is no need to tell AWS what type of object each is. It can figure that out on its own. In this example we will launch a new instance and tag the instance and its resources.
$AMI = Get-EC2ImageByName -Name 'WINDOWS_2016_BASE'
$Reservation = New-EC2Instance -ImageId $AMI[0].ImageId -KeyName 'MyKey' -InstanceType 't2.micro' -MinCount 1 -MaxCount 1
$InstanceId = $Reservation.Instances.InstanceId
Start-Sleep -s 60 #Wait for drives to be created and mounted, etc.
$Reservation = Get-EC2Instance -Instance $InstanceId
$VolumeId = $Reservation.Instances.Blockdevicemappings.EBS.VolumeId
$NetworkInterfaceId = $Reservation.Instances.NetworkInterfaces.NetworkInterfaceId
$Tag = New-Object Amazon.EC2.Model.Tag
$Tag.Key = 'Name'
$Tag.Value = 'Multi Tagged Server'
New-EC2Tag -ResourceId $InstanceId, $VolumeId, $NetworkInterfaceId -Tag $Tag

Notice that Start-Sleep in the previous command. When we create a new instance, the command may return before all of the resources have been allocated. Therefore, we may find that a volume or network interface is null if we move too quickly.

To get around this, we have the script sleep for a few seconds. Then we query AWS for an updated copy of the instance metadata. This gives AWS enough time to allocate resources.

Working with Filters

In the previous section, we used the Where-Object command to filter a collection and find a specific tag. This same method could be applied to other objects – for example, to find all of the instances owned by a given department.

AWS provides a better solution: filters. A filter allows us to specify search criteria to be executed on the server side. This way we don’t have to download metadata from hundreds of instances and sort through them when we are only interested in a handful.

The Get methods usually include a filter parameter. The filter allows us to return only those resources with a specific value for a given attribute. For example, if we want to return a list of instances that are currently in a running state, we can use the instance-state-code filter. A value of 16 indicates an instance is running.

The filter names and values are not always intuitive. They use the AWS CLI syntax, which may be foreign to a user of the PowerShell API. Included is a list of filters and values with each Get command in Appendix C.

Once again, we use the generic New-Object to create the filter. For example:
$Filter = New-Object Amazon.EC2.Model.Filter
$Filter.Name = 'instance-state-code'
$Filter.Value = 16
Get-EC2Instance -Filter $Filter
Optionally we can just use a hashtable using the name and value key pair. In this example we will use the friendlier ‘instance-state-name’ filter of ‘running’.
$Filter = @{name='instance-state-name';value='running'}
Get-EC2Instance -Filter $Filter
We can also use filters to search for custom tags. For example, assume we record the department that owns each instance. If we wanted to retrieve all instances that belong to the Information Technology department, we could use
$Filter = @{name='tag:Department';value='Information Technology'}
Get-EC2Instance -Filter $filter

When we filter on tags, we use the format tag, followed by the key name. Remember that keys and their values are case sensitive. When creating keys manually using the Web Console, be consistent.

If we wanted to retrieve all of the running and pending instances that belong to the Information Technology department, we could use multiple filters that specify the tag of “Department” with the value of “Information Technology” and an instance-state-name with a value of “running” or “pending”. To do that we can add multiple comma-separated values for a given name and pass multiple hashtables as an array.
$Filter = @(@{name='instance-state-name';value='running','pending'};@{name='tag:Department';value='Information Technology'})
Get-EC2Instance -Filter $filter

Exercise 3.1: Waiting For an Instance to Launch

For this exercise let’s assume that we often receive requests to create new instances from developers in our organization and those developers don’t have access to the AWS Web Console. As AWS adoption has grown, this has become very time-consuming. It would be nice to script the build in PowerShell.

We can create a new instance and get the password with a few lines of code, and it would be great if a script could wait for the build to finish and then automatically e-mail the password to the requestor. But, how do we know when the server is finished?

One way to determine whether the server is finished is to poll the instance to check if the password is available. We can call the Get-EC2PasswordData command to check if a password exists. This provides a convenient way to check for password availability.

Let’s start by creating a new method, called GetPasswordWhenReady . This method checks once every minute until the password is ready and then returns it. The method takes three parameters. The first is the ID of the instance to wait on. The second is the location of the private key used to decrypt the password. The third is the number of minutes to wait for the password, after which the script will give up.

Note that the script writes periods to the screen each minute to let the user know that it is still working. Also note that we had the set WarningAction to stop as the cmdlet Get-EC2PasswordData throws a warning to our catch statement when the password has yet to be generated.
Function GetPasswordWhenReady
{
    Param(
        [string][Parameter(Mandatory=$True)] $InstanceId,
        [string][Parameter(Mandatory=$True)] $PemFile,
        [Int] $TimeOut = 35
    )
    $RetryCount = $TimeOut
    Write-Host "Waiting for password..." -NoNewline
    While($RetryCount -gt 1)
    {
        Try {
            $Password = Get-EC2PasswordData -InstanceId $InstanceId -PemFile $PemFile -WarningAction stop
            Write-Host ""
            Return $Password
        }
        Catch {
            $RetryCount--
            Start-Sleep -s 60 #It's not ready. Let's wait for it.
            Write-Host "..." -NoNewline #It's nice to give a little feedback now and then
        }
    }
    throw "Failed to get password from $InstanceId after waiting $Timeout minutes."
}
All we need now is a method that sends e-mails. This method will take three parameters: recipient, instance address, and password. Note that we have hard-coded the from address and SMTP server name in my script. We will need to change them to our own SMTP server settings if one is configured.
Function SendInstanceReadyEmail {
    Param(
        [string][Parameter(Mandatory=$True)] $Recipient,
        [string][Parameter(Mandatory=$True)] $InstanceAddress,
        [string][Parameter(Mandatory=$True)] $Password
    )
    $Message = "Access the instance at $InstanceAddress. The administrator password is $Password."
    #Create the message
    $Email = New-Object Net.Mail.MailMessage
    $Email.From = "[email protected]"
    $Email.ReplyTo = "[email protected]"
    $Email.To.Add($Recipient)
    $Email.Subject = "Instance is Ready"
    $Email.Body = $Message
    #Send the message
    $SMTP = New-Object Net.Mail.SmtpClient('smtp.brianbeach.com')
    $SMTP.Send($Email)
}
Now we can test it. Here we are creating a new instance and retrieving the ID. Then we wait for the password to become available. This usually takes about 5–10 minutes. Once the password is ready, we refresh the metadata. Remember that some attributes are not available when New-EC2Instance returns. By refreshing the metadata after the build completes, we know that all variables are present. Now we can send an e-mail to the requestor.
Param(
    [string][Parameter(Mandatory=$false)] $ImageID,
    [string][Parameter(Mandatory=$false)] $KeyName = 'MyKey',
    [string][Parameter(Mandatory=$false)] $PemFile = 'c:awsMyKey.pem',
    [string][Parameter(Mandatory=$false)] $InstanceType = 't2.micro',
    [string][Parameter(Mandatory=$true)] $EmailRecipient
)
#Create a new instance
If([System.String]::IsNullOrEmpty($ImageID))
{
    $ImageID = (Get-EC2ImageByName -Name "WINDOWS_2016_BASE")[0].ImageId
}
$Reservation = New-EC2Instance -ImageId $ImageID -KeyName $KeyName -InstanceType $InstanceType -MinCount 1 -MaxCount 1
$InstanceId = $Reservation.Instances[0].InstanceId
#Get the password to the new instance
$Password = GetPasswordWhenReady -Instance $InstanceId -PemFile $PemFile
#Get the latest meta-data including the DNS name
$Reservation = Get-EC2Instance –Instance $InstanceId
$InstanceAddress = $Reservation.RunningInstance[0].PrivateIPAddress
#Send an email with connection info
SendInstanceReadyEmail -Recipient $EmailRecipient -InstanceAddress $InstanceAddress -Password $Password

Exercise 3.2: Bootstrapping With User Data

At this point we know how to launch and manage instances. Before we close this chapter, let’s spend a minute talking about how we can customize instances. We could, of course, just log in and configure each instance manually, but the cloud is all about automation and standardization.

If we script the configuration of our server, the results will be more consistent and reproducible.

Amazon thought of this, and it included the capability to run configuration scripts when a server boots. In this exercise, we are going to configure our instance for remote administration. We will use a PowerShell script in the user data to complete the configuration.

Amazon includes the EC2Config or EC2Launch service agent (depending on the OS version) in every Windows AMI they provide. The first time an instance boots, this agent service will check the user data for <script>...</script> or <powershell>...</powershell> tags and then execute them at the command prompt or PowerShell prompt, respectively. By default, scripts are run only the first time an instance boots, but we can configure it to run every time the instance starts (we will look at this in Chapter 7).

We talked in the last chapter about specifying default credentials and a default region. We will use a server role to provide credentials, but remember that we still need to set the default region and we can use PowerShell in the user data to accomplish this. When a new AWS instance launches, it will be ready to run scripts without further configuration.

On our next instance launch, let’s make a few more changes with a user data script to enable PowerShell remoting for administration and Windows Management Instrumentation (WMI) for monitoring and management.

PowerShell remoting is really easy. The command is simply Enable-PSRemoting. WMI is a bit more complicated. WMI is already running, but Windows Firewall will block external access. Fortunately, the firewall rules are already configured. They just need to be enabled. All we need to do is use the PowerShell command Enable-NetFirewallRule. Here we enable PSRemoting and then find and enable all of the WMI firewall rules:
Enable-PSRemoting
Get-NetFirewallRule | Where { $_.DisplayName -like "Windows Management Instrumentation ∗" } |
Enable-NetFirewallRule

The complete script is available with the accompanying code in a file called Bootstrap.ps1. For information on downloading the sample code, see Chapter 1. We could use the “As file” option under advanced details in the Configure Instance page of the Launch Instance Wizard to open this file, but we are going to generate the user data and launch the instance using only PowerShell.

The following script will open the bootstrap script from disk. Then it will format the script for use with the AWS API. Finally, it will launch the instance, passing the script as user data.
param(
    [parameter(mandatory=$false)][string]$KeyName = 'MyKey',
    [parameter(mandatory=$false)][string]$RoleName = 'AdminRole',
    [parameter(mandatory=$false)][string]$UserDataFile = 'C:AWSChapter3Exercise2Bootstrap.ps1',
    [parameter(mandatory=$false)][string]$ImageId,
    [parameter(mandatory=$false)][string]$InstanceType = 't2.micro'
)
#If no image was specified, assume 2016 base
If([System.String]::IsNullOrEmpty($ImageID)){$ImageID = (Get-EC2ImageByName -Name "WINDOWS_2016_BASE")[0].ImageId}
#Read the bootstrap script from the file specified
#Get-Content returns an array of strings. Raw converts the array to a single string
$BootstrapScript = Get-Content -Raw $UserDataFile
#Add the PowerShell tags to the script
$BootstrapScript = @"
<powershell>
$BootstrapScript
</powershell>
"@
#Base 64 encode the script
$UserData = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($BootstrapScript))
#Get the IAM Role to apply to the new instance
$Profile = Get-IAMInstanceProfile -InstanceProfileName $RoleName
#Launch the new instance with bootstrap script
$Reservation = New-EC2Instance -ImageId $ImageId -KeyName $KeyName -InstanceType $InstanceType -MinCount 1 -MaxCount 1 -UserData $UserData -InstanceProfile_Arn $Profile.Arn
$InstanceId = $Reservation.Instances[0].InstanceId
Write-Host "Launched new instance with ID $InstanceId"

User data is a really powerful option. We can use this to make just about any customizations we need without ever logging into a server. As our adoption of AWS matures, we will likely begin to use features such as Auto Scaling, which deploys instances automatically in response to load. Obviously, it is critical that we can auto configure these instances at launch. (We will talk more about Auto Scaling in Chapter 8).

Summary

In this chapter, we got a good introduction to instances. We learned to launch and verify instances using both Web Console and PowerShell. We learned how to start, stop, and terminate instances. We also learned how to discover information about our instance using both PowerShell and the metadata URL. Next, we learned how to include custom data with user data and tags. Then we discussed how to use filters to find specific instances. In the examples we created a complete script to manage launching instances. Then we learned how to customize our instance at launch using user data.

In the next chapter, we will discuss storage including volumes and snapshots. Volumes are the disks that are attached to an instance, and snapshots are point-in-time backups of our volumes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset