DSCResources/POSHOrigin_vSphere_VM/Helpers/_SetGuestDisks.ps1

function _SetGuestDisks{
    [cmdletbinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNull()]
        $vm,

        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$DiskSpec,

        [Parameter(Mandatory)]
        [Microsoft.Management.Infrastructure.CimSession]$CimSession,

        [Parameter(Mandatory)]
        [System.Management.Automation.Runspaces.PSSession]$PSSession
    )

    begin {
        Write-Debug -Message 'Starting _SetGuestDisks()'
    }

    process {
        try {
            $desiredDiskConfigMapping = _GeConfigDiskToVMDiskMapping -vm $vm -DiskSpec $DiskSpec

            # Let's do a sanity check first.
            # Make sure we passed in valid values for the block size
            # If we didn't, let's stop right here
            $blockSizes = @(
                4096, 8192, 16386, 32768, 65536
            )
            $desiredDiskConfigMapping | foreach {
                # Set default block size
                if ($_.BlockSize -eq $null) {
                    $_.BlockSize = 4096
                }
                if ($blockSizes -notcontains $_.BlockSize) {
                    Write-Error -Message 'Invalid block size passed in. Aborting configuration the disks'
                    break
                }
            }
            # $opt = New-CimSessionOption -Protocol DCOM
            # $cim = New-CimSession -ComputerName $ip -Credential $Credential -SessionOption $opt -Verbose:$false
            # $session = New-PSSession -ComputerName $ip -Credential $credential -Verbose:$false

            # Get mapped disks between the guest and VMware
            $guestDiskMapping = _GetGuestDiskToVMDiskMapping -VM $vm -CimSession $CimSession
            $os = _GetGuestOS -CimSession $CimSession

            if ($os -ge 62) {
                $disks = Invoke-Command -Session $PSSession -ScriptBlock { Get-Disk } -Verbose:$false
            } else {
                $disks = Get-CimInstance -ClassName CIM_DiskDrive -CimSession $CimSession -Verbose:$false | Select -Property *
            }

            # Rename CDROM to Z:
            _RenameCDROM -CimSession $CimSession -DriveLetter 'Z'

            # Format each disk according to instructions
            foreach ($config in $desiredDiskConfigMapping) {

                # Do we have a matching guest disk
                $guestDisk = $guestDiskMapping |
                 Where-Object {(($_.HasSN) -and ($_.SerialNumber -eq $config.SerialNumber)) -or ((!$_.HasSN) -and ($_.SCSIBus -eq $config.SCSIController -and $_.SCSIUnit -eq $config.SCSITarget))} |
                    Select-Object -First 1

                if ($guestDisk) {

                    if ($os -ge 62) {
                        $disk = $disks | Where-Object {$_.Number -eq $guestDisk.WindowsDisk} | Select-Object -First 1
                    } else {
                        $disk = $disks | Where-Object {$_.Index -eq $guestDisk.WindowsDisk} | Select-Object -First 1
                    }

                    if ($disk) {

                        # Format / Initialize disk
                        $formatParams = @{
                            Disk = $disk
                            PSSession = $PSSession
                            PartitionStyle = 'GPT'
                            VolumeName = $config.VolumeName
                            VolumeLabel = $config.VolumeLabel
                            AllocationUnitSize = $config.BlockSize
                        }
                        if ($os -ge 62) {
                            _FormatGuestDisk @formatParams
                        } else {
                            _FormatOldGuestDisk @formatParams
                        }
                        Write-Debug -Message "Formatting disk [$($guestDisk.WindowsDisk)]complete"
                    } else {
                        Write-Verbose -Message "Could not find guest disk [$($guestDisk.WindowsDisk)]"
                    }
                } else {
                    Write-Verbose -Message "Could not find disk with SN $($config.SerialNumber)"
                }
            }

            # Compare the formated guest volumes with the mapping configuration
            # if the matching volume from the mapping has a size greater
            # than what exists, then extend the volume to match the configuration
            # BIG ASSUMPTION
            # There is only one volume per disk

            # Get mapped disks between the guest and VMware
            $guestDiskMapping = _GetGuestDiskToVMDiskMapping -VM $vm -CimSession $CimSession

            # Get formated disks
            if ($os -ge 62) {
                $gfd = @{
                    Session = $PSSession
                    ScriptBlock = {
                        Get-Disk | Where-Object {$_.PartitionStyle -ne 'Raw'}
                    }
                }
            $formatedDisks = Invoke-Command @gfd
            } else {
                $formatedDisks = $guestDiskMapping | where-object {$_.Format -ne ''}
            }

            foreach ($config in $desiredDiskConfigMapping) {

                # Do we have a matching guest disk from our mapping?
                $guestDisk = $guestDiskMapping |
                    Where-Object {(($_.HasSN) -and ($_.SerialNumber -eq $config.SerialNumber)) -or ((!$_.HasSN) -and ($_.SCSIBus -eq $config.SCSIController -and $_.SCSIUnit -eq $config.SCSITarget))} |
                    Select-Object -First 1 

                if ($guestDisk) {
                    if ($os -ge 62) {
                        $disk = $formatedDisks |
                            Where-Object {$_.Number -eq $guestDisk.WindowsDisk} |
                            Select-Object -first 1
                    } else {
                        $disk = $formatedDisks |
                            Where-Object {$_.WindowsDisk -eq $guestDisk.WindowsDisk} |
                            Select-Object -first 1
                    }

                    if ($null -ne $disk) {

                        # Get the partition
                        if ($os -ge 62) {
                            Write-Debug -Message "Looking at disk $($disk.Number)"
                            Write-Debug -Message "Using 2012 commands"
                            $gp = @{
                                Session = $PSSession
                                ScriptBlock = {
                                    $args[0] |
                                        Get-Partition |
                                        Where-Object {$_.Type -ne 'Reserved' -and $_.IsSystem -eq $false -and $_.Type -ne 'Unknown'} |
                                        Select-Object -First 1
                                    }
                                ArgumentList = $disk
                                Verbose = $false
                            }
                            $partition = Invoke-Command @gp

                            # Get max parition size supported on this disk
                            $gpss = @{
                                Session = $PSSession
                                ArgumentList = $partition
                                ScriptBlock = { $args[0] | Get-PartitionSupportedSize | Select-Object -Last 1 }
                                Verbose = $false
                            }
                            $sizes = Invoke-Command @gpss

                            # The max partition size is greater than the current partition size
                            Write-Debug -Message "Partition size: $($partition.Size)"
                            Write-Debug -Message "Paritition max size: $($sizes.SizeMax)"
                            if ( [math]::round($partition.Size / 1GB) -lt [math]::round($sizes.SizeMax / 1GB)) {
                                Write-Verbose -Message "Resisizing disk $($partition.DiskNumber) partition $($partition.PartitionNumber) to $($config.DiskSizeGB) GB"
                                $rp = @{
                                    Session = $PSSession
                                    ArgumentList = @($partition, $sizes.SizeMax)
                                    ScriptBlock = { $args[0] | Resize-Partition -Confirm:$false -Size $args[1] }
                                    Verbose = $false
                                }
                                Invoke-Command @rp
                            }

                            $gv = @{
                                Session = $PSSession
                                ArgumentList = $partition
                                ScriptBlock = { $args[0] | Get-Volume }
                                Verbose =$false
                            }
                            $volume = Invoke-Command @gv

                            # Drive letter
                            if ($Volume.DriveLetter -ne $config.VolumeName) {
                                Write-Verbose -Message "Setting drive letter to [$($config.VolumeName)]"
                                $sdl = @{
                                    Session = $PSSession
                                    ArgumentList = @($partition, $config.VolumeName)
                                    ScriptBlock = { $args[0] | Set-Partition -NewDriveLetter $args[1] }
                                    Verbose = $false
                                }
                                Invoke-Command @sdl
                            }

                            # Volume label
                            if ($Volume.FileSystemLabel -ne $config.VolumeLabel) {
                                Write-Verbose -Message "Setting volume to [$($config.VolumeLabel)]"
                                $gld = @{
                                    CimSession = $CimSession
                                    ClassName = 'Win32_LogicalDisk'
                                    Filter = "deviceid='$($Volume.DriveLetter):'"
                                    Verbose = $false
                                }
                                $vol = Get-CimInstance @gld
                                $vol | Set-CimInstance -Property @{volumename=$config.VolumeLabel} -Verbose:$false
                            }
                        } else {
                            Write-Debug -Message "Looking at disk $($disk.WindowsDisk)"
                            Write-Debug -Message "Using 2008r2 commands"
                            $gs = @{
                                Session = $PSSession
                                ArgumentList = $disk.WindowsDisk
                                ScriptBlock = {
                                    $diskInfo = New-Object psobject
                                    $windowsDisk = [int]$($args[0])
                                    $primaryPart = Get-WMIObject win32_diskpartition | where {($_.DiskIndex -eq $windowsDisk) -and ($_.PrimaryPartition -eq $true)}
                                    if ($primaryPart.count -gt 1) {
                                                $pass = $false
                                                $diskError = "Not able to configure $windowsDisk because it has more than 1 primary partition"
                                                Write-Error $diskError
                                                throw                                       
                                    }
                                    $diskID = ' Disk ' + $windowsDisk.ToString()
                                    $results = "list disk" | diskpart | ? {$_.startswith($diskID)}
                                    $results |% { 
                                        if ($_ -match 'Disk\s+(\d+)\s+\w+\s+(\d+)\s+\w+\s+(\d+)\s+(\w+)') {
                                            Add-Member -InputObject $diskInfo -MemberType Noteproperty -Name ExtraSpace -Value $($matches[3])
                                            Add-Member -InputObject $diskInfo -MemberType NoteProperty -Name DiskSize -Value $($matches[2])
                                            $command = "select disk $($matches[1])`r`nlist part"
                                            $x = $command |diskpart | where {($_ -notlike '*Reserved*') -and ($_ -notlike '*Unknown*') -and ($_ -match 'Partition\s\d')}
                                            if ($x.count -gt 1) {
                                                $pass = $false
                                                $diskError = "Not able to configure $windowsDisk because it has more than 1 primary partition"
                                                Write-Error $diskError
                                                throw
                                            }
                                            $results2 = $x | where {$_ -match 'Partition\s+(\d+).*\s+(\d+\s+\w+)\s+(.*)'}
                                            Add-Member -InputObject $diskInfo -Membertype Noteproperty -Name PartNum -Value ([convert]::ToInt32($matches[1], 10))
                                            #$tempSize = $matches[2].replace(' ', '')
                                            #$diskInBytes = [scriptblock]::Create($tempSize).Invoke()
                                            #$diskInGB = ([convert]::ToInt64($diskInBytes, 10) / 1GB)
                                            $diskInGB = ($primaryPart.size / 1GB)
                                            Add-Member -InputObject $diskInfo -Membertype Noteproperty -Name PartSize -Value $diskInGB
                                            #Lots of type casting magic to get the correct offset size in GB based on given type(KB, MB, or GB)
                                            #$offSet = $matches[3].replace(' ', '')
                                            #$sizeInBytes = [scriptblock]::Create($offSet).Invoke()
                                            #$sizeInGB = ([convert]::ToInt32($sizeInBytes, 10) / 1GB)
                                            $sizeInGB = ($primaryPart.StartingOffset / 1GB) 
                                            Add-Member -InputObject $diskInfo -Membertype NoteProperty -Name Offset -Value ([convert]::ToDecimal($sizeInGB))
                                        }
                                    }
                                    $diskInfo
                                }
                            }

                            $diskInfo = Invoke-Command @gs
                            Write-Debug $diskInfo

                            $actualSize = [math]::round($diskInfo.PartSize + $diskInfo.Offset)
                            if ($actualSize -lt $config.DiskSizeGB) {
                                Write-Verbose "Extending partition for disk $($disk.WindowsDisk)"
                                $ed = @{
                                    Session = $PSSession
                                    ArgumentList = $disk.WindowsDisk, $diskInfo.PartNum
                                    ScriptBlock = {
                                        $diskID = $args[0].ToString()
                                        $partNum = $args[1].ToString()
                                        $x = "Select Disk $($diskID)", "Select Partition $($partNum)", "extend noerr" | diskpart | out-null
                                    }
                                }
                                $results = Invoke-Command @ed
                            }

                            # Drive letter
                            if ($disk.VolumeName -ne $config.VolumeName) {
                                Write-Verbose -Message "Setting drive letter to [$($config.VolumeName)]"
                                $sdl = @{
                                    Session = $PSSession
                                        ArgumentList = $disk.WindowsDisk, $config.VolumeName, $diskInfo.PartNum
                                        ScriptBlock = {
                                            $DiskID = $args[0].ToString()
                                            $VolName = $args[1].ToString()
                                            $PartNum = $args[2].ToString()
                                            $x = "Select Disk $($DiskID)", "Select Partition $($PartNum)", "assign letter=$($VolName)" | diskpart | Out-Null
                                        }
                                    }
                                    $results = Invoke-Command @sdl
                            }

                            # Volume label
                            if ($disk.VolumeLabel -ne $config.VolumeLabel) {
                                Write-Verbose -Message "Setting volume to [$($config.VolumeLabel)]"
                                $gld = @{
                                    CimSession = $CimSession
                                    ClassName = 'Win32_LogicalDisk'
                                    Filter = "deviceid='$($disk.VolumeName):'"
                                    Verbose = $false
                                }
                                $vol = Get-CimInstance @gld
                                $vol | Set-CimInstance -Property @{volumename=$config.VolumeLabel} -Verbose:$false
                            }
                        }
                    }
                }
            }
        } catch {
            Write-Error -Message 'There was a problem configuring the guest disks'
            Write-Error -Message "$($_.InvocationInfo.ScriptName)($($_.InvocationInfo.ScriptLineNumber)): $($_.InvocationInfo.Line)"
            write-Error $_
        }
    }

    end {
        Write-Debug -Message 'Ending _SetGuestDisks()'
    }
}