Migration/vSphere/vSphere.psm1
using module '../../Common/Result' using module './RiverMeadow.VSphereNetworkConfiguration' using module './RiverMeadow.VSphereVMTag' Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath MigrationProfile | Join-Path -ChildPath VSphereMigrationProfile) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath DifferentialProfile | Join-Path -ChildPath DifferentialProfile) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Preflight | Join-Path -ChildPath Preflight) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Util | Join-Path -ChildPath Util) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Util | Join-Path -ChildPath MigrationUtil) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath CloudAccount | Join-Path -ChildPath CloudAccount) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath RiverMeadow.Release.Source | Join-Path -ChildPath SourceUtil | Join-Path -ChildPath SourceUtil) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Validate | Join-Path -ChildPath Validate) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Common | Join-Path -ChildPath Common) 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 vSphereUtil) function Start-RMNonInteractiveVsphereOsBasedMigration { param ( [string] $TargetCloud, [string] $SourceIP, [string] $ScheduledAt, [string] $TargetVMName, [string[]] $MountPoint, [string[]] $ResizeMountPoint, [string] $TransferMethod, [int] $TargetVMVCPUCount, [string] $CoresPerSocket, [int] $TargetVMMemorySize, [string] $DatacenterName, [bool] $EnableDestinationNetworkIsolation, [RMVSphereMigrationNetworkConfiguration] $MigrationNetworkConfig, [RMVSphereIsolatedNetworkConfiguration] $IsolatedNetworkConfig, [RMVSphereDestinationNetworkConfiguration[]] $DestinationNICConfig, [bool] $DisableAutomaticDNSRegistrationOnTheTarget, [string] $ClusterName, [string] $ResourcePoolName, [string] $FolderName, [string] $DatastoreClusterName, [string[]] $DatastoreName, [string[]] $DiskProvisioningType, [int] $HardwareVersion, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $RemoveRMSAgentFromSource, [bool] $RemoveRMSAgentFromTarget, [string[]] $MigrationInstruction, [string] $UpgradeOSVersion, [hashtable[]] $UpgradeSQLServer, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid = Confirm-RMvSphereFullMigrationParameter $PSBoundParameters $CloudAccount = $null $Source = $null try { if (![string]::IsNullOrEmpty($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "rivermeadow_standalone" if (![string]::IsNullOrEmpty($ErrorString)) { $Errors += $ErrorString $IsSourceAndTargetCloudPresent = $false } else { Get-RMTargetInventory -CloudAccount $CloudAccount | Out-Null } } } catch [System.Management.Automation.ItemNotFoundException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } $ShouldExit = $false try { if (![string]::IsNullOrEmpty($SourceIP)) { $Source = Get-RMSourceByIP -IPAddress $SourceIP } } catch [System.Management.Automation.ItemNotFoundException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() if (!$IsSourceAndTargetCloudPresent) { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } try { $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = ` Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationError -AccountType "rivermeadow_standalone" ` -RMMigrationReturn $RMMigrationReturn if (!$IgnoreValidationError -and $OverrideExistingMigrationError -and !$OverrideExistingMigration) { $Errors += "Please set 'OverrideExistingMigration' to true and try again." } } catch [System.InvalidOperationException], [System.Management.Automation.RuntimeException] { $Errors += $PSItem.Exception.Message $IsRequiredParametersPresentAndValid = $false } if ($null -ne $Source) { $SourceSQLServerMapping = Get-RMSQLMMappingBySource -Source $Source $SourceErrors, $RequiredParameterState = Confirm-RMvSphereFullMigrationParameterWithSource ` -UserParameter $PSBoundParameters -Source $Source -SourceSQLServerMapping $SourceSQLServerMapping if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $RequiredParameterState } $Errors += $SourceErrors } $UserInput = @{} $Entitlement = Get-RMEntitlement $UserInput.Add("CloudAccount", $CloudAccount) $UserInput.Add("Entitlement", $Entitlement) $UserInput.Add("Source", $Source) if ([string]::IsNullOrEmpty($TargetVMName)) { $TargetVMName = $Source.hostname } $UserInput.Add("TargetVMName", $TargetVMName) $SelectedMountPoints = $null $SourceMountPoints = Get-MountPoint -Source $Source if ($MountPoint.Count -gt 0) { $SelectedMountPoints = Get-RMSelectedMount -MountPoints $SourceMountPoints -DifferenceList $MountPoint -IncludeEqual $true } else { # If no mount points are given then take all mount points on the source as the selected mount points $SelectedMountPoints = $SourceMountPoints } $UserInput.Add("SelectedMounts", $SelectedMountPoints) $MountsResize = @{} if ($null -ne $ResizeMountPoint -and $ResizeMountPoint.Count -gt 0) { $MountsResize, $MountsResizeErrors = Get-RMResizeMountsPoint -ResizeMountPoints $ResizeMountPoint -SelectedMountPoints $SelectedMountPoints -Source $Source if($null -eq $MountsResize) { $Errors += $MountsResizeErrors } if ("" -ne $TransferMethod -and "block-based" -eq $TransferMethod ) { $Errors += "TransferMethod needs to be 'file-based' if you want to resize the mount points." } $TransferMethod = "file-based" } else { $TransferMethod, $ErrorString = Get-RMTransferMethod -Source $Source -SelectedMountPoints $SelectedMountPoints ` -TransferMethod $TransferMethod if (![string]::IsNullOrEmpty($ErrorString)) { $Errors += $ErrorString } } $UserInput.Add("ResizeMountPoints", $MountsResize) $UserInput.Add("TransferType", $TransferMethod) if(0 -eq $TargetVMVCPUCount) { $TargetVMVCPUCount = $Source.attributes.cpu.processors.Count } $UserInput.Add("TargetVMVCPUCount", $TargetVMVCPUCount) if ("" -eq $CoresPerSocket) { $CoresPerSocket = 1 } else { $CoresPerSockets = Get-RMCoresPerSocket -TargetVMVCPUCount $TargetVMVCPUCount if(!($CoresPerSocket -in $CoresPerSockets)) { $CoresPerSocketsAsString = $CoresPerSockets -join ", " $Errors += "Invalid CoresPerSocket '$CoresPerSocket', valid cores per socket are: '$CoresPerSocketsAsString'" } } $UserInput.Add("CoresPerSocket", $CoresPerSocket) $UserInput.Add("TargetVMMemorySize", $TargetVMMemorySize) if ($Source.os_type -eq "windows") { $UserInput.Add("DisableAutomaticDNSRegistrationOnTheTarget", $DisableAutomaticDNSRegistrationOnTheTarget) } else { $UserInput.Add("DisableAutomaticDNSRegistrationOnTheTarget", $false) } $UserInput.Add("DatacenterName", $DatacenterName) $UserInput.Add("EnableDestinationNetworkIsolation", $EnableDestinationNetworkIsolation) $UserInput.Add("MigrationNetworkConfig", $MigrationNetworkConfig) $UserInput.Add("IsolatedNetworkConfig", $IsolatedNetworkConfig) $UserInput.Add("DestinationNICConfig", $DestinationNICConfig) $UserInput.Add("ClusterName", $ClusterName) $UserInput.Add("ResourcePoolName", $ResourcePoolName) $UserInput.Add("FolderName", $FolderName) $UserInput.Add("DatastoreClusterName", $DatastoreClusterName) $DiskProvisioningType = Get-DiskProvisioningTypeBySource -Source $Source -DiskProvisioningTypes $DiskProvisioningType -IsInteractive $false $UserInput.Add("DatastoreLocations", $DatastoreName) $UserInput.Add("DisksProvisioningType", $DiskProvisioningType) $HardwareVersions, $DefaultHardwareVersion, $ToolsPackage = Get-RMHardwareVersionsAndToolsVersion -CloudAccount $CloudAccount if (0 -eq $HardwareVersion) { $HardwareVersion = $DefaultHardwareVersion } else { if ($HardwareVersions -notcontains $HardwareVersion) { $HardwareVersionsAsString = $HardwareVersions -join ", " $Errors += "Invalid HardwareVersion '$HardwareVersion', valid hardware versions are: '$HardwareVersionsAsString'" } } $UserInput.Add("HardwareVersion", $HardwareVersion) $UserInput.Add("ToolsPackage", $ToolsPackage) $MigrationInstructionsAsHashTable = $null try { if (($IgnoreValidationError -and $OverrideExistingMigration) -or (!$IgnoreValidationError -and $OverrideExistingMigration) -or $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $MigrationInstruction -ParameterName "MigrationInstruction" } catch { $Errors += $PSItem.Exception.Message } $UserInput.Add("MigrationInstructions", $MigrationInstructionsAsHashTable) $UserInput.Add("ShutdownSource", $ShutdownSource) $UserInput.Add("ShutdownTarget", $ShutdownTarget) $UserInput.Add("RemoveRMSAgentFromSource", $RemoveRMSAgentFromSource) $UserInput.Add("RemoveRMSAgentFromTarget", $RemoveRMSAgentFromTarget) $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationError) Add-RMOSUpgrade -UserParameter $PSBoundParameters -UpdatedParameter $UserInput -Source $Source $SQLServerUpgrade = Get-RMUpgradeSQLServer -UpgradeSQLServer $UpgradeSQLServer -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping $UserInput.Add("SQLServerUpgrade", $SQLServerUpgrade) $ValidationErrors = $null if ($IsRequiredParametersPresentAndValid) { $ValidationErrors = Confirm-RMVSphereValidateOSBasedMigrationProfile @UserInput } if ($null -ne $ValidationErrors) { # validation errors have already been printed, so add after the below call Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings $Errors += $ValidationErrors Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } else { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings if ($Errors.Count -gt 0 -or $ShouldExit) { return $RMMigrationReturn } } if ([string]::IsNullOrEmpty($ScheduledAt)) { $UserInput.Add("ScheduledAt", "") } else { $UserInput.Add("ScheduledAt", (Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt)) } $UserInput["DisksProvisioningType"] = Update-DiskProvisioningTypeForME -DiskProvisioningTypes $UserInput["DisksProvisioningType"] $Response = New-RMVSphereMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMInteractiveVSphereOSBasedMigration { param( ) $Entitlement = Get-RMEntitlement $CloudAccount = Read-RMCloudAccount -AccountType "rivermeadow_standalone" -UserMessage "Enter target cloud" $TargetInventory = Get-RMTargetInventory -CloudAccount $CloudAccount $Source = Read-RMSource -UserMessage "Enter the IP address of the source machine to be migrated" -ParameterName "Source IP address" -IsRequired $true $IgnoreValidationErrors = Read-RMBoolean -UserMessage "Ignore validation errors" -DefaultValue "false" [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn -AccountType "rivermeadow_standalone" if ($ShouldExit) { return $RMMigrationReturn } if ($OverrideExistingMigrationError) { $OverrideExistingMigrationError = Read-RMBoolean -UserMessage "Would you like to override the previous migration attempt" -DefaultValue $false if (!$IgnoreValidationErrors -and !$OverrideExistingMigrationError) { return $RMMigrationReturn } } $ScheduledAt = Read-RMMigrationSchedule $TargetVMName = Read-RMString -UserMessage "Enter target VM Name" -DefaultValue $Source.hostname ` -ParameterName "Target VM Name" -IsRequired $false $MountPoints = Get-MountPoint -Source $Source if (0 -eq $MountPoints.count) { throw "Source has no mount points, cannot be migrated" } $MountPointsAsString = $MountPoints.values -join ", " Write-Output "Mount points to be migrated [$MountPointsAsString]" | Out-Host $ExcludedMountPoints = Get-RMExcludedMountPoint -OSType $Source.os_type -MountPoints $MountPoints.Values $SelectedMountPoints = $MountPoints if ("" -ne $ExcludedMountPoints) { $ExcludedList = $ExcludedMountPoints.Split(",").Trim() $SelectedMountPoints = Get-RMSelectedMount -MountPoints $MountPoints -DifferenceList $ExcludedList -IncludeEqual $false } $ReadValue = Read-RMBoolean -UserMessage "Resize mount points" -DefaultValue "false" $MountsResize = @{} $TransferType = "file-based" if ($ReadValue) { $MountsResize = Get-RMInteractiveMountsResize -SelectedMountPoints $SelectedMountPoints -Source $Source } else { $TransferType = (Get-RMTransferMethod -Source $Source -SelectedMountPoints $SelectedMountPoints -IsInteractive $true)[0] } $TargetVMVCPUCount = $Source.attributes.cpu.processors.Count $TargetVMVCPUCount = Read-RMInt -UserMessage "Enter virtual CPU count" -DefaultValue $TargetVMVCPUCount ` -ParameterName "Virtual CPUs count" -IsRequired $false $CoresPerSocket = 1 $CoresPerSockets = Get-RMCoresPerSocket -TargetVMVCPUCount $TargetVMVCPUCount $CoresPerSocket = Read-RMInt -UserMessage "Enter cores per socket" -Options $CoresPerSockets -DefaultValue $CoresPerSocket ` -ParameterName "Cores per socket" -IsRequired $false $SourceMemorySize = [math]::Round($Source.attributes.memory.total_kb/(1024 * 1024),2) $TargetVMMemorySize = Read-RMInt -UserMessage "Enter target VM's memory size in GiB" -DefaultValue $SourceMemorySize ` -ParameterName "Target VM's memory size" -IsRequired $false $DatacenterNames = Get-RMDatacenterName -TargetInventory $TargetInventory $DatacenterName = Read-RMString -UserMessage "Enter datacenter name" -Options $DatacenterNames ` -ParameterName "Datacenter name" -IsRequired $true $NetworkNames = Get-RMNetworkName -TargetInventory $TargetInventory -datacenterName $DatacenterName $EnableDestinationNetworkIsolation = $false [RMVSphereMigrationNetworkConfiguration] $MigrationNetworkConfig = $null [RMVSphereIsolatedNetworkConfiguration] $IsolatedNetworkConfig = $null [RMVSphereDestinationNetworkConfiguration[]] $DestinationNetworkConfigs = $null if ($Source.os_type -eq "windows") { $EnableDestinationNetworkIsolation = Read-RMBoolean -UserMessage "Enable destination network isolation" -DefaultValue "false" if ($EnableDestinationNetworkIsolation) { $MigrationNetworkConfig = Get-RMMigrationNetworkConfig -NetworkName $NetworkNames $IsolatedNetworkConfig = Get-RMIsolatedNetworkConfig -NetworkName $NetworkNames } else { $DestinationNetworkConfigs = Get-RMDestinationNetworkConfig -NetworkName $NetworkNames } } else { $DestinationNetworkConfigs = Get-RMDestinationNetworkConfig -NetworkName $NetworkNames } $DisableAutomaticDNSRegistrationOnTheTarget = $false if ($Source.os_type -eq "windows") { $DisableAutomaticDNSRegistrationOnTheTarget = Read-RMBoolean -UserMessage "Disable automatic DNS registration on the Target" ` -DefaultValue "false" } $Clusters = Get-RMCluster -TargetInventory $TargetInventory -datacenterName $DatacenterName $ClusterName = Read-RMString -UserMessage "Enter cluster name" -Options $Clusters -ParameterName "Cluster name" -IsRequired $true $ResourcePoolName = Read-RMString -UserMessage "Enter resource pool name" -DefaultValue "None" ` -ParameterName "Resource pool name" -IsRequired $false $VMFolders = Get-RMVMFolderName -TargetInventory $TargetInventory -DatacenterName $DatacenterName $FolderName = Read-RMVMFolderString -UserMessage "Enter the VM folder path using '/' as the path separator" -VMFolders $VMFolders -DefaultValue "None" $DatastoreClusters = Get-RMDatastoreCluster -TargetInventory $TargetInventory -datacenterName $DatacenterName $DatastoreClusterName = Read-RMString -UserMessage "Enter datastore cluster name" -Options $DatastoreClusters ` -DefaultValue "None" -ParameterName "Datastore cluster name" -IsRequired $false $Datastores = Get-RMDatastore -TargetInventory $TargetInventory -DatacenterName $DatacenterName -ClusterName $ClusterName $SelectedDatastores = Get-RMDatastoreBySource -Source $Source -TargetDatastores $Datastores -IsInteractive $true $SelectedProvisioningTypes = Get-DiskProvisioningTypeBySource -Source $Source -IsInteractive $true $SelectedProvisioningTypes = Update-DiskProvisioningTypeForME -DiskProvisioningTypes $SelectedProvisioningTypes $HardwareVersions, $DefaultHardwareVersion, $ToolsPackage = Get-RMHardwareVersionsAndToolsVersion -CloudAccount $CloudAccount $HardwareVersion = Read-RMInt -UserMessage "Enter VM hardware version" -Options $HardwareVersions ` -DefaultValue $DefaultHardwareVersion -ParameterName "VM hardware version" -IsRequired $false $OSMUpgradeUserInput = @{} Read-RMOSUpgradeOption -Source $Source -UpdatedUserInput $OSMUpgradeUserInput $UpgradeOSVersion = $OSMUpgradeUserInput["UpgradeOSVersion"] $InPlaceUpgrade = $OSMUpgradeUserInput["InPlaceUpgrade"] $SQLServerUpgrade = Read-RMSQLServerUpgradeOption -Source $Source $ShutdownSource = Read-RMBoolean -UserMessage "Shutdown source after data is fully migrated" -DefaultValue "false" $ShutdownTarget = Read-RMBoolean -UserMessage "Shutdown target after data is fully migrated" -DefaultValue "false" $RemoveRMSAgentFromSource = Read-RMBoolean -UserMessage "Remove RMS agent post migration from source" -DefaultValue "false" $RemoveRMSAgentFromTarget = Read-RMBoolean -UserMessage "Remove RMS agent post migration from target" -DefaultValue "false" $ReadValue = Read-RMPair -UserMessage "Enter migration instructions in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue "None" if (($IgnoreValidationErrors -and $OverrideExistingMigrationError) -or (!$IgnoreValidationErrors -and $OverrideExistingMigrationError) -or $OverrideExistingMigrationWarning) { if ("" -eq $ReadValue) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstructions = Get-RMStringAsHashtable -InputString $ReadValue $HashArguments = @{ CloudAccount = $CloudAccount Entitlement = $Entitlement Source = $Source ScheduledAt = $ScheduledAt TargetVMName = $TargetVMName SelectedMounts = $SelectedMountPoints ResizeMountPoints = $MountsResize ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget RemoveRMSAgentFromSource = $RemoveRMSAgentFromSource RemoveRMSAgentFromTarget = $RemoveRMSAgentFromTarget DatacenterName = $DatacenterName EnableDestinationNetworkIsolation = $EnableDestinationNetworkIsolation MigrationNetworkConfig = $MigrationNetworkConfig IsolatedNetworkConfig = $IsolatedNetworkConfig DestinationNICConfig = $DestinationNetworkConfigs DisableAutomaticDNSRegistrationOnTheTarget = $DisableAutomaticDNSRegistrationOnTheTarget ClusterName = $ClusterName DatastoreClusterName = $DatastoreClusterName DatastoreLocations = $SelectedDatastores FolderName = $FolderName DisksProvisioningType = $SelectedProvisioningTypes TransferType = $TransferType TargetVMVCPUCount = $TargetVMVCPUCount CoresPerSocket = $CoresPerSocket TargetVMMemorySize = $TargetVMMemorySize ResourcePoolName = $ResourcePoolName HardwareVersion = $HardwareVersion ToolsPackage = $ToolsPackage MigrationInstructions = $MigrationInstructions UpgradeOSVersion = $UpgradeOSVersion SQLServerUpgrade = $SQLServerUpgrade IgnoreValidationErrors = $IgnoreValidationErrors InPlaceUpgrade = $InPlaceUpgrade } $Response = New-RMVSphereMigrationProfile @HashArguments $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMInteractiveVSphereVMBasedMigration { param () $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "rivermeadow_standalone" ` -UserMessage "Enter target cloud that supports VM-based migrations" -VMBasedAppliancesOnly $true $Source = Read-RMVMBasedSource -UserMessage "Enter the VM name of the source machine to be migrated" ` -ParameterName "Source VM name" -IsRequired $true -CloudAccount $CloudAccount $Entitlement = Get-RMEntitlement $UserInput.Add("Entitlement", $Entitlement) [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() if ($null -eq $CloudAccount) { return Update-RMMigrationReturnAsError ` -Message "The migration appliance associated with the given source is not ready for use, cannot start the migration" ` -RMMigrationReturn $RMMigrationReturn } $UserInput.Add("CloudAccount", $CloudAccount) $TargetInventory = Get-RMTargetInventory -CloudAccount $CloudAccount $IgnoreValidationErrors = Read-RMBoolean -UserMessage "Ignore validation errors" -DefaultValue "false" $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationErrors) $SourceAttributeResult = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn ` -AccountType "rivermeadow_standalone" $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = $SourceAttributeResult $UserInput.Add("Source", $Source) if ($ShouldExit) { return $RMMigrationReturn } if ($OverrideExistingMigrationError) { $OverrideExistingMigrationError = Read-RMBoolean -UserMessage "Would you like to override the previous migration attempt" -DefaultValue $false if (!$IgnoreValidationErrors -and !$OverrideExistingMigrationError) { return $RMMigrationReturn } } $ScheduledAt = Read-RMMigrationSchedule $UserInput.Add("ScheduledAt", $ScheduledAt) $TargetVMName = Read-RMString -UserMessage "Enter target VM Name" -DefaultValue $Source.host ` -ParameterName "Target VM Name" -IsRequired $false $UserInput.Add("TargetVMName", $TargetVMName) if (0 -eq $Source.attributes.storage.vm_disks.Count) { return Update-RMMigrationReturnAsError ` -Message "Source has no disks, cannot be migrated" -RMMigrationReturn $RMMigrationReturn } $SourceDisksAsString = "Disks to be migrated [" + ((Get-RMVMDiskProperty -Source $Source) -join ", ") + "]" Write-Output $SourceDisksAsString | Out-Host $SelectedDisks = @() $ReturnedValue = Get-RMSelectedDisk -Source $Source if ($SelectedDisks -is [hashtable]) { $SelectedDisks += $ReturnedValue } else { $SelectedDisks = $ReturnedValue } $UserInput.Add("SelectedDisk", $SelectedDisks) $SelectedDiskIndices = @() foreach ($Item in $SelectedDisks) { $SelectedDiskIndices += $Item.Values } $UserInput.Add("SelectedDiskIndex", $SelectedDiskIndices) $TargetVMVCPUCount = $Source.attributes.cpu.processors.Count $TargetVMVCPUCount = Read-RMInt -UserMessage "Enter virtual CPU count" -DefaultValue $TargetVMVCPUCount ` -ParameterName "Virtual CPUs count" -IsRequired $false $UserInput.Add("TargetVMVCPUCount", $TargetVMVCPUCount) $CoresPerSocket = 1 $CoresPerSockets = Get-RMCoresPerSocket -TargetVMVCPUCount $TargetVMVCPUCount $CoresPerSocket = Read-RMInt -UserMessage "Enter cores per socket" -Options $CoresPerSockets -DefaultValue $CoresPerSocket ` -ParameterName "Cores per socket" -IsRequired $false $UserInput.Add("CoresPerSocket", $CoresPerSocket) $SourceMemorySize = [math]::Round($Source.attributes.memory.total_kb/(1024 * 1024),2) $TargetVMMemorySize = Read-RMInt -UserMessage "Enter target VM's memory size in GiB" -DefaultValue $SourceMemorySize ` -ParameterName "Target VM's memory size" -IsRequired $false $UserInput.Add("TargetVMMemorySize", $TargetVMMemorySize) $DatacenterNames = Get-RMDatacenterName -TargetInventory $TargetInventory $DatacenterName = Read-RMString -UserMessage "Enter datacenter name" -Options $DatacenterNames ` -ParameterName "Datacenter name" -IsRequired $true $UserInput.Add("DatacenterName", $DatacenterName) $NetworkNames = Get-RMNetworkName -TargetInventory $TargetInventory -datacenterName $DatacenterName $PreserveIPAddress = Read-RMBoolean -UserMessage "Do you want to preserve the IP address" -DefaultValue "false" $UserInput.Add("PreserveIPAddress", $PreserveIPAddress) [RMVSphereDestinationNetworkConfiguration[]] $DestinationNetworkConfigs = $null if ($PreserveIPAddress) { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" ` -ParameterName "Destination network name" -Options $NetworkNames -IsRequired $true $DestinationNetworkConfigs += [RMVSphereDestinationNetworkConfiguration]::new(` $DestinationNetworkName, "dhcp") } else { $DestinationNetworkConfigs = Get-RMDestinationNetworkConfig -NetworkName $NetworkNames -Source $Source } $UserInput.Add("DestinationNICConfig", $DestinationNetworkConfigs) $UserInput.Add("PreserveMACAddress", (Read-RMBoolean -UserMessage "Do you want to preserve the MAC address" ` -DefaultValue "false")) $UserInput.Add("VMTag", (Get-RMVMTag -TargetInventory $TargetInventory)) $Clusters = Get-RMCluster -TargetInventory $TargetInventory -datacenterName $DatacenterName $ClusterName = Read-RMString -UserMessage "Enter cluster name" -Options $Clusters ` -ParameterName "Cluster name" -IsRequired $true $UserInput.Add("ClusterName", $ClusterName) $UserInput.Add("ResourcePoolName", (Read-RMString -UserMessage "Enter resource pool name" -DefaultValue "None" ` -ParameterName "Resource pool name" -IsRequired $false)) $UserInput.Add("FolderName", (Read-RMString -UserMessage "Enter VM folder name" -DefaultValue "None" ` -ParameterName "VM folder name" -IsRequired $false)) $DatastoreClusters = Get-RMDatastoreCluster -TargetInventory $TargetInventory -datacenterName $DatacenterName $UserInput.Add("DatastoreClusterName", (Read-RMString -UserMessage "Enter datastore cluster name" -Options $DatastoreClusters ` -DefaultValue "None" -ParameterName "Datastore cluster name" -IsRequired $false)) $Datastores = Get-RMDatastore -TargetInventory $TargetInventory -DatacenterName $DatacenterName -ClusterName $ClusterName $UserInput.Add("DatastoreLocation", (Get-RMDatastoreByVMBasedSource -Source $Source ` -TargetDatastores $Datastores -SelectedDiskIndex $SelectedDiskIndices -IsInteractive $true)) $SelectedStorageProfileIds, $SelectedStorageProfileNames = Get-RMStoragePolicy -TargetInventory $TargetInventory ` -Source $Source -SelectedDiskIndex $SelectedDiskIndices -IsInteractive $true $UserInput.Add("StorageProfileId", $SelectedStorageProfileIds) $UserInput.Add("StorageProfileName", $SelectedStorageProfileNames) $SelectedDiskProvisioningTypes = Get-RMDiskProvisioningTypeForVMBasedSource -Source $Source ` -SelectedStorageProfileName $SelectedStorageProfileNames -SelectedDiskIndex $SelectedDiskIndices -IsInteractive $true $UserInput.Add("DiskProvisioningType", (Update-DiskProvisioningTypeForME -DiskProvisioningTypes $SelectedDiskProvisioningTypes)) $UserInput.Add("UpgradeTool", (Read-RMBoolean -UserMessage "Do you want to upgrade the VM tools on the target VM" -DefaultValue "false")) $HardwareVersions, $DefaultHardwareVersion, $ToolsPackage = Get-RMHardwareVersionsAndToolsVersion -CloudAccount $CloudAccount $UserInput.Add("HardwareVersion", (Read-RMInt -UserMessage "Enter VM hardware version" -Options $HardwareVersions ` -DefaultValue $DefaultHardwareVersion -ParameterName "VM hardware version" -IsRequired $false)) $UserInput.Add("ToolsPackage", $ToolsPackage) $UserInput.Add("ShutdownSource", (Read-RMBoolean -UserMessage "Shutdown source after data is fully migrated" -DefaultValue "false")) $UserInput.Add("ShutdownTarget", (Read-RMBoolean -UserMessage "Shutdown target after data is fully migrated" -DefaultValue "false")) $UserInput.Add("FinalizeMigration", (Read-RMBoolean -UserMessage "Remove snapshot(s) from the Target VM in preparation for a cutover" ` -DefaultValue "false")) $ReadValue = Read-RMPair -UserMessage "Enter migration instructions in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue "None" if (($IgnoreValidationErrors -and $OverrideExistingMigrationError) -or (!$IgnoreValidationErrors -and $OverrideExistingMigrationError) -or $OverrideExistingMigrationWarning) { if ("" -eq $ReadValue) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstructions = Get-RMStringAsHashtable -InputString $ReadValue $UserInput.Add("MigrationInstruction", $MigrationInstructions) $Response = New-RMVSphereVMBasedMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMNonInteractiveVsphereVMBasedMigration { param( [string] $SourceVMName, [string] $SourceVMFolderPath, [string] $TargetCloud, [string] $ScheduledAt, [string] $TargetVMName, [string[]] $SelectedDiskLabel, [int] $TargetVMVCPUCount, [string] $CoresPerSocket, [int] $TargetVMMemorySize, [string] $DatacenterName, [bool] $PreserveIPAddress, [RMVSphereDestinationNetworkConfiguration[]] $DestinationNICConfig, [bool] $PreserveMACAddress, [RMVSphereTag[]] $VMTag, [string] $ClusterName, [string] $ResourcePoolName, [string] $FolderName, [string] $DatastoreClusterName, [string[]] $DatastoreName, [string[]] $StoragePolicyName, [string[]] $DiskProvisioningType, [bool] $UpgradeTool, [int] $HardwareVersion, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $FinalizeMigration, [string[]] $MigrationInstruction, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid = ` Confirm-RMvSphereVMBasedFullMigrationParameter $PSBoundParameters try { $TargetInventory = $null if (![string]::IsNullOrEmpty($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud ` -AccountType "rivermeadow_standalone" -VMBasedAppliancesOnly $true if ($null -eq $CloudAccount) { $Errors += $ErrorString $IsSourceAndTargetCloudPresent = $false } else { $TargetInventory = Get-RMTargetInventory -CloudAccount $CloudAccount } } } catch [System.Management.Automation.ItemNotFoundException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } $Source = $null [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() try { if (![string]::IsNullOrEmpty($SourceVMName) -and $null -ne $CloudAccount) { $Source = Get-RMSourceByVMName -VMName $SourceVMName -SourceVMFolderPath $SourceVMFolderPath ` -CloudAccount $CloudAccount if ($Source.collection_type -ine "VM") { $Errors += "Source '$SourceVMName' is not a VM-Based source, to migrate this source, please use the cmdlet 'Start-RMVSphereOSBasedMigration'." Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } } } catch [System.Management.Automation.ItemNotFoundException], [System.Data.DuplicateNameException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } if (!$IsSourceAndTargetCloudPresent) { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } $ShouldExit = $false try { $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = ` Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn ` -AccountType "rivermeadow_standalone" if (!$IgnoreValidationError -and $OverrideExistingMigrationError -and !$OverrideExistingMigration) { $Errors += "Please set 'OverrideExistingMigration' to true and try again." } } catch [System.InvalidOperationException], [System.Management.Automation.RuntimeException] { $Errors += $PSItem.Exception.Message $IsRequiredParametersPresentAndValid = $false } if ($null -ne $Source) { if ($null -eq $SelectedDiskLabel -or $SelectedDiskLabel.Count -eq 0) { # When the user has not selected any disk labels to migrate, # select all for the source. $Warnings += "No disk labels have been given, all the disks on the source will be migrated." $SelectedDiskLabel = Get-RMVMBasedSourceDiskLabel -Source $Source $PSBoundParameters["SelectedDiskLabel"] = $SelectedDiskLabel } $SourceErrors, $SourceWarnings, $RequiredParameterState = Confirm-RMvSphereVMBasedFullMigrationParameterWithSource ` -UserParameter $PSBoundParameters -Source $Source -TargetInventory $TargetInventory if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $RequiredParameterState } $Errors += $SourceErrors $Warnings += $SourceWarnings } $StoragePolicyNamePerDiskLabel = Get-RMDiskLabelToStoragePolicyMapping ` -StoragePolicyName $StoragePolicyName -UserParameter $PSBoundParameters $UserInput = @{} $Entitlement = Get-RMEntitlement $UserInput.Add("CloudAccount", $CloudAccount) $UserInput.Add("Entitlement", $Entitlement) $UserInput.Add("Source", $Source) if ([string]::IsNullOrEmpty($TargetVMName)) { $TargetVMName = $Source.host } $UserInput.Add("TargetVMName", $TargetVMName) $SelectedDisks = Get-RMSelectedDiskByDiskLabel -DiskLabel $SelectedDiskLabel -Source $Source $UserInput.Add("SelectedDiskLabel", $SelectedDiskLabel) $UserInput.Add("SelectedDisk", $SelectedDisks) $SelectedDiskIndices = @() foreach ($Item in $SelectedDisks) { $SelectedDiskIndices += $Item.Values } $UserInput.Add("SelectedDiskIndex", $SelectedDiskIndices) if(0 -eq $TargetVMVCPUCount) { $TargetVMVCPUCount = $Source.attributes.cpu.processors.Count } $UserInput.Add("TargetVMVCPUCount", $TargetVMVCPUCount) if ("" -eq $CoresPerSocket) { $CoresPerSocket = 1 } else { $CoresPerSockets = Get-RMCoresPerSocket -TargetVMVCPUCount $TargetVMVCPUCount if(!($CoresPerSocket -in $CoresPerSockets)) { $CoresPerSocketsAsString = $CoresPerSockets -join ", " $Errors += "Invalid CoresPerSocket '$CoresPerSocket', valid cores per socket are: '$CoresPerSocketsAsString'" } } $UserInput.Add("CoresPerSocket", $CoresPerSocket) $UserInput.Add("TargetVMMemorySize", $TargetVMMemorySize) $UserInput.Add("DatacenterName", $DatacenterName) $UserInput.Add("PreserveIPAddress", $PreserveIPAddress) $UserInput.Add("DestinationNICConfig", $DestinationNICConfig) $UserInput.Add("PreserveMACAddress", $PreserveMACAddress) $UserInput.Add("VMTag", (Get-RMSelectedVMTagByRMVSphereTag -InputTag $VMTag -TargetInventory $TargetInventory)) $UserInput.Add("ClusterName", $ClusterName) $UserInput.Add("ResourcePoolName", $ResourcePoolName) $UserInput.Add("FolderName", $FolderName) $UserInput.Add("DatastoreClusterName", $DatastoreClusterName) $UserInput.Add("DatastoreLocation", $DatastoreName) $StorageProfileIds = Get-RMStorageProfileIdByStoragePolicyName -StoragePolicyNamePerDiskLabel $StoragePolicyNamePerDiskLabel ` -TargetInventory $TargetInventory $UserInput.Add("StorageProfileId", $StorageProfileIds) $UserInput.Add("StorageProfileName", $StoragePolicyNamePerDiskLabel) $DiskProvisioningType = Get-RMDiskProvisioningTypeForVMBasedSource -Source $Source ` -DiskProvisioningType (Get-RMValidDiskProvisioningType -DiskProvisioningType $DiskProvisioningType) ` -SelectedDiskIndex $SelectedDiskIndices -SelectedStorageProfileName $StoragePolicyNamePerDiskLabel -IsInteractive $false $UserInput.Add("DiskProvisioningType", $DiskProvisioningType) $UserInput.Add("UpgradeTool", $UpgradeTool) $HardwareVersions, $DefaultHardwareVersion, $ToolsPackage = Get-RMHardwareVersionsAndToolsVersion -CloudAccount $CloudAccount if (0 -eq $HardwareVersion) { $HardwareVersion = $DefaultHardwareVersion } else { if ($HardwareVersions -notcontains $HardwareVersion) { $HardwareVersionsAsString = $HardwareVersions -join ", " $Errors += "Invalid HardwareVersion '$HardwareVersion', valid hardware versions are: '$HardwareVersionsAsString'" } } $UserInput.Add("HardwareVersion", $HardwareVersion) $UserInput.Add("ToolsPackage", $ToolsPackage) $MigrationInstructionsAsHashTable = $null try { if (($IgnoreValidationError -and $OverrideExistingMigration) -or ` (!$IgnoreValidationError -and $OverrideExistingMigration) -or ` $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $MigrationInstruction -ParameterName "MigrationInstruction" } catch { $Errors += $PSItem.Exception.Message } $UserInput.Add("MigrationInstructions", $MigrationInstructionsAsHashTable) $UserInput.Add("ShutdownSource", $ShutdownSource) $UserInput.Add("ShutdownTarget", $ShutdownTarget) $UserInput.Add("FinalizeMigration", $FinalizeMigration) $ValidationErrors = $null if ($IsRequiredParametersPresentAndValid) { $ValidationErrors = Confirm-RMVSphereValidateVMBasedMigrationProfile @UserInput } if ($null -ne $ValidationErrors) { # validation errors have already been printed, so add after the below call Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings $Errors += $ValidationErrors Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } else { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings if ($Errors.Count -gt 0 -or $ShouldExit) { return $RMMigrationReturn } } if ([string]::IsNullOrEmpty($ScheduledAt)) { $UserInput.Add("ScheduledAt", "") } else { $UserInput.Add("ScheduledAt", (Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt)) } $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationError) $UserInput["DiskProvisioningType"] = Update-DiskProvisioningTypeForME -DiskProvisioningTypes $UserInput["DiskProvisioningType"] $Response = New-RMVSphereVMBasedMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Get-RMTargetInventory { param( [System.Object] $CloudAccount ) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $CollectList = New-Object Collections.Generic.List[string] $CollectList.Add("datacenter") $CollectList.Add("cluster") $CollectList.Add("datastore") $CollectList.Add("datastore_cluster") $CollectList.Add("resource_pool") $CollectList.Add("storage_profile") $CollectList.Add("vm_folder") $CollectList.Add("network") $Body = @{ "appliance_id" = $CloudAccount.appliance.id "organization_id" = $CloudAccount.organization_id "objects_to_collect" = $CollectList } | ConvertTo-Json $Params = @{ Method = "Post" Uri = $Uri.Value + "/targetinventories" Headers = $Headers Body = $Body ContentType = "application/json" } Write-Output "Starting target inventory..." | Out-Host $TargetInventory = Invoke-RMRestMethod -Param $Params return Watch-RMTargetInventoryStatus -TargetInventoryId $TargetInventory.id } function Get-RMDatacenterName { param( [System.Object] $TargetInventory ) $DatacenterNames = @() foreach ($datacenterName in $TargetInventory.attributes.vSphere.datacenters) { $DatacenterNames += $datacenterName.name } return $DatacenterNames } function Get-RMNetworkName { param ( [System.Object] $TargetInventory, [string] $datacenterName ) $NetworkNames = @() foreach ($datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($datacenterName -eq $datacenter.name) { foreach($network in $datacenter.networks) { if ([string]::IsNullOrEmpty($network.switch_name)) { $NetworkNames += $network.name } else { $NetworkNames += ($network.switch_name + "/" + $network.name) } } break } } return $NetworkNames } function Get-RMVMFolderName { param ( [System.Object] $TargetInventory, [string] $DatacenterName ) $VMFolders = @() foreach ($Datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($DatacenterName -ieq $Datacenter.name) { foreach ($Folder in $Datacenter.vm_folder.folders) { $VMFolders += Get-RMPath -Folder $Folder } } } return $VMFolders } function Get-RMPath { param( [System.Object] $Folder, [array] $Paths ) $Paths += $Folder.path if ($null -ne $Folder.folders) { foreach ($F in $Folder.folders) { $Paths = Get-RMPath -Folder $F -Paths $Paths } } return $Paths } function Get-RMCluster { param ( [System.Object] $TargetInventory, [string] $datacenterName ) $Clusters = @() foreach ($datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($datacenterName -eq $datacenter.name) { foreach($cluster in $datacenter.clusters) { $Clusters += $cluster.name } break } } return $Clusters } function Get-RMDatastoreCluster { param( [System.Object] $TargetInventory, [string] $datacenterName ) $DatastoreClusters = @() foreach ($datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($datacenterName -eq $datacenter.name) { foreach($datastoreCluster in $datacenter.datastore_clusters) { $DatastoreClusters += $datastoreCluster.name } break } } return $DatastoreClusters } function Get-RMDatastore { param ( [System.Object] $TargetInventory, [string] $DatacenterName, [string] $ClusterName ) $Datastores = @() foreach ($Datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($Datacenter.name -ne $DatacenterName) { continue } foreach ($Cluster in $Datacenter.clusters) { if ($Cluster.name -ne $ClusterName) { continue } foreach ($Datastore in $Cluster.datastores) { $Datastores += $Datastore.name } break } break } return $Datastores } function Get-RMHardwareVersionsAndToolsVersion { param( [System.Object] $CloudAccount ) $HardwareVersions = @() $HardwareVersionList = @(8, 9, 10, 11, 13, 14, 15, 17, 18, 19) $DefaultVersion = $CloudAccount.vsphere_version $ToolsPackage , $DefaultHardwareVersion = Get-RMVsphereVersionInfo -Version $DefaultVersion foreach($HardwareVersion in $HardwareVersionList) { if ($DefaultHardwareVersion -gt $HardwareVersion -or $DefaultHardwareVersion -eq $HardwareVersion) { $HardwareVersions += $HardwareVersion } } return $HardwareVersions, $DefaultHardwareVersion, $ToolsPackage } function Get-RMVsphereVersionInfo { param ( [string] $Version ) $Versions = Get-RMVsphereVersionHashtable $ToolsPackage = "" $HardwareVersion = "" foreach($VsphereVersion in $Versions.GetEnumerator()) { if ($Version -eq $VsphereVersion.Name) { $ToolsPackage = $VsphereVersion.Value.tools_version $HardwareVersion = $VsphereVersion.Value.hardware_version Break } } return $ToolsPackage, $HardwareVersion } function Get-RMVsphereVersionHashtable { param () $VersionInfo = @{ "VMC" = @{ "tools_version" = "vmwaretools-11.3.0.tar.gz" "hardware_version" = 19 } "GCVE" = @{ "tools_version" = "vmwaretools-11.3.0.tar.gz" "hardware_version" = 19 } "AVS" = @{ "tools_version" = "vmwaretools-11.3.0.tar.gz" "hardware_version" = 19 } "ESXi_7_0" = @{ "tools_version" = "vmwaretools-11.0.5.tar.gz" "hardware_version" = 17 } "ESXi_6_7_U3" = @{ "tools_version" = "vmwaretools-10.3.5.tar.gz" "hardware_version" = 15 } "ESXi_6_7_U2" = @{ "tools_version" = "vmwaretools-10.3.5.tar.gz" "hardware_version" = 15 } "ESXi_6_7" = @{ "tools_version" = "vmwaretools-10.3.2.tar.gz" "hardware_version" = 14 } "ESXi_6_5" = @{ "tools_version" = "vmwaretools-10.1.0.tar.gz" "hardware_version" = 13 } "ESXi_6_0" = @{ "tools_version" = "vmwaretools-9.10.0.tar.gz" "hardware_version" = 11 } } return $VersionInfo } function Get-RMMigrationNetworkConfig { param( [string[]] $NetworkName ) $MigrationNetworkName = Read-RMString -UserMessage "Enter migration network name" ` -ParameterName "Migration network name" -Options $NetworkName -IsRequired $true $IPType = (Read-RMString -UserMessage "Enter migration network's IP type" ` -Options "static", "DHCP" -DefaultValue "DHCP" ` -ParameterName "IP Type" -IsRequired $false).ToLower() if ($IPType -ieq "dhcp") { return [RMVSphereMigrationNetworkConfiguration]::new($MigrationNetworkName, $IPType) } $IPAddress = Read-RMIPAddress -UserMessage "Enter migration network's IP address" ` -ParameterName "IP address" -IsRequired $true $Netmask = Read-RMIPAddress -UserMessage "Enter migration network's netmask" ` -ParameterName "Netmask" -IsRequired $true $DefaultGateway = Read-RMIPAddress -UserMessage "Enter migration network's default gateway" ` -ParameterName "Default gateway" -IsRequired $true $PrimaryDNS = Read-RMIPAddress -UserMessage "Enter migration network's primary DNS" ` -ParameterName "Primary DNS" -IsRequired $true $SecondaryDNS = Read-RMIPAddress -UserMessage "Enter migration network's secondary DNS" ` -ParameterName "Secondary DNS" -DefaultValue "None" -IsRequired $false return [RMVSphereMigrationNetworkConfiguration]::new($MigrationNetworkName, $IPType, ` $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS) } function Get-RMIsolatedNetworkConfig { param( [string[]] $NetworkName ) $IsolatedNetworkName = Read-RMString -UserMessage "Enter isolated network name" ` -ParameterName "Isolated network name" -Options $NetworkName -IsRequired $true $IPType = (Read-RMString -UserMessage "Enter isolated network's IP type" ` -Options "static", "DHCP" -DefaultValue "DHCP" ` -ParameterName "IP Type" -IsRequired $false).ToLower() if ($IPType -ieq "dhcp") { return [RMVSphereIsolatedNetworkConfiguration]::new($IsolatedNetworkName, $IPType) } $IPAddress = Read-RMIPAddress -UserMessage "Enter isolated network's IP address" ` -ParameterName "IP address" -IsRequired $true $Netmask = Read-RMIPAddress -UserMessage "Enter isolated network's netmask" ` -ParameterName "Netmask" -IsRequired $true $DefaultGateway = Read-RMIPAddress -UserMessage "Enter isolated network's default gateway" ` -ParameterName "Default gateway" -IsRequired $true $PrimaryDNS = Read-RMIPAddress -UserMessage "Enter isolated network's primary DNS" ` -ParameterName "Primary DNS" -IsRequired $true $SecondaryDNS = Read-RMIPAddress -UserMessage "Enter isolated network's secondary DNS" ` -ParameterName "Secondary DNS" -DefaultValue "None" -IsRequired $false return [RMVSphereIsolatedNetworkConfiguration]::new($IsolatedNetworkName, $IPType, $IPAddress, ` $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS) } function Get-RMDestinationNetworkConfig { param( [string[]] $NetworkName, [System.Object] $Source ) $DestinationNetworkConfigs = @() $AddMoreNIC = $false $IsGatewayDNSProvided = $false do { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" ` -ParameterName "Destination network name" -Options $NetworkName -IsRequired $true $IPType = (Read-RMString -UserMessage "Enter destination network's IP type" ` -Options "static", "DHCP" -DefaultValue "DHCP" ` -ParameterName "IP Type" -IsRequired $false).ToLower() if ($IPType -ieq "dhcp") { $DestinationNetworkConfigs += [RMVSphereDestinationNetworkConfiguration]::new(` $DestinationNetworkName, $IPType) $AddMoreNIC = Read-RMBoolean -UserMessage "Do you want to add more network adapters" -DefaultValue "false" if ($AddMoreNIC) { continue } return $DestinationNetworkConfigs } $IPAddress = Read-RMIPAddress -UserMessage "Enter destination network's IP address" ` -ParameterName "IP address" -IsRequired $true $Netmask = Read-RMIPAddress -UserMessage "Enter destination network's netmask" ` -ParameterName "Netmask" -IsRequired $true if (!$IsGatewayDNSProvided) { $DefaultGateway = Read-RMIPAddress -UserMessage "Enter destination network's default gateway" ` -ParameterName "Default gateway" -IsRequired $true if ($null -ne $Source -and $Source.collection_type -ieq "vm") { $DestinationNetworkConfigs += [RMVSphereDestinationNetworkConfiguration]::new($DestinationNetworkName, ` $IPType, $IPAddress, $Netmask, $DefaultGateway, "", "") $IsGatewayDNSProvided = $true } else { $PrimaryDNS = Read-RMIPAddress -UserMessage "Enter destination network's primary DNS" ` -ParameterName "Primary DNS" -IsRequired $true $SecondaryDNS = Read-RMIPAddress -UserMessage "Enter destination network's secondary DNS" ` -ParameterName "Secondary DNS" -DefaultValue "None" -IsRequired $false $DestinationNetworkConfigs += [RMVSphereDestinationNetworkConfiguration]::new($DestinationNetworkName, ` $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS) $IsGatewayDNSProvided = $true } } else { $DestinationNetworkConfigs += [RMVSphereDestinationNetworkConfiguration]::new($DestinationNetworkName, ` $IPType, $IPAddress, $Netmask) } $AddMoreNIC = Read-RMBoolean -UserMessage "Do you want to add more network adapters" -DefaultValue "false" } while ($AddMoreNIC) return $DestinationNetworkConfigs } function Get-RMDatastoreBySource { param( [System.Object] $Source, [string[]] $TargetDatastores, [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." } $Datastores = @() $SortedDisks = $Source.attributes.storage.disks.psobject.Properties.Value | Sort-Object -property device foreach ($Disk in $SortedDisks) { $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 } return $Datastores } function Get-DiskProvisioningTypeBySource { param( [System.Object] $Source, [string[]] $DiskProvisioningTypes, [bool] $IsInteractive ) $ProvisioningTypes = "thick-lazy-zeroed", "thick-eager-zeroed", "thin" $SortedDisks = $Source.attributes.storage.disks.psobject.Properties.Value | Sort-Object -property device $DiskCnt = 0 $ResultProvisioningTypes = @() foreach ($Disk in $SortedDisks) { if ($IsInteractive) { $Size = $Disk.size_kb/(1024*1024) $Size = [math]::round($Size, 2) $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 { if ($null -ne $DiskProvisioningTypes -and $DiskCnt -lt $DiskProvisioningTypes.Count) { $ResultProvisioningTypes += $DiskProvisioningTypes[$DiskCnt].Trim() } else { $ResultProvisioningTypes += "thin" } } $DiskCnt ++ } return $ResultProvisioningTypes } function Update-DiskProvisioningTypeForME { param( [string[]] $DiskProvisioningTypes ) $Result = @() switch ($DiskProvisioningTypes) { "thick-lazy-zeroed" { $Result += "thick_lazy_zero" } "thick-eager-zeroed" { $Result += "thick_eager_zero" } "thin" { $Result += "thin" } default { $Result += $null } } return $Result } function Get-RMDestinationNetworkAndDvSwitchName { param( [string[]] $NetworkNames, [string] $DestinationNetworkName, [bool] $IsInteractive ) if ($IsInteractive) { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" -Options $NetworkNames ` -ParameterName "Destination network name" -IsRequired $true } $DvSwitchName = "" [string[]] $networkNamesArray = $DestinationNetworkName -split "/" if ($networkNamesArray.Count -eq 2) { $DestinationNetworkName = $networkNamesArray[1] $DvSwitchName = $networkNamesArray[0] } return $DestinationNetworkName, $DvSwitchName } function Confirm-RMvSphereFullMigrationParameter { param( [hashtable] $UserParameter ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent = Confirm-RMCommonParameter -UserParameter $UserParameter $vSphereErrors, $IsRequiredParametersPresentAndValid = Confirm-RMvSphereParameter -UserParameter $UserParameter $Errors += $vSphereErrors return $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid } function Confirm-RMvSphereVMBasedFullMigrationParameter { param( [hashtable] $UserParameter ) $Errors, $Warnings, $IsSourcePresent = Confirm-RMVMBasedCommonParameter -UserParameter $UserParameter $vSphereErrors, $IsRequiredParametersPresentAndValid = Confirm-RMvSphereParameter -UserParameter $UserParameter $Errors += $vSphereErrors return $Errors, $Warnings, $IsSourcePresent, $IsRequiredParametersPresentAndValid } function Confirm-RMvSphereFullMigrationParameterWithSource { param ( [hashtable] $UserParameter, [System.Object] $Source, [System.Object] $SourceSQLServerMapping ) $Errors = @() $IsRequiredParametersPresentAndValid = $true if ($Source.os_type -ieq "linux") { if ($UserParameter.ContainsKey("EnableDestinationNetworkIsolation") -and ` $UserParameter["EnableDestinationNetworkIsolation"] -eq $true) { $Errors += "EnableDestinationNetworkIsolation can be 'true' only for a Windows source" $IsRequiredParametersPresentAndValid = $false } [string[]] $NetworkIsolationConfigs = "MigrationNetworkConfig", "IsolatedNetworkConfig" foreach($NetworkIsolationConfig in $NetworkIsolationConfigs) { if ($UserParameter.ContainsKey($NetworkIsolationConfig) -or ` $null -ne $UserParameter[$NetworkIsolationConfig]) { $Errors += "$NetworkIsolationConfig can be not null only for a Windows source" } } $NetworkConfigErrors, $RequiredParameterState = ` Confirm-RMDestinationNetworkConfig -UserParameter $UserParameter $Errors += $NetworkConfigErrors # Update the flag only if everything is good so far if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $RequiredParameterState } } elseif ($UserParameter.ContainsKey("EnableDestinationNetworkIsolation") ` -and $UserParameter["EnableDestinationNetworkIsolation"] -eq $true) { [string[]] $NetworkIsolationConfigs = "MigrationNetworkConfig", "IsolatedNetworkConfig" foreach ($NetworkIsolationConfig in $NetworkIsolationConfigs) { if (!$UserParameter.ContainsKey($NetworkIsolationConfig) -or ` $null -eq $UserParameter[$NetworkIsolationConfig]) { $Errors += "$NetworkIsolationConfig is required when 'EnableDestinationNetworkIsolation' is 'true'" $IsRequiredParametersPresentAndValid = $false continue } $NetworkConfig = $UserParameter[$NetworkIsolationConfig] $NetworkConfigErrors, $RequiredParameterState = ` Confirm-RMNetworkIsolationConfig -NetworkConfig $NetworkConfig $Errors += $NetworkConfigErrors # Update the flag only if everything is good so far if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $RequiredParameterState } } } else { if ($UserParameter.ContainsKey("MigrationNetworkConfig") -and $null -ne $UserParameter["MigrationNetworkConfig"] -and ` $UserParameter.ContainsKey("IsolatedNetworkConfig") -and $null -ne $UserParameter["IsolatedNetworkConfig"]) { $Errors += "'EnableDestinationNetworkIsolation' is required when 'MigrationNetworkConfig' and 'IsolatedNetworkConfig' are not null." $IsRequiredParametersPresentAndValid = $false } $NetworkConfigErrors, $RequiredParameterState = ` Confirm-RMDestinationNetworkConfig -UserParameter $UserParameter $Errors += $NetworkConfigErrors # Update the flag only if everything is good so far if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $RequiredParameterState } } $HasDynamicDisks = Test-RMSourceHasDynamicDisks -Source $Source if ($HasDynamicDisks) { if (!$UserParameter.ContainsKey("DatastoreName") -or $UserParameter["DatastoreName"].Count -eq 0) { $Errors += "DatastoreName is required and since the source has dynamic disk(s), please provide only one datastore name." $IsRequiredParametersPresentAndValid = $false } elseif ($UserParameter["DatastoreName"].Count -gt 1) { $Errors += "Source has dynamic disks, please provide only one datastore name." } if (!$UserParameter.ContainsKey("DiskProvisioningType") -or $UserParameter["DiskProvisioningType"].Count -eq 0) { $Errors += "DiskProvisioningType is required and since the source has dynamic disk(s), please provide only one disk provisioning type." $IsRequiredParametersPresentAndValid = $false } elseif ($UserParameter["DiskProvisioningType"].Count -gt 1) { $Errors += "Source has dynamic disks, please provide only one disk provisioning type." } } else { $SourceDiskCnt = $Source.attributes.storage.disks.psobject.properties.name.Count if (!$UserParameter.ContainsKey("DatastoreName") -or $UserParameter["DatastoreName"].Count -eq 0) { $Errors += "DatastoreName is required." $IsRequiredParametersPresentAndValid = $false } elseif ($UserParameter["DatastoreName"].Count -lt $SourceDiskCnt) { $DatastoreCnt = $UserParameter["DatastoreName"].Count $Errors += "The parameter 'DatastoreName' contains '$DatastoreCnt' datastore names but the number of disks found on the source are '$SourceDiskCnt'. The number of datastore names given should be equal to the number of disks on the source." $IsRequiredParametersPresentAndValid = $false } if (!$UserParameter.ContainsKey("DiskProvisioningType") -or $UserParameter["DiskProvisioningType"].Count -eq 0) { $Errors += "DiskProvisioningType is required." $IsRequiredParametersPresentAndValid = $false } elseif ($UserParameter["DiskProvisioningType"].Count -lt $SourceDiskCnt) { $DiskProvCnt = $UserParameter["DiskProvisioningType"].Count $Errors += "The parameter 'DiskProvisioningType' contains '$DiskProvCnt' disk provisioning types but the number of disks found on the source are '$SourceDiskCnt'. The number of disk provisioning types given should be equal to the number of disks on the source." $IsRequiredParametersPresentAndValid = $false } } $Errors += Confirm-RMCommonParameterWithSource -UserParameter $UserParameter -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping return $Errors, $IsRequiredParametersPresentAndValid } function Confirm-RMvSphereVMBasedFullMigrationParameterWithSource { param( [hashtable] $UserParameter, [System.Object] $Source, [System.Object] $TargetInventory ) $Errors = @() $Warnings = @() $IsRequiredParametersPresentAndValid = $true $SelectedDiskLabelCnt = $UserParameter["SelectedDiskLabel"].Count if (!$UserParameter.ContainsKey("DatastoreName") -or [string]::IsNullOrWhiteSpace($UserParameter["DatastoreName"])) { $Errors += "DatastoreName is required." $IsRequiredParametersPresentAndValid = $false } elseif ($UserParameter["DatastoreName"].Count -ne $UserParameter["SelectedDiskLabel"].Count) { $GivenDatastoreCount = $UserParameter["DatastoreName"].Count $Errors += "The parameter 'DatastoreName' contains '$GivenDatastoreCount' datastore names but there are '$SelectedDiskLabelCnt' selected disks on the source. Please provide the same number of datastore names as the disks selected for migration." } if ($UserParameter.ContainsKey("PreserveIPAddress") -and $UserParameter["PreserveIPAddress"] ` -and $UserParameter.ContainsKey("DestinationNICConfig")) { $NetworkConfigs = $UserParameter["DestinationNICConfig"] if ($NetworkConfigs.Count -gt 1) { $Warnings += "The parameter 'PreserveIPAddress' is true and the parameter 'DestinationNICConfig' contains more than one NIC configuration, ` only the destination network name will be used from the first NIC configuration and all other NIC configurations will be ignored." } elseif ($NetworkConfigs[0].IPType -ieq "static" ` -or ![string]::IsNullOrWhiteSpace($NetworkConfigs[0].IPAddress) ` -or ![string]::IsNullOrWhiteSpace($NetworkConfigs[0].Netmask) ` -or ![string]::IsNullOrWhiteSpace($NetworkConfigs[0].DefaultGateway) ` -or ![string]::IsNullOrWhiteSpace($NetworkConfigs[0].PrimaryDNS)) { $Warnings += "When parameter 'PreserveIPAddress' is true then only the destination network name will be used from the parameter 'DestinationNICConfig'" } if ([string]::IsNullOrWhiteSpace($NetworkConfigs[0].DestinationNetworkName)) { $Errors += "DestinationNICConfig's DestinationNetworkName is required" $IsRequiredParametersPresentAndValid = $false } } else { $NetworkConfigErrors, $RequiredParameterState = ` Confirm-RMDestinationNetworkConfig -UserParameter $UserParameter $Errors += $NetworkConfigErrors if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $RequiredParameterState } } $SourceDiskLabels = Get-RMVMBasedSourceDiskLabel -Source $Source $DiskLabelsNotFound = @() foreach ($DiskLabel in $UserParameter["SelectedDiskLabel"]) { if ($SourceDiskLabels -notcontains $DiskLabel) { $DiskLabelsNotFound += $DiskLabel } } if ($DiskLabelsNotFound.Count -gt 0) { $DiskLabelsNotFoundAsString = $DiskLabelsNotFound -join ", " $Errors += "The disk label(s) '$DiskLabelsNotFoundAsString' specified in the parameter 'SelectedDiskLabel' does not exist on the source" } if ($null -ne $UserParameter["StoragePolicyName"] ` -and $UserParameter["StoragePolicyName"].Count -gt 0) { $ValidPolicyNames, $InvalidPolicyNames = Confirm-RMStoragePolicy -TargetInventory $TargetInventory ` -StoragePolicyName $UserParameter["StoragePolicyName"] $ValidPolicyCnt = $ValidPolicyNames.Count if ($InvalidPolicyNames.Count -gt 0) { $InvalidPolicyNamesAsString = $InvalidPolicyNames -join ", " $Errors += "The storage policy name(s) '$InvalidPolicyNamesAsString' specified by the parameter 'StoragePolicyName' do not exist on the target vCenter" } $StoragePolicyCnt = $UserParameter["StoragePolicyName"].Count if ($StoragePolicyCnt -ne $SelectedDiskLabel.Count) { $Errors += "The parameter 'StoragePolicyName' has '$StoragePolicyCnt' storage policy names but '$SelectedDiskLabelCnt' disks have been selected for migration. When the parameter 'StoragePolicyName' is used it should either provide a storage policy name or 'none' for each selected disk. Use 'none' when you do not want to assign a storage policy to a disk but a disk provisioning type should be given for that disk." } else { if ($ValidPolicyNames.Count -eq $SelectedDiskLabel.Count -and ` ($null -ne $UserParameter["DiskProvisioningType"] -and ` $UserParameter["DiskProvisioningType"].Count -gt 0 -and ` $UserParameter["DiskProvisioningType"] -notcontains 'none')) { $Warnings += "The parameter 'StoragePolicyName' has '$ValidPolicyCnt' valid storage policy names and there are '$SelectedDiskLabelCnt' selected disks for migration. The given disk provisioning types will be ignored." } elseif ($ValidPolicyNames.Count -gt $SelectedDiskLabel.Count) { $Errors += "The parameter 'StoragePolicyName' has '$ValidPolicyCnt' valid storage policy names and the number of disks selected for migration are '$SelectedDiskLabelCnt'. The number of storage policy names should be equal to the number of disks selected for migration." } elseif ($ValidPolicyNames.Count -lt $SelectedDiskLabel.Count ` -and $null -eq $UserParameter["DiskProvisioningType"]) { $Errors += "The parameter 'StoragePolicyName' has '$ValidPolicyCnt' valid storage policy names but '$SelectedDiskLabelCnt' disk(s) have been selected for migration. Please provide additional storage policy names or disk provisioning types for the remaining disks." } elseif ($null -ne $UserParameter["DiskProvisioningType"] ` -and $UserParameter["DiskProvisioningType"].Count -gt 0) { $ValidDiskProvisioningTypes = Get-RMValidDiskProvisioningType -DiskProvisioningType $UserParameter["DiskProvisioningType"] $SumOfPolicyAndDiskProvCnt = $ValidPolicyCnt + $ValidDiskProvisioningTypes.Count if ($SumOfPolicyAndDiskProvCnt -lt $SelectedDiskLabelCnt) { $Errors += "The sum of given storage policies and disk provisioning types is less than the number of disks selected for migration. When using both storage policies and disk provisioning types, the sum of storage policy names and disk provisioning types should be equal to the number of selected disks." } elseif ($SumOfPolicyAndDiskProvCnt -gt $SelectedDiskLabelCnt) { $Errors += "The sum of given storage policies and disk provisioning types is greater than the number of disks selected for migration. When using both storage policies and disk provisioning types, the sum of storage policy names and disk provisioning types should be equal to the number of selected disks." } } } } elseif ($null -ne $UserParameter["DiskProvisioningType"] -and ` $UserParameter["DiskProvisioningType"].Count -gt 0) { $ValidDiskProvisioningTypes = Get-RMValidDiskProvisioningType -DiskProvisioningType $UserParameter["DiskProvisioningType"] $DiskProvCnt = $ValidDiskProvisioningTypes.Count if ($DiskProvCnt -ne $SelectedDiskLabelCnt) { $Errors += "The parameter 'DiskProvisioningType' contains '$DiskProvCnt' disk provisioning types whereas the number of disks selected for migration are '$SelectedDiskLabelCnt'. The number of disk provisioning types should be equal to the number of disks selected for migration." } } else { $Errors += "Please provide the storage policy name(s) by using the parameter 'StoragePolicyName' or disk provisioning type(s) by using parameter 'DiskProvisioningType'. You can also use a combination of these two parameters such that any disk that you want to assign a storage policy should have a 'none' value for the corresponding disk in the parameter 'DiskProvisioningType' and vice versa." } return $Errors, $Warnings, $IsRequiredParametersPresentAndValid } function Confirm-RMNetworkIsolationConfig { param( [RMVSphereBaseNetworkConfiguration] $NetworkConfig ) $Errors = @() $IsRequiredParametersPresentAndValid = $true $NetworkConfigType = "" if ($NetworkConfig -is [RMVSphereMigrationNetworkConfiguration]) { $NetworkConfigType = "MigrationNetworkConfig's" if ([string]::IsNullOrWhiteSpace($NetworkConfig.MigrationNetworkName)) { $Errors += "$NetworkConfigType MigrationNetworkName is required" $IsRequiredParametersPresentAndValid = $false } } if ($NetworkConfig -is [RMVSphereIsolatedNetworkConfiguration]) { $NetworkConfigType = "IsolatedNetworkConfig's" if ([string]::IsNullOrWhiteSpace($NetworkConfig.IsolatedNetworkName)) { $Errors += "$NetworkConfigType IsolatedNetworkName is required" $IsRequiredParametersPresentAndValid = $false } } if (!(Confirm-RMIPType -NetworkConfig $NetworkConfig)) { $GivenIPType = $NetworkConfig.IPType $Errors += "$NetworkConfigType IPType should be 'static' or 'DHCP', given IPType is '$GivenIPType'" $IsRequiredParametersPresentAndValid = $false return $Errors, $IsRequiredParametersPresentAndValid } if ($NetworkConfig.IPType -ieq "dhcp") { return $Errors, $IsRequiredParametersPresentAndValid } $ReturnedData = Confirm-RMStaticNetworkConfig -NetworkConfig $NetworkConfig ` -NetworkConfigPrefix $NetworkConfigType -NICName $null $Errors += $ReturnedData[0] # Update the flag only if everything is good so far, to avoid overwriting bad state if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $ReturnedData[1] } return $Errors, $IsRequiredParametersPresentAndValid } function Confirm-RMDestinationNetworkConfig { param( [hashtable] $UserParameter ) $Errors = @() if (!$UserParameter.ContainsKey("DestinationNICConfig") -or ` $null -eq $UserParameter["DestinationNICConfig"]) { $Errors += "DestinationNICConfig is required" return $Errors, $false } $IsRequiredParametersPresentAndValid = $true $SkipGatewayAndDNSValidation = $false $NetworkConfig = $UserParameter["DestinationNICConfig"] for ($Index = 0; $Index -lt $NetworkConfig.Count; $Index++) { $NICWithIndex = "NIC" + $Index if ([string]::IsNullOrWhiteSpace($NetworkConfig[$Index].DestinationNetworkName)) { $Errors += "DestinationNICConfig's DestinationNetworkName is required for $NICWithIndex" $IsRequiredParametersPresentAndValid = $false } if (!(Confirm-RMIPType -NetworkConfig $NetworkConfig[$Index])) { $GivenIPType = $NetworkConfig[$Index].IPType $Errors += "DestinationNICConfig's IPType should be 'static' or 'DHCP', given IPType for " + $NICWithIndex + " is '$GivenIPType'" $IsRequiredParametersPresentAndValid = $false continue } if ($NetworkConfig[$Index].IPType -ieq "dhcp") { continue } if ($SkipGatewayAndDNSValidation -and !([string]::IsNullOrWhiteSpace($NetworkConfig[$Index].DefaultGateway) ` -or [string]::IsNullOrWhiteSpace($NetworkConfig[$Index].PrimaryDNS))) { $Errors += "DestinationNICConfig's DefaultGateway, PrimaryDNS and optionally Secondary DNS should be provided for one NIC only" } $ReturnedData = Confirm-RMStaticNetworkConfig -NetworkConfig $NetworkConfig[$Index] ` -NetworkConfigPrefix "DestinationNICConfig's" -SkipGatewayAndDNS $SkipGatewayAndDNSValidation -NICName $NICWithIndex $Errors += $ReturnedData[0] # Update the flag only if everything is good so far, to avoid overwriting bad state if ($IsRequiredParametersPresentAndValid) { $IsRequiredParametersPresentAndValid = $ReturnedData[1] } # Validate gateway and DNS for one NIC if ($ReturnedData[2]) { $SkipGatewayAndDNSValidation = $true } } return $Errors, $IsRequiredParametersPresentAndValid } function Confirm-RMStaticNetworkConfig { param( [RMVSphereBaseNetworkConfiguration] $NetworkConfig, [string] $NetworkConfigPrefix, [string] $NICName, [bool] $SkipGatewayAndDNS ) $Errors = @() $IsRequiredParametersPresentAndValid = $true if ([string]::IsNullOrWhiteSpace($NetworkConfig.IPAddress)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " IPAddress is required, when IPType is 'static'" } else { $Errors += $NetworkConfigPrefix + " IPAddress is required for " + $NICName + ", when IPType is 'static'" } $IsRequiredParametersPresentAndValid = $false } else { if (!(Confirm-RMIPAddress -IPAddress $NetworkConfig.IPAddress)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " IPAddress is not valid" } else { $Errors += $NetworkConfigPrefix + " IPAddress is not valid for $NICName" } $IsRequiredParametersPresentAndValid = $false } } if ([string]::IsNullOrWhiteSpace($NetworkConfig.Netmask)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " Netmask is required, when IPType is 'static'" } else { $Errors += $NetworkConfigPrefix + " Netmask is required for " + $NICName + ", when IPType is 'static'" } $IsRequiredParametersPresentAndValid = $false } else { if (!(Confirm-RMIPAddress -IPAddress $NetworkConfig.Netmask)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " Netmask is not valid" } else { $Errors += $NetworkConfigPrefix + " Netmask is not valid for $NICName" } $IsRequiredParametersPresentAndValid = $false } } if ($SkipGatewayAndDNS) { return $Errors, $IsRequiredParametersPresentAndValid, $false } $IsValidGatewayAndDNS = $true if ([string]::IsNullOrWhiteSpace($NetworkConfig.DefaultGateway)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " DefaultGateway is required, when IPType is 'static'" } else { $Errors += $NetworkConfigPrefix + " DefaultGateway is required for " + $NICName + ", when IPType is 'static'" } $IsRequiredParametersPresentAndValid = $false $IsValidGatewayAndDNS = $false } else { if (!(Confirm-RMIPAddress -IPAddress $NetworkConfig.DefaultGateway)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " DefaultGateway is not valid" } else { $Errors += $NetworkConfigPrefix + " DefaultGateway is not valid for $NICName" } $IsRequiredParametersPresentAndValid = $false $IsValidGatewayAndDNS = $false } } if ([string]::IsNullOrWhiteSpace($NetworkConfig.PrimaryDNS)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " PrimaryDNS is required, when IPType is 'static'" } else { $Errors += $NetworkConfigPrefix + " PrimaryDNS is required for " + $NICName + ", when IPType is 'static'" } $IsRequiredParametersPresentAndValid = $false $IsValidGatewayAndDNS = $false } else { if (!(Confirm-RMIPAddress -IPAddress $NetworkConfig.PrimaryDNS)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " PrimaryDNS is not valid" } else { $Errors += $NetworkConfigPrefix + " PrimaryDNS is not valid for $NICName" } $IsRequiredParametersPresentAndValid = $false $IsValidGatewayAndDNS = $false } } if (![string]::IsNullOrWhiteSpace($NetworkConfig.SecondaryDNS)) { if (!(Confirm-RMIPAddress -IPAddress $NetworkConfig.PrimaryDNS)) { if ([string]::IsNullOrEmpty($NICName)) { $Errors += $NetworkConfigPrefix + " SecondaryDNS is not valid" } else { $Errors += $NetworkConfigPrefix + " SecondaryDNS is not valid for $NICName" } } } return $Errors, $IsRequiredParametersPresentAndValid, $IsValidGatewayAndDNS } function Confirm-RMIPType { param ( [RMVSphereBaseNetworkConfiguration] $NetworkConfig ) if ($NetworkConfig.IPType -ine "dhcp" -and $NetworkConfig.IPType -ine "static") { return $false } return $true } function Confirm-RMvSphereParameter { param( [hashtable] $UserParameter ) $Errors = @() $IsRequiredParametersPresentAndValid = $true if (!$UserParameter.ContainsKey("DatacenterName") -or [string]::IsNullOrWhiteSpace($UserParameter["DatacenterName"])) { $Errors += "DatacenterName is required." $IsRequiredParametersPresentAndValid = $false } if (!$UserParameter.ContainsKey("ClusterName") -or [string]::IsNullOrWhiteSpace($UserParameter["ClusterName"])) { $Errors += "ClusterName is required" $IsRequiredParametersPresentAndValid = $false } return $Errors, $IsRequiredParametersPresentAndValid } function Get-RMCoresPerSocket { param ( [int] $TargetVMVCPUCount ) $CoresPerSocketList = @() for ([int]$i = 1; $i -lt $TargetVMVCPUCount+1; $i++) { if ($TargetVMVCPUCount % $i -eq 0) { $CoresPerSocketList += $i } } return $CoresPerSocketList } Export-ModuleMember -Function Start-RMInteractiveVSphereOSBasedMigration, Start-RMNonInteractiveVsphereOsBasedMigration, ` Start-RMInteractiveVSphereVMBasedMigration, Start-RMNonInteractiveVsphereVMBasedMigration |