Expand-SCVirtualMachineOSDisk.ps1

#requires -module VirtualMachineManager

<#PSScriptInfo
 
.Version
    1.0
.Guid
    1badb9c5-8b26-4184-ab23-9e2de92306e7
.Author
    Thomas Malkewitz @dotps1
.Tags
    WindowsStore, Registry
.ProjectUri
    https://github.com/dotps1/PSFunctions
.ReleaseNotes
    Initial Release.
.ExternalModuleDependencies
    VirtualMachineManager
 
#>


<#
 
.SYNOPSIS
    Expands the OS Drive of a Virtual Machine.
.DESCRIPTION
    Using information from Virtual Machine Manager and CIM, this cmdlet adds space to the virtual machines vhdx file and expands the partion.
.INPUTS
    System.String
    System.Int
.OUTPUTS
    System.Management.Automation.PSCustomObject
.PARAMETER Name
    System.String
    The name of the Virtual Machine to perform the expansion against.
.PARAMETER AmmountToAddGB
    System.Int
    The ammount of disk space to add in GB.
    Default Value: 10
.PARAMETER MinimumFreeSpaceGB
    System.Int
    The ammount of minimum free space on the disk required before the operation is performed.
    Default Value: 10
.NOTES
    If the system recovery partion is located on the disk after the OS partition, it will be removed.
.EXAMPLE
    PS C:\> Expand-SCVirtualMachineOSDisk -Name MyVirtualMachine
 
    Name: MyVirtualMachine
    OSDriveLetter: C
    OSPartitionPreviousSizeGB: 40
    OSPartitionNewSizeGB: 50
.EXAMPLE
    PS C:\> "MyVirtualMachine" | Expand-SCVirtualMachineOSDisk -AmmountToAddGB 25
 
    Name: MyVirtualMachine
    OSDriveLetter: C:
    OSPartitionPreviousSizeGB: 25
    OSPartitionNewSizeGB: 50
.LINK
    https://dotps1.github.io
 
#>



[CmdletBinding(
    ConfirmImpact = "High"
)]
[OutputType(
    [System.Management.Automation.PSCustomObject]
)]

param (
    [Parameter(
        Mandatory = $true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true
    )]
    [Alias(
        'ComputerName'
    )]
    [String[]]
    $Name,

    [Parameter()]
    [Int]
    $AmountToAddGB = 10,

    [Parameter()]
    [Int]
    $MinumumFreeSpaceGB = 10
)

process {
    foreach ($nameValue in $Name) {
        $vm = $null
        $vm = Get-SCVirtualMachine -Name $nameValue
        if ($null -eq $vm) {
            Write-Warning -Message "Virtual Machine '$($vm.Name)' does not exist in VMM, please ensure the host and the guest are in the VMM database."
        } else {
            $osHardDisk = Get-SCVirtualHardDisk -VM $vm | Where-Object { $_.ID -eq $vm.OSDiskID }
            $osDiskDrive = Get-SCVirtualDiskDrive -VM $vm | Where-Object { $_.VirtualHardDiskId -eq $vm.OSDiskID }
            if ($null -ne $osHardDisk -and $null -ne $osDiskDrive) {
                $osHardDiskFreeSpace = [Math]::Round( ($osHardDisk.MaximumSize - $osHardDisk.Size) / 1GB )

                # If the freespace is less then the minimum free space specified, add space to existing OSDrive.
                if ($osHardDiskFreeSpace -lt $MinumumFreeSpaceGB) {
                    try {
                        Expand-SCVirtualDiskDrive -VirtualDiskDrive $osDiskDrive -VirtualHardDiskSizeGB ( [Math]::Round( ($osHardDisk.MaximumSize / 1GB) ) + $AmountToAddGB ) -ErrorAction Stop | Out-Null
                    } catch {
                        $PSCmdlet.ThrowTerminatingError(
                            $_
                        )

                        continue
                    }
                } else {
                    Write-Warning "Virtual Machine '$($vm.Name)' has $osHardDiskFreeSpace avaiable."

                    continue
                }

                if ($vm.Generation -ne 2) {
                    Write-Warning -Message "Virtual Machine '$($vm.Name)' is not generation 2, and the volume will need to be manually expanded."
                } else {
                    # Expand the partition via CIM.
                    try {
                        $cimSession = New-CimSession -ComputerName $vm
                    } catch {
                        $PSCmdlet.ThrowTerminatingError(
                            $_
                        )

                        continue
                    }

                    $osDriveLetter = (Get-CimInstance -CimSession $cimSession -ClassName Win32_OperatingSystem).SystemDirectory.SubString( 0,1 )
                    $osPartition = Get-Partition -CimSession $cimSession -DriveLetter $osDriveLetter
                    $recoveryPartition = Get-Partition -CimSession $cimSession | Where-Object { $_.Type -eq 'Recovery' }
                    if ($null -ne $recoveryPartition -and $recoveryPartition.PartitionNumber -gt $osPartition.PartitionNumber) {
                        if ($recoveryPartition.Size -lt 1GB) {
                            Write-Warning "Removing Recovery partition from '$($vm.Name)' to allow for the partition expansion."
                            Remove-Partition -CimSession $cimSession -InputObject $recoveryPartition -Confirm:$false
                        }
                    }

                    $partitionSizeMax = (Get-PartitionSupportedSize -CimSession $cimSession -DriveLetter $osDriveLetter).SizeMax
                    Resize-Partition -CimSession $cimSession -DriveLetter $osDriveLetter -Size $partitionSizeMax
                    $osPartitionNewSize = Get-Partition -CimSession $cimSession -DriveLetter $osDriveLetter | Select-Object -ExpandProperty Size

                    Remove-CimSession -CimSession $cimSession

                    [PSCustomObject]@{
                        Name = $vm.Name
                        OSDriveLetter = $osDriveLetter
                        OSPartiontType = $osPartition.Type
                        OSPartitionPreviousSizeGB = ( [Math]::Round(( $osPartition.Size / 1GB )))
                        OSPartitionNewSizeGB = ( [Math]::Round(( $osPartitionNewSize / 1GB )))
                    } | Write-Output
                }
            }
        }
    }
}