Chapter 3.Virtual Machines - NEW FEATURES OFFERED BY MICROSOFT ACCESS - Automating Microsoft Azure Infrastructure Services (2015)

Automating Microsoft Azure Infrastructure Services

Chapter 3. Virtual Machines

Creating Virtual Machines with PowerShell

In this chapter you will learn about using the Microsoft Azure PowerShell cmdlets to create a virtual machine with Microsoft Azure platform images. As part of learning this process, you will learn how to specify the initial configuration settings such as the local administrator account name and password, the virtual machine size (CPUs and memory), network endpoints, and underlying storage. From there you will learn how to use those same concepts to modify the configuration of existing virtual machines, whether they are running or not.

To get started creating your first virtual machine using PowerShell, you will need some environment information from Microsoft Azure. This is the same information that you use in the portal, such as the region name and the storage account that will be used as the location where your virtual machine disks are created.

For the first part of this chapter, I would recommend creating a new PowerShell file and saving it with a name such as chapter3create.ps1. Some portions of this chapter will be saved to the script and edited in the Script pane (top portion of the ISE) to make it easier to follow, and some portions should be executed in the Console pane (bottom portion of the ISE) for immediate results.

The first call related to Microsoft Azure of your new script should always be to Select-AzureSubscription to ensure that you are executing commands against the correct Microsoft Azure subscription.

Add the code shown in Example 3-1 to create a variable to store your subscription name and then select that subscription for use. Ensure that you replace the placeholder values with real ones.

Example 3-1. Selecting your subscription (Script pane)

$subscription = "[subscription name]"

Select-AzureSubscription $subscription

REPLACING THE SUBSCRIPTION NAME PLACEHOLDER

Remember, you can find the name of your subscriptions by calling Get-AzureSubscription | Select SubscriptionName in the Console pane. Use that value instead of the placeholder value in the example. The subscription name is case sensitive!

Executing the script

When the call to Select-AzureSubscription is in place, press F5, or highlight the script and press F8, to select your current subscription. This will validate that you have the correct subscription name in place and will also set any future commands run from the Console pane to that subscription.

Virtual Machine Location and Storage

All resources in Microsoft Azure are created in a specific region. This is the same region that you see in the management portal when you create a virtual machine.

To retrieve a list of available regions, you can run the Get-AzureLocation cmdlet (see Example 3-2). Since the goal is to have an immediate list of available names and not run these each time you execute this script, I would suggest you run this command in the Console pane of the PowerShell ISE (see Example 3-2).

Example 3-2. Returning Microsoft Azure location details (Console pane)

Get-AzureLocation

A few properties of the output shown in Figure 3-1 are very important for provisioning virtual machines:

§ AvailableServices

§ Name

You can create a virtual machine only in locations where the AvailableServices list contains PersistentVMRole. The AvailableServices list can also contain a HighMemory value. This denotes locations where the A5, A6, A7, A8, A9, and future high-memory virtual machine configurations are available to be provisioned. The Name property is the value you will use to specify the location during the creation of resources.

Using Get-AzureLocation

Figure 3-1. Using Get-AzureLocation

After you have determined the region in which to create virtual machines, you can store the name of the region in a variable for later reference. Add the code in Example 3-3 to your script to store the region name.

Example 3-3. Storing the region name in a variable (Script pane)

$location = "[region name]"

The next step is to specify the storage account where the virtual machines will be created. The storage account must be in the same region as the virtual machine. This is enforced at the API level so you do not accidentally end up in a situation where your virtual machine is running on the West Coast of the United States but the underlying disks are in Europe!

The first option is to enumerate your existing storage accounts for a suitable storage account. The command in Example 3-4 will enumerate all of the storage accounts in your subscription but return only the StorageAccountName and Location properties (see Figure 3-2).

Example 3-4. Enumerating existing storage accounts (Console pane)

Get-AzureStorageAccount | select StorageAccountName, Location

If you do not have a storage account available, or you just want to create a new one, use the New-AzureStorageAccount cmdlet.

To ensure the availability of the Microsoft Azure storage account name, you should use the Test-AzureName cmdlet first (see Example 3-5). Test-AzureName verifies whether the name is available for your use in Microsoft Azure. Make sure you replace the [storage account name]placeholder in the script before executing!

Using Get-AzureStorageAccount to enumerate storage accounts

Figure 3-2. Using Get-AzureStorageAccount to enumerate storage accounts

Example 3-5. Finding a unique storage account name (Console pane)

Test-AzureName -Storage -Name "[storage account name]"

If the call returns True, the storage account name already exists and is not available to you. Run the command with a new name until the call returns False, which means that the storage account name is available. Create the new storage account as shown in Example 3-6.

STORAGE ACCOUNT NAME

The name of your storage account must be unique within Azure. Storage account names must be between 3 and 24 characters in length and use numbers and lowercase letters only.

Example 3-6. Creating a new storage account (Console pane)

New-AzureStorageAccount -StorageAccountName "[storage account name]" `

-Location $location

When you determine the name of the storage account to use, save it in a variable for later reference. Add the code in Example 3-7 to your script to store the storage account name.

Example 3-7. Specifying the current storage account (Script pane)

$storageAccount = "[storage account name]"

The next step is to associate the storage account with the subscription you are using by specifying the name with the -CurrentStorageAccountName parameter in the Set-AzureSubscription cmdlet. Once set, any PowerShell cmdlets that create virtual machines or deploy cloud-service packages will use this storage account as the default.

Add the code in Example 3-8 to associate the subscription with the storage account.

Example 3-8. Specifying the current storage account (Script pane)

Set-AzureSubscription -SubscriptionName $subscription `

-CurrentStorageAccountName $storageAccount

Selecting the Virtual Machine Platform Image

When creating a virtual machine, you can start from an existing disk or from one of the platform images in Microsoft Azure. In Chapter 5 I will cover provisioning virtual machines directly from disk. For now, this chapter will focus on using an image. To view the available images for your subscription run the command Get-AzureVMImage, as shown in Example 3-9.

Example 3-9. Enumerating virtual machine images (Console pane)

Get-AzureVMImage

The amount of information that Get-AzureVMImage returns can be quite overwhelming (see Figure 3-3).

Output from Get-AzureVMImage

Figure 3-3. Output from Get-AzureVMImage

Table 3-1 lists some important properties to note.

Table 3-1. Get-AzureVMImage properties

EULA

This is a link to an end-user license agreement for the particular image.

LogicalDiskSizeInGB

Shows how large the OS disk will be if you use this image (maximum 127 GB).

RecommendedVMSize

The recommended size to run this image.

IsPremium

If True, you are paying above standard compute rates for the operating system. SQL Server is a good example, as you are paying a premium for the SQL Server licensing cost.

Description

Description of what the image contains.

ImageFamily

A name to group the same type of images. There are multiple images of the same family due to creating new patched images and sometimes configuration differences.

ImageName

When provisioning from PowerShell, this is the value you will use when specifying the image.

Thankfully, PowerShell provides the ability to quickly filter out information.

The first step is to identify the image family by using the Get-AzureVMImage cmdlet and returning only the ImageFamily property (see Example 3-10).

Example 3-10. Returning all available image families (Console pane)

Get-AzureVMImage | select ImageFamily

When you have identified the image family that you want to use, assign the image family name to a variable. You can use that variable with PowerShell’s native comparison and filter capabilities to always return the latest image for that family and store that image name in a variable for later use.

The code in Example 3-11 returns a list of available images, and then passes that output to the where command, which filters only images with the image family name that matches $imageFamily. That output is then sorted by PublishedDate (Descending) so the newest image is the first one returned. Finally, that output is then passed to the select command with the -First parameter, which indicates to return only the first item.

Add the code in Example 3-11 to your script to return and store the name of the virtual machine image to use.

Example 3-11. Finding the latest image name (Script pane)

$imageFamily = "Windows Server 2012 R2 Datacenter"

$imageName = Get-AzureVMImage |

where { $_.ImageFamily -eq $imageFamily } |

sort PublishedDate -Descending |

select -ExpandProperty ImageName -First 1

Virtual Machine Size

The Get-AzureRoleSize cmdlet can be used to enumerate the available virtual machine sizes (see Example 3-12). This will tell you the maximum memory, the maximum size on the resource disk, and the number of data disks supported per role (see Figure 3-4).

Example 3-12. Identifying the virtual machine size (Console pane)

Get-AzureRoleSize

Using Get-AzureRoleSize

Figure 3-4. Using Get-AzureRoleSize

Ensure that the size you select has SupportedByVirtualMachines set to True. Since this is PowerShell, you can filter output on that property (see Example 3-13).

Example 3-13. Returning only role sizes supported by virtual machines (Console pane)

Get-AzureRoleSize | where { $_.SupportedByVirtualMachines -eq $true }

When you have identified which role size to use to create your virtual machines, simply store the InstanceSize name in a variable.

Add the code in Example 3-14 to store the virtual machine size.

Example 3-14. Storing the virtual machine size (Script pane)

$vmSize = "Small"

Cloud Services and Virtual Machines

are always created in a container called a cloud service. A cloud service provides a networking and security boundary for your virtual machines. Virtual machines that are created in the same cloud service are on the same private network and can directly communicate with each other without going through the public load balancer or a virtual network to communicate.

Also, if virtual machines need to be load-balanced together or require high availability, they must be created in the same cloud service as load-balanced endpoints (internal and external), and availability sets cannot span multiple cloud services. Microsoft Azure also provides built-in name resolution to virtual machines in the same cloud service.

During virtual machine creation, you are required either to specify the cloud service name for an existing cloud service that is available in your subscription or to supply a new name that is not in use and is globally available. In this chapter you will use PowerShell to create a new cloud service.

Just like the name of a Microsoft Azure storage account, a cloud service name must be globally unique in Microsoft Azure. To ensure the availability of the cloud service name, use the Test-AzureName cmdlet first (see Example 3-15).

Ensure that you replace the [cloud service name] placeholder with the name of the cloud service you wish to create.

Example 3-15. Finding a unique cloud service name (Console pane)

Test-AzureName -Service -Name "[cloud service name]"

If the call returns True, the service name exists and cannot be created again (this does not indicate whether the service is in your subscription). In this example, we specifically want to create a new cloud service, so you should run the command with a new name until the call returns False. When you have identified a unique name, store it in a variable for later reference.

Add the code in Example 3-16 to your script to store the cloud service name.

Example 3-16. Store the cloud service name in a variable (Script pane)

$serviceName = "[cloud service name]"

Creating a Virtual Machine with New-AzureQuickVM

The New-AzureQuickVM cmdlet is very similar to using the Quick Create button in the Microsoft Azure management portal. The available customizations are limited, but it is a relatively easy way of provisioning a virtual machine.

To use this technique, you will need to define three more variables: the administrator username, the password, and the computer name. When choosing the name and password for the local administrator account, ensure that the values you choose are not overly obvious, like “administrator” or “password”, because the Microsoft Azure API will reject them. Add the code in Example 3-17 to your script and replace the placeholder values with values of your own.

Example 3-17. Username, password, and computer name (Script pane)

# Specify the admin credentials

$adminUser = "[admin username]"

$password = "[admin password]"

# Specify the virtual machine name

$vmName = "ps-vm1"

STORING USERNAMES AND PASSWORDS IN SCRIPTS

As a general rule, it is a bad security practice and a bad maintenance practice to store credentials directly in a script. It is shown here to keep the scripts simple and focus on the task at hand. Practical alternatives include passing credentials in as parameters to a script or prompting for credentials by using the Get-Credential cmdlet.

COMPUTER NAME UNIQUENESS

The computer name must be unique to all of the virtual machines in the same cloud service.

Now that all of the necessary information is stored in variables, you can create a virtual machine (VM).

The New-AzureQuickVM cmdlet supports parameter sets for creating Windows- or Linux-based virtual machines from an image. In this example, passing -Windows tells the cmdlets that the image you are passing is a Windows-based OS.

Add the code in Example 3-18 to your script.

Example 3-18. Creating a virtual machine using New-AzureQuickVM (Script pane)

New-AzureQuickVM -Windows `

-ServiceName $serviceName `

-Name $vmName `

-ImageName $imageName `

-Location $location `

-InstanceSize $vmSize `

-AdminUsername $adminUser `

-Password $password

This technique is quick and simple but it does have its drawbacks. The limitations to using New-AzureQuickVM are as follows:

§ You cannot add data disks or endpoints at creation time.

§ You cannot have the virtual machine domain-joined at creation time.

§ You cannot boot from a disk (images only).

Several other provisioning features supported by New-AzureQuickVM are discussed in Chapter 7.

Creating a Virtual Machine Configuration with New-AzureVMConfig

The second technique for creating a virtual machine requires the use of two (or more) cmdlets together to compose a virtual machine by creating a configuration object, modifying it, and then creating a virtual machine with the customized configuration object. This pattern is similar to how the cmdlets are used for updating existing virtual machines.

As the name New-AzureVMConfig implies, this cmdlet does not create a virtual machine but instead creates a virtual machine configuration object. Once it is created, you modify the configuration object with other cmdlets to have all of the characteristics that you want the virtual machine to have at provisioning time. This technique can save you several API calls, such as individually adding data disks or network endpoints. If you are automating the creation of several virtual machines, this can save you a lot of time spent in provisioning and, in the long run, a lot of code you do not have to write.

Add the code in Example 3-19 to your script. Note that the $vmName variable has also been modified because this code will create a second virtual machine named ps-vm2 in the same cloud service as ps-vm1.

Example 3-19. Creating a VM configuration object with New-AzureVMConfig (Script pane)

$vmName = "ps-vm2"

$vmConfig = New-AzureVMConfig -Name $vmName `

-InstanceSize $vmSize `

-ImageName $imageName

When the virtual machine configuration is created, you then modify it using the PowerShell pipeline and several other Microsoft Azure cmdlets that know how to modify this object.

Specifying the Initial Provisioning Configuration

Creating a virtual machine configuration from an image, as shown in the previous example, requires you to specify the initial provisioning configuration. Use the Add-AzureProvisioningConfig cmdlet to specify these settings (see Example 3-20). This cmdlet accepts the passed-in object $vmConfig and modifies it by creating and setting the properties that will hold the local administrator username, password, and various other properties that can be set at provisioning time.

Example 3-20. Specifying the provisioning configuration (Script pane)

$vmConfig | Add-AzureProvisioningConfig -Windows `

-AdminUsername $adminUser `

-Password $password

Adding Storage with Add-AzureDataDisk

Creating virtual machines by composing the configuration allows you to specify additional information such as adding data disks at provisoning time. The amount of storage you can specify per virtual machine depends on the instance size you are creating. Each disk can be up to 1023 GB in size. Each virtual machine size allows a different number of data disks to be attached. The output from the Get-AzureRoleSize cmdlet used earlier will show the maximum number of data disks supported.

In Example 3-21 Add-AzureDataDisk with the -CreateNew parameter is used to modify the passed-in configuration $vmConfig to create blank, unformatted VHDs attached to the virtual machine on boot.

Add the code in Example 3-21 to your script to attach a new 500 GB data disk on LUN 0 of the virtual machine that will be created.

Example 3-21. Adding storage at provisioning time (Script pane)

$vmConfig | Add-AzureDataDisk -CreateNew `

-DiskSizeInGB 500 `

-DiskLabel "data 1" `

-LUN 0

MAXIMUM DATA DISK SIZE

The maximum size of a data disk in Microsoft Azure is currently 1023 GB.

The Add-AzureDataDisk cmdlet supports three parameter sets. As shown in Example 3-21, the -CreateNew parameter is used to create blank VHDs. The -Import parameter allows you to specify a disk by referencing the name of the disk registered in Microsoft Azure. The -ImportFrom parameter allows you to specify the URL to the VHD in a Microsoft Azure storage account (in the same subscription and same region) and a disk label.

I will cover managing disks, images, and storage in greater detail in Chapter 5.

Creating Network Endpoints at Provisioning

Similar to adding storage, you can also add network endpoints at provisioning time by modifying the virtual machine configuration before passing it to Microsoft Azure for creation.

Example 3-22 modifies the virtual machine configuration $vmConfig by adding a new load-balanced endpoint named HTTP to the configuration.

This endpoint is using TCP as the protocol accepting traffic on public port 80 and forwarding it to local port 80. The -LBSetName parameter specifies that this endpoint is part of a load-balanced set. If I wanted to create additional virtual machines to handle additional traffic on port 80, I would just need to reference the same load-balanced set name as specified in the following example.

The -DefaultProbe parameter tells Microsoft Azure to set up a TCP health probe on the local port. This means that the load balancer will occasionally attempt to connect on the port specified with -LocalPort. If it can connect, the endpoint is considered healthy, but if it cannot connect after a configurable number of tries, then it will no longer be considered healthy and the load balancer will not forward traffic to the endpoint.

Add the code in Example 3-22 to modify your $vmConfig to add the load-balanced endpoint.

Example 3-22. Adding a load-balanced endpoint (Script pane)

$vmConfig | Add-AzureEndpoint -Name "HTTP" `

-Protocol tcp `

-LocalPort 80 `

-PublicPort 80 `

-LBSetName "LBHTTP" `

-DefaultProbe

As with data disks, I can add more endpoints if needed just by adding another call to Add-AzureEndpoint. In Example 3-22 I have added an endpoint for port 80 for HTTP traffic. I could also open up port 443 for HTTPS traffic simply by adding an endpoint to the configuration (seeExample 3-23).

Example 3-23. Opening up port 443 (Script pane)

$vmConfig | Add-AzureEndpoint -Name "HTTPS" `

-Protocol tcp `

-LocalPort 443 `

-PublicPort 443 `

-LBSetName "LBHTTPS" `

-DefaultProbe

I will cover managing endpoints in greater detail in Chapter 4.

Creating a Virtual Machine with New-AzureVM

The cmdlet that does the heavy lifting of actually creating virtual machines from one or more configuration objects is New-AzureVM. The New-AzureVM cmdlet supports passing a single configuration object or an array of configuration objects to the -VMs parameter (see Example 3-24). If passed an array, the cmdlet will automatically create each virtual machine in the same cloud service for you.

Example 3-24. Creating a virtual machine with New-AzureVM (Script pane)

New-AzureVM -ServiceName $serviceName -VMs $vmConfig

Now that the last line of code is added, let me add a complete example (see Example 3-25) using placeholder values (ensure that you replace them with real values), and then I will review what the script does.

Example 3-25. Complete script for chapter3create.ps1 (Script pane)

# Replace with your own subscription name

$subscription = "[subscription name]"

Select-AzureSubscription $subscription

# Replace with the region you wish to deploy in

$location = "[region name]"

$vmSize = "Small"

# Replace with your own storage account name

$storageAccount = "[storage account name]"

Set-AzureSubscription -SubscriptionName $subscription `

-CurrentStorageAccountName $storageAccount

$imageFamily = "Windows Server 2012 R2 Datacenter"

$imageName = Get-AzureVMImage |

where { $_.ImageFamily -eq $imageFamily } |

sort PublishedDate -Descending |

select -ExpandProperty ImageName -First 1

# Replace with a unique cloud service name

$serviceName = "[cloud service name]"

# Specify the admin credentials

$adminUser = "[admin user name]"

$password = "[admin password]"

# Specify the computer name

$vmName = "ps-vm1"

New-AzureQuickVM -Windows `

-ServiceName $serviceName `

-Name $vmName `

-ImageName $imageName `

-Location $location `

-InstanceSize $vmSize `

-AdminUsername $adminUser `

-Password $password

$vmName = "ps-vm2"

$vmConfig = New-AzureVMConfig -Name $vmName `

-InstanceSize $vmSize `

-ImageName $imageName

$vmConfig | Add-AzureProvisioningConfig -Windows `

-AdminUsername $adminUser `

-Password $password

$vmConfig | Add-AzureDataDisk -CreateNew `

-DiskSizeInGB 500 `

-DiskLabel "data 1" `

-LUN 0

$vmConfig | Add-AzureEndpoint -Name "HTTP" `

-Protocol tcp `

-LocalPort 80 `

-PublicPort 80 `

-LBSetName "LBHTTP" `

-DefaultProbe

$vmConfig | Add-AzureEndpoint -Name "HTTPS" `

-Protocol tcp `

-LocalPort 443 `

-PublicPort 443 `

-LBSetName "LBHTTPS" `

-DefaultProbe

New-AzureVM -ServiceName $serviceName -VMs $vmConfig

This script performs the following operations:

1. The script selects your subscription so that any Microsoft Azure cmdlet that is executed afterward runs against the correct subscription.

2. The script then updates your subscription to specify the CurrentStorageAccountName property, which is really just a shortcut so you do not have to specify the storage account to use with each call.

3. The script returns the name of the latest image for the Server 2012 R2 Datacenter image family. This image name is required to tell the Microsoft Azure PowerShell cmdlets which image to use.

4. The script creates a new virtual machine named ps-vm1 by using the New-AzureQuickVM cmdlet. This cmdlet also creates the cloud service container for the virtual machine.

5. The script creates a new virtual machine configuration for a virtual machine named ps-vm2. This configuration has one data disk added and two network endpoints (HTTP and HTTPS).

6. The New-AzureVM cmdlet actually creates the ps-vm2 virtual machine and, by omitting the -Location parameter, creates the virtual machine in the same cloud service as ps-vm1.

Now that you understand what the script is intended to do, simply press F5, or highlight the script and press F8 to execute.

How New-AzureVM Works

The New-AzureVM cmdlet accepts a cloud service name, an array of configuration objects, a location or affinity group, and optionally a virtual network name. Provisioning virtual machines inside a virtual network will be discussed later.

Under the covers, New-AzureVM performs several activities against the Microsoft Azure Service Management API on your behalf. If you specify the -Location or -AffinityGroup parameter, the cmdlet will first create the cloud service container in the location or affinity group you specify. The cmdlet will then loop through the array of virtual machine configuration objects passed to it and create the virtual machines in the cloud service. The New-AzureVM cmdlet performs the serialization required to create multiple virtual machines if passed more than one configuration object. Serialization is required because virtual machines created in the same cloud service or the same virtual network must be created one by one due to locks put in place at the API level.

The New-AzureVM behavior regarding creating a new cloud service or using an existing cloud service depends on the -Location or -AffinityGroup parameters passed to it. If you want the cmdlet to create a new cloud service, simply specify one of the location parameters (-Locationor -AffinityGroup). Passing either of these parameters tells the cmdlet that you want to create a new cloud service in the specified location or affinity group.

To create a virtual machine in an existing cloud service, simply omit the parameters (-Location or -AffinityGroup), and New-AzureVM will assume that the cloud service exists in your subscription and will attempt to create the virtual machine in that cloud service. In the previous code example, -Location was omitted because the cloud service was created with the previous call to New-AzureQuickVM.

CLOUD SERVICE CONFLICTS WITH NEW-AZUREVM

When you run New-AzureVM, you might see: “WARNING: The specified DNS name is already taken.” This means that the -ServiceName you have specified already exists. If the cloud service is part of your subscription and in the same region of the virtual machine you are going to create, you can ignore the warning or simply omit -Location or -AffinityGroup to avoid it altogether. If the cloud service name is owned by another Microsoft Azure subscription, the warning will be followed by an error: “New-AzureVM: ResourceNotFound: The hosted service does not exist.” This is beyond your control, and it is time to pick a new name for your cloud service!

Querying Virtual Machines with Get-AzureVM

The Get-AzureVM cmdlet is very useful for managing virtual machines. It has three distinct behaviors that allow you to perform some fairly advanced operations.

Run Get-AzureVM without passing any parameters, and the cmdlet will enumerate all of the virtual machines in your subscription (see Example 3-26 and Figure 3-5). Depending on how many virtual machines you have, this can be a lengthy operation. The architecture of the Microsoft Azure API requires that the cmdlet query the available virtual machines per cloud service. So if you have 100 cloud services, each with 1 virtual machine, the cmdlet will have to make 100 round-trips to the Microsoft Azure Service Management API.

Example 3-26. Viewing the status of your virtual machines (Console pane)

Get-AzureVM

The Get-AzureVM cmdlet can also return the detailed configuration of one or more virtual machines.

To return detailed configuration, you must specify the cloud service name and optionally the name of the virtual machine (see Example 3-27 and Figure 3-6). If the name of the virtual machine is specified with the -Name parameter, the Get-AzureVM cmdlet will return the configuration for only that virtual machine. If a virtual machine name is not specified, Get-AzureVM returns the configuration for all of the virtual machines in the cloud service.

Example 3-27. Returning virtual machine configuration (Console pane)

Get-AzureVM -ServiceName $serviceName

Querying virtual machine status with Get-AzureVM

Figure 3-5. Querying virtual machine status with Get-AzureVM

Querying virtual machine configuration with Get-AzureVM

Figure 3-6. Querying virtual machine configuration with Get-AzureVM

The detailed configuration can be inspected using standard PowerShell operators or by using helper cmdlets that are part of the Microsoft Azure PowerShell cmdlets (see Examples 3-28 through 3-30, and Figures 3-7 through 3-9).

Example 3-28. Viewing endpoint configuration (Script console)

Get-AzureVM -ServiceName $serviceName | Get-AzureEndpoint

Viewing virtual machine endpoints with Get-AzureEndpoint

Figure 3-7. Viewing virtual machine endpoints with Get-AzureEndpoint

Example 3-29. Viewing data disk configuration

Get-AzureVM -ServiceName $serviceName | Get-AzureDataDisk

Example 3-30. Viewing OS disk configuration (Console pane)

Get-AzureVM -ServiceName $serviceName | Get-AzureOSDisk

Viewing virtual machine data disk configuration with Get-AzureDataDisk

Figure 3-8. Viewing virtual machine data disk configuration with Get-AzureDataDisk

Viewing a virtual machine OS disk configuration with Get-AzureOSDisk

Figure 3-9. Viewing a virtual machine OS disk configuration with Get-AzureOSDisk

Changing a Virtual Machine Configuration

Updating a Microsoft Azure virtual machine is very similar to creating a new one. The difference is that instead of creating a new virtual machine configuration object, you are retrieving an existing configuration from the virtual machine that you want to update.

To retrieve an existing virtual machine configuration, use the Get-AzureVM cmdlet, passing the name of the cloud service and optionally the name of the virtual machine. Once the configuration is retrieved, you then modify it with the changes you want, using the same cmdlets used during creation. To make the final changes, call the Update-AzureVM cmdlet instead of New-AzureVM. Update-AzureVM accepts the cloud service name and the virtual machine name and passes the configuration back to the Microsoft Azure Management API to perform the update.

Using the pattern of Get-Modify-Update, Example 3-31 retrieves the configuration of the specified virtual machine, indicating the cloud service name and the virtual machine name. The configuration is stored in the $vmConfig variable. To modify the configuration, the $vmConfig variable is piped to the Remove-AzureEndpoint cmdlet, which looks in the configuration for an endpoint named RemoteDesktop and removes it if it exists. When the Remove-AzureEndpoint cmdlet has removed the endpoint from the virtual machine configuration, it is then piped to Update-AzureVM, which makes the API call to update the virtual machine.

Example 3-31. Removing an endpoint from a virtual machine (Console pane)

$serviceName = "[cloud service name]"

$vmName = "ps-vm1"

$vmConfig = Get-AzureVM -ServiceName $serviceName -Name $vmName

$vmConfig | Remove-AzureEndpoint -Name "RemoteDesktop"

$vmConfig | Update-AzureVM

REMOTE DESKTOP ENDPOINT NAMES

If you try the previous example against the ps-vm2 virtual machine, the code will not work. Virtual machines created with the New-AzureQuickVM cmdlet name the endpoint RemoteDesktop, and virtual machines created using New-AzureVM use RDP as the endpoint name. In Chapter 4 I will show how to identify endpoints by using the local port instead of the name.

The previous example removes the remote desktop endpoint from the specified virtual machine. Since the endpoint is removed, you can no longer use remote desktop to connect to the virtual machine. You can try this on your own by executing the Get-AzureRemoteDesktopFile cmdlet to attempt a connection (see Example 3-32.

Example 3-32. Connecting to a virtual machine using remote desktop (Console pane)

Get-AzureRemoteDesktopFile -ServiceName $serviceName -Name $vmName -Launch

This can be very useful from a security perspective, as it gives you the ability to open up remote desktop only when needed and remove it when it is not. Later, I will show how to configure an access control list (ACL) to make this even more secure.

Now we will create another simple script that takes the ps-vm1 virtual machine and updates it to have the same network endpoints and data disk configuration that ps-vm2 was provisioned with, since it was created with New-AzureVMConfig. We will also add the RemoteDesktop endpoint back and validate that connectivity works.

Create a new PowerShell script with the name chapter3update.ps1 and add the code in Example 3-33. Ensure that you replace the placeholder values with the actual values for your subscription.

Example 3-33. Updating a virtual machine configuration (Script pane)

Select-AzureSubscription "[subscription name]"

$serviceName = "[cloud service name]"

$vmName = "ps-vm1"

$vmConfig = Get-AzureVM -ServiceName $serviceName -Name $vmName

$vmConfig | Add-AzureEndpoint -Name "RemoteDesktop" `

-LocalPort 3389 `

-Protocol TCP

$vmConfig | Add-AzureDataDisk -CreateNew `

-DiskSizeInGB 500 `

-DiskLabel "data 1" `

-LUN 0

$vmConfig | Add-AzureEndpoint -Name "HTTP" `

-Protocol tcp `

-LocalPort 80 `

-PublicPort 80 `

-LBSetName "LBHTTP" `

-DefaultProbe

$vmConfig | Add-AzureEndpoint -Name "HTTPS" `

-Protocol tcp `

-LocalPort 443 `

-PublicPort 443 `

-LBSetName "LBHTTPS" `

-DefaultProbe

$vmConfig | Update-AzureVM

Press F5 to execute the script, or highlight the script and press F8.

When the script has finished executing, run the Get-AzureRemoteDesktopFile cmdlet again from the console to verify that you can now connect to the virtual machine (see Example 3-34).

Example 3-34. Validating remote desktop connectivity (Console pane)

Get-AzureRemoteDesktopFile -ServiceName $serviceName -Name $vmName -Launch

Stopping and Starting Virtual Machines

The final topic of this chapter is a very important one for your pocketbook: stopping and starting virtual machines.

When you stop a virtual machine in Microsoft Azure using PowerShell or the portal (not from within the virtual machine), you are no longer billed for the compute time used (just for the storage cost for the underlying disks). As part of this book, I will point back to virtual machines created in previous topics and chapters so we don’t have to re-create them with each example. With this in mind, it is likely a good idea to learn how to not be charged for virtual machines when not in use.

Example 3-35 will shut down all of the virtual machines in the cloud service. One of the limitations of Microsoft Azure is that if you shut down the last virtual machine in a cloud service without assigning a reserved IP address to the virtual machine, you will lose the public IP address (VIP) of the cloud service. This is why running the following code will prompt you to ensure that you are aware of this fact.

Example 3-35. Stopping all virtual machines in a cloud service (Console pane)

Get-AzureVM -ServiceName $serviceName | Stop-AzureVM

There are three things you can do to avoid the prompt shown in Figure 3-10:

§ Pass the -Force parameter. This tells the cmdlet to not prompt you.

§ Specify a reserved IP address. This feature will be discussed in more detail in Chapter 4.

§ Pass the -StayProvisioned parameter. This tells the cmdlet to not deprovision the virtual machine and to just shut it down. However, you will still be charged for compute time when you use this switch, so it is not a good solution for saving money.

Warning regarding deployment IP

Figure 3-10. Warning regarding deployment IP

In addition to Stop-AzureVM, there are also Start-AzureVM and Restart-AzureVM. All three cmdlets accept the same -ServiceName and -Name parameters that correspond to the cloud service container name and the virtual machine name. They all accept pipeline output, as shown in the previous example, so you can run them against multiple virtual machines, if needed.

Summary

In this chapter we explored the basics of using the Microsoft Azure PowerShell cmdlets to create and configure a virtual machine. We learned how to use the Get-AzureLocation cmdlet to identify the Microsoft Azure regions that are available for virtual machines, and also to create them using the high-memory configurations.

This chapter also introduced the idea of using the virtual machine configuration object not only to create a virtual machine, but also to update an existing one by modifying the configuration and posting it back to the Microsoft Azure API by using the cmdlets. You will see this Get-Modify-Update pattern used throughout this book, as it is the underlying convention of the Microsoft Azure API and the command-line tools that use it.

In the next chapter we will dig deeper into virtual machine configuration by investigating the network stack in thorough detail from PowerShell.