Automating tasks in Azure can save significant time and effort, especially when deploying resources like virtual machines (VMs). In this blog post, we’ll walk through automating the deployment of a Windows VM in Azure using PowerShell. We’ll configure networking, security, and install IIS for a web server all in one script.
Why Automate VM Deployment?
Automating tasks such as virtual machine deployment ensures consistency, reduces errors, and accelerates the setup process. With PowerShell, you can define all the necessary parameters and let the script handle the deployment, instead of manually creating each resource via the Azure Portal.
Here’s a step-by-step breakdown of the PowerShell script used to deploy an Azure VM, configure networking, set security rules, and install IIS.
Here’s the script if you just want to download it.
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ResourceGroupName = 'Admissions',
[Parameter(Mandatory)]
[string]$Location = 'East US',
[Parameter(Mandatory)]
[string]$VMName = 'ADMISSIONSWEB',
[Parameter(Mandatory)]
[string]$VMSize = 'Standard_DS3_v2',
[Parameter(Mandatory)]
[string]$PublicIPName = 'Admissions-PubIp',
[Parameter(Mandatory)]
[string]$NICName = 'Admissions-vNIC',
[Parameter(Mandatory)]
[string]$OSDiskName = 'Admissions-OSDisk',
[Parameter(Mandatory)]
[string]$NSGName = 'ADMISSIONSWEB-NSG',
[Parameter(Mandatory)]
[string]$AdminUsername = 'adam',
[Parameter(Mandatory)]
[SecureString]$AdminPassword = (ConvertTo-SecureString 'P@$$w0rd12' -AsPlainText -Force)
)
$ErrorActionPreference = 'Stop'
function CreateAzResource {
param(
[Parameter(Mandatory)]
[string]$ResourceType,
[Parameter(Mandatory)]
[string]$Name,
[Parameter(Mandatory)]
[hashtable]$NewParameter
)
try {
$resource = & "Get-Az$ResourceType" -Name $Name -ResourceGroupName $NewParameter.ResourceGroupName
} catch {
if ($_.Exception.Message -match "under resource group '.*' was not found") {
$resource = & "New-Az$ResourceType" @NewParameter
} else {
throw $_
}
} finally {
$resource
}
}
#region VM Configuration
$vmconfig = New-AzVMConfig -VMName $VMName -VMSize $VMSize
#endregion
#region Public IP Creation
$newPublicIpParams = @{
Name = $PublicIPName
ResourceGroupName = $ResourceGroupName
AllocationMethod = 'Static'
Location = $Location
}
$publicIp = CreateAzResource -ResourceType PublicIpAddress -Name $PublicIPName -NewParameter $newPublicIpParams
#endregion
#region Network Interface Configuration
$vNet = Get-AzVirtualNetwork -ResourceGroupName $ResourceGroupName
$subnetId = $vNet.Subnets[0].Id
$newVNicParams = @{
Name = $NICName
ResourceGroupName = $ResourceGroupName
Location = $Location
SubnetId = $subnetId
PublicIpAddressId = $publicIp.Id
}
$vNic = CreateAzResource -ResourceType NetworkInterface -Name $NICName -NewParameter $newVNicParams
#endregion
#region OS Configuration
$cred = New-Object System.Management.Automation.PSCredential ($AdminUsername, $AdminPassword)
$newVmOsParams = @{
Windows = $true
ComputerName = $VMName
Credential = $cred
EnableAutoUpdate = $true
VM = $vmconfig
}
$vm = Set-AzVMOperatingSystem @newVmOsParams
#endregion
#region Image Configuration
$newSourceImageParams = @{
PublisherName = 'MicrosoftWindowsServer'
Offer = 'WindowsServer'
Skus = '2019-Datacenter'
Version = 'latest'
VM = $vm
}
$vm = Set-AzVMSourceImage @newSourceImageParams
#endregion
#region Disk Configuration
$vm = Set-AzVMOSDisk -VM $vm -Name $OSDiskName -CreateOption FromImage
#endregion
#region Network Interface Attachment
$vm = Add-AzVMNetworkInterface -VM $vm -Id $vNic.Id
#endregion
#region NSG Configuration
$newNsgParams = @{
ResourceGroupName = $ResourceGroupName
Location = $Location
Name = $NSGName
}
$nsg = CreateAzResource -ResourceType NetworkSecurityGroup -Name $NSGName -NewParameter $newNsgParams
$ruleExists = $nsg.SecurityRules.Name -contains "Allow-RDP"
if (-not $ruleExists) {
$ip = Invoke-RestMethod -Uri "https://api.ipify.org"
$rdpRule = New-AzNetworkSecurityRuleConfig -Name "Allow-RDP" -Description "Allow RDP" -Access Allow -Protocol Tcp -Direction Inbound -Priority 1000 -SourceAddressPrefix $ip -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389
$nsg.SecurityRules.Add($rdpRule)
$nsg | Set-AzNetworkSecurityGroup
}
#endregion
#region Web Traffic Rule Configuration
$webRuleExists = $nsg.SecurityRules.Name -contains "Allow-Web"
if (-not $webRuleExists) {
$webRule = New-AzNetworkSecurityRuleConfig -Name "Allow-Web" -Description "Allow HTTP" -Access Allow -Protocol Tcp -Direction Inbound -Priority 200 -SourceAddressPrefix * -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 80
$nsg.SecurityRules.Add($webRule)
$nsg | Set-AzNetworkSecurityGroup
}
#endregion
$vNic.NetworkSecurityGroup = $nsg
$vNic | Set-AzNetworkInterface
#region VM Creation
$newVmParams = @{
ResourceGroupName = $ResourceGroupName
VM = $vm
Location = $Location
}
CreateAzResource -ResourceType VM -Name $VMName -NewParameter $newVmParams
#endregion
#region IIS Installation
$installIIS = {
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
}
$installScript = [scriptblock]::create($installIIS)
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName -VMName $VMName -CommandId 'RunPowerShellScript' -ScriptString $installScript
#endregion
#region Output Public IP
$publicIp.IpAddress
Define Parameters
The script starts by defining parameters that will be used throughout the deployment. These include basic information such as resource group, VM name, location, and admin credentials. Using parameters ensures the script is flexible and can be reused for different environments.
param(
[Parameter(Mandatory)]
[string]$ResourceGroupName = 'Admissions',
[Parameter(Mandatory)]
[string]$Location = 'East US',
[Parameter(Mandatory)]
[string]$VMName = 'ADMISSIONSWEB',
[Parameter(Mandatory)]
[string]$VMSize = 'Standard_DS3_v2',
[Parameter(Mandatory)]
[string]$PublicIPName = 'Admissions-PubIp',
[Parameter(Mandatory)]
[string]$NICName = 'Admissions-vNIC',
[Parameter(Mandatory)]
[string]$OSDiskName = 'Admissions-OSDisk',
[Parameter(Mandatory)]
[string]$NSGName = 'ADMISSIONSWEB-NSG',
[Parameter(Mandatory)]
[string]$AdminUsername = 'adam',
[Parameter(Mandatory)]
[SecureString]$AdminPassword = (ConvertTo-SecureString 'P@$$w0rd12' -AsPlainText -Force)
)
Creating Azure Resources
The `CreateAzResource` function helps create various Azure resources like public IPs, network interfaces, and network security groups (NSGs). It attempts to get a resource and creates it if it doesn’t exist, making the process more efficient.
function CreateAzResource {
param(
[Parameter(Mandatory)]
[string]$ResourceType,
[Parameter(Mandatory)]
[string]$Name,
[Parameter(Mandatory)]
[hashtable]$NewParameter
)
try {
$resource = & "Get-Az$ResourceType" -Name $Name -ResourceGroupName $NewParameter.ResourceGroupName
} catch {
if ($_.Exception.Message -match "not found") {
$resource = & "New-Az$ResourceType" @NewParameter
} else {
throw $_
}
} finally {
$resource
}
}
VM Configuration and Networking Setup
Once resources like public IP and virtual networks are created, the script configures a virtual machine (VM) using `New-AzVMConfig`, attaches a network interface, and sets up the operating system and disk.
$vmconfig = New-AzVMConfig -VMName $VMName -VMSize $VMSize
$vNic = CreateAzResource -ResourceType NetworkInterface -Name $NICName -NewParameter $newVNicParams
$vm = Set-AzVMOperatingSystem @newVmOsParams
$vm = Set-AzVMSourceImage @newSourceImageParams
$vm = Set-AzVMOSDisk -VM $vm -Name $OSDiskName -CreateOption FromImage
Configuring Network Security Rules
The script adds security rules to the NSG to allow inbound RDP (Remote Desktop) and web traffic on port 80 (HTTP). This is critical for managing the VM and hosting web applications.
$ruleExists = $nsg.SecurityRules.Name -contains "Allow-RDP"
if (-not $ruleExists) {
$ip = Invoke-RestMethod -Uri "https://api.ipify.org"
$rdpRule = New-AzNetworkSecurityRuleConfig -Name "Allow-RDP" -Access Allow -Protocol Tcp -SourceAddressPrefix $ip -DestinationPortRange 3389
$nsg.SecurityRules.Add($rdpRule)
$nsg | Set-AzNetworkSecurityGroup
}
Installing IIS
After the VM is created, the script installs IIS (Internet Information Services), which will allow the VM to act as a web server. This is done by executing a PowerShell command on the VM.
$installIIS = {
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
}
Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName -VMName $VMName -CommandId 'RunPowerShellScript' -ScriptString $installIIS
Output the Public IP
Finally, the public IP of the VM is outputted for easy access to the web server.
$publicIp.IpAddress
Conclusion
With this PowerShell script, deploying a Windows VM on Azure with configured networking, security, and IIS setup becomes seamless. This level of automation is invaluable for repetitive tasks and ensures that your infrastructure is set up consistently.
By following this guide, you can deploy VMs quickly and focus more on configuring applications rather than spending time manually setting up resources.