Provisioning an Azure Virtual Machine with PowerShell

*If you're just joining us, this post is part of a series on Getting Started with PowerShell. If you'd like to catch up (or skip ahead), click on the appropriate post below.

Getting Started with PowerShell
Windows PowerShell, PowerShell Core and PowerShell: Huh?
Installing PowerShell and Visual Studio Code
Running PowerShell Commands and Getting Help
Working with the PowerShell Pipeline
Writing your First PowerShell Script
Understanding Loops in PowerShell
Using PowerShell Modules
Connecting to Azure
PowerShell Error Handling
Building PowerShell Functions

For the final PowerShell article in our series, let's bring all of that knowledge together and put it to good use. If you've read the other articles in this series, your wheels should already be spinning thinking of all the tasks you can manage and automate with PowerShell. PowerShell a universal scripting language that can work with just about anything.

Even though you could automate anything with PowerShell, let's keep this last article/tutorial in the Azure space. More specifically, let's see how PowerShell and the Azure PowerShell module by Microsoft can automate the task of creating an Azure virtual machine (VM) from scratch.

Prerequisites

To ensure you can follow along with everything you're (hopefully) going to learn, you should first have a few prerequisites in place. If not, you're won't be able to follow along.

You will need:

  • An Azure subscription

  • PowerShell (Core) - Although you could follow along with this tutorial with Windows PowerShell, you should know by now it's no longer being actively developed by Microsoft. Instead, be sure you have PowerShell (Core) installed. Learn how to install PowerShell (Core) in a previous post in our series <link here>.

  • To have already authenticated to Azure (For instructions on connecting to Azure, check out this post<link here> in our series on how to do that)

  • Authenticated with an account with permission to create an Azure VM and all of it's necessary components like a vNet, storage, etc.

  • A code editor - You should use Visual Studio Code <link here to previous post> for your PowerShell code editor but any editor will do. The tutorial will assume you're using Visual Studio Code.

Project Overview

This tutorial will be presented in a project format. To use all the skills you've learned in this blog post series and learn more a few more PowerShell tricks, you're going to build a real-world script. This script will create an Azure virtual machine. It may sound easy at first but there's a lot that goes into an Azure VM.

An Azure VM not only consists of a lot more than just a VM but also has various dependencies like a network and a storage account. We're going to assume you have none of that and create everything from scratch.

More specifically, you're going to learn how to:

  1. Create a resource group to place all of the resources you'll be building in.

  2. Create a virtual network that the VM will attach to.

  3. Create a storage account that will hold the VM's disk.

  4. Create a public IP address to connect to the VM.

  5. Create a VM's network interface (vNic).

  6. Define the OS disk image for the VM to use.

  7. Create the VM.

  8. Stop the VM.

Wheww, that's a lot of work ahead of us! Don't worry though. Automating a process always takes work upfront but over time, you'll save many hours.

Download the Script

Throughout this tutorial, you will be running a lot of code in the form of snippets with explanations. All of this code will come from a pre-built script available here. Download it and play on your own if you'd like. Otherwise, once you've downloaded the script, stick around and we'll walk through each step.

Splatting

Before we get too far, you might see something unfamiliar in this tutorial's script. Take a look at the following code snippet. You'll see a different way of passing parameters to commands you may not be used to. This is called splatting.

Splatting is a way to pass parameters to PowerShell commands not by specifying parameter values on the same line as the command but by first defining a hashtable and passing all of the parameters to the command at once.

You will see many instances of splatting in the script you're learning from. There's nothing fancy going on here. It's just another way of providing parameter values to PowerShell commands.

Building the Script

It's finally time to dive into the script so let's get started.

  • Because the script is referencing a few common strings, first define these as variables sooner than later.

 
$resourceGoupName = 'skylinespsdemo'
$azureRegion = 'East US'
$vmName = 'MYVM'
  • Create the Azure resource group using the New-AzResourceGroup cmdlet.

 
New-AzResourceGroup -Name $resourceGoupName -Location $azureRegion
  • Create the vNet. To do this, you'll see in the following snippet you first must define the subnet that will go inside of the vNet first. Then, using the New-AzVirtualNetwork cmdlet, you will pass that subnet object to the command to create the vNet.

 
$newSubnetParams = @{
    'Name'          = 'MySubnet'
    'AddressPrefix' = '10.0.1.0/24'
}
$subnet = New-AzVirtualNetworkSubnetConfig @newSubnetParams

$newVNetParams = @{
    'Name'              = 'MyNetwork'
    'ResourceGroupName' = $resourceGoupName
    'Location'          = $azureRegion
    'AddressPrefix'     = '10.0.0.0/16'
}
$vNet = New-AzVirtualNetwork @newVNetParams -Subnet $subnet
  • Create the storage account. Be sure to change the name of the storage account. Also, the type the following example uses is Standard_LRS. This isn't mandatory. You can also choose from other types if you wish.

 
$newStorageAcctParams = @{
    'Name'              = 'skylinesdemo1' ## Must be globally unique and all lowercase
    'ResourceGroupName' = $resourceGoupName
    'Type'              = 'Standard_LRS'
    'Location'          = $azureRegion
}
$storageAccount = New-AzStorageAccount @newStorageAcctParams
  • Create the public IP address. VMs don't have to have public IP addresses but if you'd like to connect to it from the Internet, you'll need one.

 
$newPublicIpParams = @{
    'Name'              = 'MyNIC'
    'ResourceGroupName' = $resourceGoupName
    'AllocationMethod'  = 'Dynamic' ## Dynamic or Static
    'DomainNameLabel'   = 'test-domain'
    'Location'          = $azureRegion
}
$publicIp = New-AzPublicIpAddress @newPublicIpParams
  • Create the VM's network interface. You can see in the following snippet that we're using the virtual network created earlier. The object returned from the New-AzVirtualNetwork cmdlet included a property called Subnets. This property is a collection of other objects. Referencing [0] allows you to find the first object in that collection. Once that object is determined, the code is then referencing the Id property.

 
$newVNicParams = @{
    'Name'              = 'MyNic'
    'ResourceGroupName' = $resourceGoupName
    'Location'          = $azureRegion
}
$vNic = New-AzNetworkInterface @newVNicParams -SubnetId $vNet.Subnets[0].Id -PublicIpAddressId $publicIp.Id
  • Define OS-related information. This is done with two commands as you can see below. Notice the Credential parameter. The code is using the Get-Credential cmdlet to interactively ask for a PSCredential object. Once you provide a username and password, that information will then be passed to Set-VMOperatingSystem.


    Also notice the output of Set-VMOperatingSystem is being sent to the $vm variable. This will be a variable that holds nearly all of the information related to this VM to create. You'll add to this a lot throughout the steps.

 
$newConfigParams = @{
    'VMName' = $vmName
    'VMSize' = 'Standard_A3'
}
$vmConfig = New-AzVMConfig @newConfigParams

$newVmOsParams = @{
    'Windows'          = $true
    'ComputerName'     = $vmName
    'Credential'       = (Get-Credential -Message 'Type the name and password of the local administrator account.')
    'ProvisionVMAgent' = $true
    'EnableAutoUpdate' = $true
}
$vm = Set-AzVMOperatingSystem @newVmOsParams -VM $vmConfig
  • Define the operating system to use. Below you can see that the VM will be Windows Server 2019. The code is overwriting the previous $vm variable adding more information to it.

 
$newSourceImageParams = @{
    'PublisherName' = 'MicrosoftWindowsServer'
    'Version'       = 'latest'
    'Skus'          = '2019-Datacenter'
}

$vm = Set-AzVMSourceImage @newSourceImageParams -VM $vm -Offer 'WindowsServer'
  • "Attach" the vNic to the VM. You created the vNic above but now's the time to attach it to the VM.

 
$vm = Add-AzVMNetworkInterface -VM $vm -Id $vNic.Id
  • Define the operating system disk. In the code below, you'll notice one semi-complicated code snippet to define the OS disk's URI. The Set-AzVMOSDisk cmdlet defines the OS disk and it has a mandatory VhdUri parameter. This URI is where the OS disk VHD will be created.

    Here is where you use the $storageAccount variable from the New-AzStorageAccount cmdlet ran earlier. Using string concatenation, we're able to craft a URI that the VhdUri cmdlet needs.

 
$osDiskName = 'myDisk'
$osDiskUri = $storageAccount.PrimaryEndpoints.Blob.ToString() + "vhds/" + $vmName + $osDiskName + ".vhd"

$newOsDiskParams = @{
    'Name'         = 'OSDisk'
    'CreateOption' = 'fromImage'
}

$vm = Set-AzVMOSDisk @newOsDiskParams -VM $vm -VhdUri $osDiskUri
  • Finally, you can create the VM. Notice how you're essentially only using the $vm object. All throughout this script, you were either creating Azure resources or defining all of the instructions to create the VM and adding them to the $vm object.

 
New-AzVM -VM $vm -ResourceGroupName $resourceGoupName -Location $azureRegion

Cleaning Up

To ensure you don't accidentally forget to shut off the VM you just created, let's clean up everything. Throughout the script, you created a lot of resources in Azure but thankfully, they were all created in the same resource group.

Now clean everything up with a single PowerShell command.

Remove-AzResourceGroup -Name $resourceGoupName -Force

Blog Series Conclusion

If you stuck around for each post in this series, thank you! You should have learned the basics of PowerShell and got an idea on what you can do in your own environment.

Know that PowerShell is capable of automating lots of tasks. In an article series like this, we had to choose a few examples to demonstrate concepts. Don't think that whatever was covered in this series is all there is - it definitely is not.

As a PowerShell developer of nearly 10 years, I can tell you that anything can be automated with PowerShell if you try hard enough. I encourage you to come up with some tasks in your environment you're tired of doing manually and see what kind of automation scripts you can come up with!

 
Adam Bertram

About the Author

Hi, I'm Adam. I'm a 20+ year veteran of IT and experienced online business professional. I'm an entrepreneur, IT influencer, Microsoft MVP, blogger, trainer, author and content marketing writer for multiple technology companies.

Follow me on my blog, Twitter, LinkedIn

 
Previous
Previous

Getting started with Terraform for Azure

Next
Next

New Microsoft DP-900 Certification Course