Craig Forrester

The Pleasure of Finding Things Out

github linkedin email rss
Resize an Azure VM Windows OS Partition
August 8, 2018
6 minutes read

Important

As always, this post is provided “as-is” without any warranty of any kind, and contains operations which can irrevocably destroy data on your systems. Your systems, storage, and other devices may have configurations or edge cases I have not accounted for here. Take great care and test these commands and any resulting scripts you create in lab/test/development environments to avoid catastrophic data loss.

It is a good idea to perform a full data backup or take a snapshot prior to performing potentially destructive operations.

You have been warned!

In the two previous posts in this series, we covered how to resize an Azure VM disk with Azure CLI and how to resize Azure VM disks with PowerShell. If you were following closely, you will have noticed that we did not address one key final task: resizing the partition within the guest OS on the VM. I did not include it for two reasons. First, depending on what kind of OS you are running in your VM (e.g., Windows or Linux), your method for resize a partition will vary. Second, shorter posts are a little easier to digest than long one.

There are two major OS types on which you are likely to resize a partition in Azure — Windows and Linux. In this post, we will cover Windows, in the next post in this series, we’ll cover how to resize a partition on Linux.

Resize the Partition

In order to benefit from resizing an Azure VM disk, we need to resize the partition of the disk within the guest operating system on the virtual machine. On Windows, this is as simple as running the following PowerShell command lines:

$drive_letter = 'C'

$MaxSize = (Get-PartitionSupportedSize -DriveLetter $drive_letter).sizeMax

Resize-Partition -DriveLetter $drive_letter -Size $MaxSize

The preceding partition cmdlets are available starting with Windows Server 2012.

This is all well and good if we know the drive letter we want to expand, but what we want is a solution that will work for any circumstance with any drive letter.

The simplest solution when we don’t know the drive letter is simply to cycle through all the local disks and check whether they need expanding or not. This has the added advantage of covering cases where we may have expanded multiple drives as well.

If we simply use Get-Partition by itself, we will get a list of every partition, including ones that have no drive letter and we don’t want to touch those, if there are any. So, we will need to filter the output of Get-Partition down to only those partitions with drive letters, as follow:

Get-Partition | where { $_.DriveLetter -gt 0 } 

You may initially try -ne $empty or -ne $null or even -ne '' where we have -gt 0 here, but if you try that out, you’ll see that you still get partitions without drive letters.

Now that we have a list of partitions with drive letters associated, we need to go through each of them one by one and compare their current size with the maximum supported size. If the two are not equal — if the SizeMax property of the partition is greater than the Size property of the existing drive – we call Resize-Partition to expand the partition and underlying volume, using the bits of code I showed earlier:

$drives = Get-Partition | where { $_.DriveLetter -gt 0 } 

foreach ($drive in $drives) { 
    Get-PartitionSupportedSize -DriveLetter $drive.DriveLetter | 
        where { $_.SizeMax -gt $drive.Size } |
        foreach {
            Resize-Partition -DriveLetter $drive.DriveLetter -Size $_.SizeMax
        }
}

Notice a couple of things here. First, note that the body of the first foreach loop is actually one long command line, with the individual sections broken up at the pipe character for better legibility (PowerShell allows us to break lines of code up on several key characters, the pipe | being one of them). The second thing to notice is that the call to Resize-Partition here is almost exactly what we saw in the very first example, but we have simply replaced the variables with those that we are using in our foreach loop.

Expansion Failure

Before we move on, I should point out a strange edge case that I tripped over in my own testing. Namely, if the current size of the partition is less than 1 MB difference from the maximum partition size, the call to Resize-Partition will fail with an error like the following.

Example:

Resize-Partition : Size Not Supported
At line:6 char:13
+             Resize-Partition -DriveLetter $drive.DriveLetter -Size $_.SizeMax
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (StorageWMI:ROOT/Microsoft/.../MSFT_Partition) [Resize-Partition], CimException
    + FullyQualifiedErrorId : StorageWMI 4097,Resize-Partition

The work-around to this behavior was provided by user Vortex100 on a Reddit forum post: Shrink the partition by 1 MB first, then expand it to the maximum size. In order for us to do this, we need to add another conditional to our code:

$drives = Get-Partition | where { $_.DriveLetter -gt 0 } 

foreach ($drive in $drives) { 
    Get-PartitionSupportedSize -DriveLetter $drive.DriveLetter | 
        where { $_.SizeMax -gt $drive.Size } |
        foreach {

            # Special handling for size differences less
            # than 1 MB to avoid 'Size Not Supported' error

            $difference = $_.SizeMax - $drive.Size

            if ($difference -lt 1mb) {

                $shrink = $drive.Size - 1mb

                Resize-Partition `
                    -DriveLetter $drive.DriveLetter `
                    -Size $shrink

            }

            Resize-Partition `
                -DriveLetter $drive.DriveLetter `
                -Size $_.SizeMax
        }
}

Note that I have placed the expansion operation following if statement to do the shrinking operation without an else clause, because we want to perform the expansion every time, regardless of whether or not we need to shrink first to avoid the error.

Formatting New Volumes

There may be situations where you need both to resize the partition and format a volume on that partition as well — for example, when you attach a new disk to a virtual machine. Or you may encounter a case where you’ve expanded a disk that was never formatted. In either case, it’s convenient to do both in the same script.

The first thing we want to do is get a list of disks whose partitions are RAW, which means that they have no partitions and are unformatted. You do not want to simply format any volume that doesn’t have a drive letter, as there are many cases where valid volumes exist that have no drive letter, such as certain system and recovery volumes.

$disks = Get-Disk | where { $_.PartitionStyle -eq 'RAW' }

Next, we want to loop through all of those RAW disks and do three things:

  1. Initialize the disk.
  2. Create a new partition that takes up the entire disk.
  3. Format the new partition.
foreach ($disk in $disks) {
    Initialize-Disk -InputObject $disk
    $part = New-Partition -InputObject $disk `
                -UseMaximumSize -AssignDriveLetter 
    Format-Volume -Partition $part -FileSystem NTFS -Confirm:$false
}

Unless you have a particular need to use another, NTFS is the recommended file system.

That’s all there is to it for about 9 out of 10 cases you’ll typically encounter.

Additional Reading


Back to posts