How to expand or format a VM disk in Azure cloud
Using infrastructure as code and powershell scripts
When using infrastructure as code with a windows server virtual machine, changing the parameters or variables regarding the os_disk_size
or data_disk_size
is not enough. It is necessary to tell the machine to expand or format the disks, which could be done with clicks and buttons, but in our case of using IaC, we'll use a script.
Example 1
Bigger OS disk size using packer image builder
By default, the os disk azure VM is 128 GB. If I want a bigger os disk before creating an image using packer. I can easily change this value on the packer template
"builders": [
{
"use_azure_cli_auth": true,
"type": "azure-arm",
"os_type": "Windows",
"vm_size": 'Standard_D2ds_v5',
"os_disk_size_gb": 256,
This will make the actual OS disk resource with a size of 256, but the machine will not be aware of it.
The following powershell script needs to be included on the provisioners block. It doesn't need any parameters, the sizeMax
property will read what size the disk is, and expand it.
$osDisk = Get-Disk | where IsBoot -eq $true
$size = Get-PartitionSupportedSize -DiskNumber $osDisk.Number -PartitionNumber 2
Resize-Partition -disknumber $osDisk.Number -PartitionNumber 2 -Size $size.SizeMax
Name this file above extendOsDisk.ps1 and include it in the packer template as follows:
"provisioners": [
{ "type": "powershell",
"inline": ["Set-ExecutionPolicy Bypass -Scope Process -Force"]
},
{
"type": "powershell",
"script": "ConfigureRemotingForAnsible.ps1"
},
{
"type": "powershell",
"script": "extendOsDisk.ps1"
},
After this, the image produced by Packer will know its extended OS disk size, and when you create a VM from it, it will always be 256 GB in this case.
Example 2
Create additional data disk for a virtual machine scale set using terraform
Sometimes you may need an extra Data disk besides the space allocated on the OS disk. Adding this block in terraform resources will create the data disk, or data disks, but the machine will not be aware of it and you won't be able to use it until it's formatted.
resource "azurerm_windows_virtual_machine_scale_set" "base_scaleset" {
...
data_disk {
lun = 0
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
disk_size_gb = var.data_disk_size
}
...
In this case, the script to format one or more data disks is provided directly by Microsoft's Github here
$disks = Get-Disk | Sort Number
# 83..89 = S..Y
$letters = 83..89 | ForEach-Object { [char]$_ }
$count = 0
$label = "datadisk"
for($index = 2; $index -lt $disks.Count; $index++) {
$driveLetter = $letters[$count].ToString()
if ($disks[$index].partitionstyle -eq 'raw') {
$disks[$index] | Initialize-Disk -PartitionStyle MBR -PassThru |
New-Partition -UseMaximumSize -DriveLetter $driveLetter |
Format-Volume -FileSystem NTFS -NewFileSystemLabel "$label.$count" -Confirm:$false -Force
} else {
$disks[$index] | Get-Partition | Set-Partition -NewDriveLetter $driveLetter
}
$count++
}
To include a script to be run on a terraform resource, one option is to use an extension resource on the same terraform file, and use the script directly from github as raw, it would look like this
resource "azurerm_virtual_machine_scale_set_extension" "format_data_disk" {
name = "format_data_disk"
virtual_machine_scale_set_id = azurerm_windows_virtual_machine_scale_set.base_scaleset.id
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
settings = jsonencode({
"fileUris": [
"https://raw.githubusercontent.com/Azure-Samples/compute-automation-configurations/master/prepare_vm_disks.ps1"
],
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File prepare_vm_disks.ps1"
})
depends_on = [
azurerm_windows_virtual_machine_scale_set.base_scaleset
]
}
After deploying these resources together, the virtual machine scale set on azure will have its disk formatted and ready to use on the path S:/