Migration/vSphere/vSphereUtil.psm1

using module './Tag'
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Common `
    | Join-Path -ChildPath Wrappers | Join-Path -ChildPath Wrappers)
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Util `
    | Join-Path -ChildPath Util)

function Get-RMVSphereTagCategory {
    param(
        [System.Object] $TargetInventory
    )
    $TagCategories = @()
    $TagCategoryAsHashtable = @{}
    foreach ($TagCategory in $TargetInventory.attributes.vsphere.tag_categories) {
        $RMTagCategory = [RMVSphereTagCategory]::new($TagCategory.name, $TagCategory.identifier)
        foreach ($Tag in $TagCategory.tags) {
            $RMTag = $RMTagCategory.AddTag($Tag.name, $Tag.identifier)
            if ($TagCategoryAsHashtable.ContainsKey($TagCategory.name)) {
                $TagCategoryAsHashtable[$TagCategory.name] += $RMTag
            } else {
                $TagCategoryAsHashtable.Add($TagCategory.name, @($RMTag))
            }
        }
        $TagCategories += $RMTagCategory
    }

    return $TagCategories, $TagCategoryAsHashtable
}

function Get-RMTagOption {
    param(
        [RMVSphereTagCategory[]] $TagCategory
    )
    $TagOptions = @()
    foreach ($Category in $TagCategory) {
        foreach ($Tag in $Category.Tags) {
            $TagOption = $Tag.Name + "[" + $Category.Name + "]"
            $TagOptions += $TagOption
        }
    }

    return $TagOptions
}

function Get-RMVMTag {
    param(
        [System.Object] $TargetInventory
    )
    $TagCategories, $TagCategoryAsHashtable = Get-RMVSphereTagCategory -TargetInventory $TargetInventory
    $TagOptions = Get-RMTagOption -TagCategory $TagCategories
    while ($true) {
        $VMTags = Read-RMToken -UserMessage "Enter one or more VM tags separated by commas" -Options $TagOptions `
            -DefaultValue "None" -ParameterName "VM tags" -Separator ","
        if ([string]::IsNullOrWhiteSpace($VMTags)) {
            return @{}
        }

        $CompareResults = Compare-Object -ReferenceObject $TagOptions -DifferenceObject $VMTags -IncludeEqual
        $InputObjects = Get-RMInputObjectBySideIndicator -CompareResult $CompareResults -SideIndicator "=="
        if ($InputObjects.Count -ne $VMTags.Count) {
            Write-RMError -Message "One or more VM tags does not belong to the given list of VM tags, please try again."
        } else {
            return (Get-RMSelectedVMTag -VMTag $VMTags -TagCategory $TagCategoryAsHashtable)
        }
    }
}

function Get-RMSelectedVMTag {
    param(
        [string[]] $VMTag,
        [hashtable] $TagCategory
    )
    $SelectedVMTag = @{}
    foreach ($Tag in $VMTag) {
        $TagName = $Tag.Substring(0, $Tag.LastIndexOf("["))
        $CategoryName = $Tag.Substring($Tag.LastIndexOf("[") + 1, $Tag.LastIndexOf("]") - ($Tag.LastIndexOf("[") + 1))
        $RMTags = $TagCategory[$CategoryName]
        foreach ($RMTag in $RMTags) {
            if ($RMTag.name -ine $TagName) {
                continue
            }
            if ($SelectedVMTag.ContainsKey($CategoryName)) {
                $SelectedVMTag[$CategoryName] += $RMTag
            } else {
                $Tags = @($RMTag)
                $SelectedVMTag.Add($CategoryName, $Tags)
            }
        }
    }
    return $SelectedVMTag
}

function Get-RMStoragePolicy {
    param(
        [System.Object] $TargetInventory,
        [System.Object] $Source,
        [string[]] $SelectedDiskIndex,
        [bool] $IsInteractive
    )
    $DiskCnt = 0
    $SelectedStorageProfileIds = @{}
    $SelectedStorageProfileNames = @{}

    $StoragePolicyOptions = Get-RMStoragePolicyOption -TargetInventory $TargetInventory
    foreach ($DiskIndex in $SelectedDiskIndex) {
        if ($IsInteractive) {
            $Disk = $Source.attributes.storage.vm_disks[$DiskIndex]
            $Size = $Disk.size_kb/(1024*1024)
            $Size = [math]::round($Size, 2)
            $StoragePolicyName = Read-RMString -UserMessage "Enter storage policy name for disk of size $Size GiB" `
                -Options $StoragePolicyOptions.keys -DefaultValue "None" -ParameterName "Storage policy name" -IsRequired $false
            if (![string]::IsNullOrWhiteSpace($StoragePolicyName)) {
                $SelectedStorageProfileIds.Add($Disk.label, $StoragePolicyOptions[$StoragePolicyName])
                $SelectedStorageProfileNames.Add($Disk.label, $StoragePolicyName)
            }
        } else {
            #TODO: Add non-interactive case functionality
        }
        $DiskCnt ++
    }

    return $SelectedStorageProfileIds, $SelectedStorageProfileNames
}

function Get-RMStoragePolicyOption {
    param(
        [System.Object] $TargetInventory
    )
    $StoragePolicyOptions = @{}
    foreach ($StorageProfile in $TargetInventory.attributes.vsphere.datacenters[0].storage_profiles) {
        # User will be providing the storage profile name and hence using it as the key
        # so that we can send both the UUID and the name to FE.
        # Storage profile names are unique in given vCenter
        $StoragePolicyOptions.Add($StorageProfile.name, $StorageProfile.uuid)
    }

    return $StoragePolicyOptions
}


function Get-DiskProvisioningTypeForVMBasedSource {
    param(
        [System.Object] $Source,
        [string[]] $DiskProvisioningTypes,
        [string[]] $SelectedDiskIndex,
        [hashtable] $SelectedStorageProfileName,
        [bool] $IsInteractive
    )

    if ($Source.collection_type -ine "vm") {
        throw "Get-DiskProvisioningTypeForVMBasedSource is supported for VM based sources only"
    }

    $ProvisioningTypes = "thick-lazy-zeroed", "thick-eager-zeroed", "thin"
    $DiskCnt = 0
    $ResultProvisioningTypes = @()

    for ($Index = 0; $Index -lt $Source.attributes.storage.vm_disks.Count; $Index++) {
        if ($IsInteractive) {
            if ($SelectedDiskIndex -contains $Index) {
                $Disk = $Source.attributes.storage.vm_disks[$Index]
                $Size = $Disk.size_kb/(1024*1024)
                $Size = [math]::round($Size, 2)
                if ($SelectedStorageProfileName.ContainsKey($Disk.label)) {
                    $ResultProvisioningTypes += ""
                } else {
                    $ResultProvisioningTypes += Read-RMString -UserMessage "Enter disk provisioning type for disk of size $Size GiB" `
                        -Options $ProvisioningTypes -DefaultValue "thin" -ParameterName "Disk provisioning type" -IsRequired $false
                }
            } else {
                $ResultProvisioningTypes += $null
            }
        } else {
            if ($null -ne $DiskProvisioningTypes -and $DiskCnt -lt $DiskProvisioningTypes.Count) {
                $ResultProvisioningTypes += $DiskProvisioningTypes[$DiskCnt].Trim()
            } else {
                $ResultProvisioningTypes += "thin"
            }
        }
        $DiskCnt ++
    }

    return $ResultProvisioningTypes
}

function Get-RMDatastoreByVMBasedSource {
    param(
        [System.Object] $Source,
        [string[]] $TargetDatastores,
        [string[]] $SelectedDiskIndex,
        [bool] $IsInteractive
    )
    if (!$IsInteractive) {
        Throw "The function Get-RMDatastoreBySource does not support non-interactive case"
    }

    if ($TargetDatastores.Count -eq 0) {
        Throw "No datastores were found, migration cannot be started."
    }

    if ($Source.collection_type -ine "vm") {
        Throw "Get-RMDatastoreByVMBasedSource is supported for VM based sources only"
    }

    $Datastores = @()
    for ($Index = 0; $Index -lt $Source.attributes.storage.vm_disks.Count; $Index++) {
        if ($SelectedDiskIndex -contains $Index) {
            $Disk = $Source.attributes.storage.vm_disks[$Index]
            $Size = $Disk.size_kb/(1024*1024)
            $Size = [math]::round($Size, 2)
            $Datastores += Read-RMString -UserMessage "Enter the datastore name for disk of size $Size GiB" `
                -Options $TargetDatastores -DefaultValue $TargetDatastores[0] -ParameterName "Datastore name" -IsRequired $false
        } else {
            $Datastores += ""
        }
    }
    return $Datastores
}