Migration/vSphere/vSphere.psm1
using module '../../Common/Result' 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.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) function Start-RMNonInteractiveVsphereOsBasedMigration { param ( [string] $TargetCloud, [string] $SourceIP, [string] $ScheduledAt, [string] $TargetVMName, [string[]] $MountPoints, [string[]] $ResizeMountPoints, [string] $TransferMethod, [int] $TargetVMVCPUCount, [string] $CoresPerSocket, [int] $TargetVMMemorySize, [string] $DatacenterName, [bool] $EnableDestinationNetworkIsolation, [string] $DestinationNetworkName, [string] $IPType, [string] $IPAddress, [string] $Netmask, [string] $DefaultGateway, [string] $PrimaryDNS, [string] $SecondaryDNS, [string] $IsolatedNetworkName, [string] $IsolatedIPType, [string] $IsolatedIPAddress, [string] $IsolatedNetmask, [string] $IsolatedDefaultGateway, [string] $IsolatedPrimaryDNS, [string] $IsolatedSecondaryDNS, [bool] $DisableAutomaticDNSRegistrationOnTheTarget, [string] $ClusterName, [string] $ResourcePoolName, [string] $FolderName, [string] $DatastoreClusterName, [string[]] $DatastoreNames, [string[]] $DiskProvisioningTypes, [int] $HardwareVersion, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $RemoveRMSAgentFromSource, [bool] $RemoveRMSAgentFromTarget, [string[]] $MigrationInstructions, [string] $UpgradeOSVersion, [bool] $IgnoreValidationErrors ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent = 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.RuntimeException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } $ShouldExit = $false try { if (![string]::IsNullOrEmpty($SourceIP)) { $Source = Get-RMSourceByIP -IPAddress $SourceIP } } catch [System.Management.Automation.RuntimeException] { $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 = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn } catch [System.Management.Automation.RuntimeException] { $Errors += $PSItem.Exception.Message } if ($null -ne $Source) { $Errors += Confirm-RMvSphereFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source } $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 ($MountPoints.Count -gt 0) { $SelectedMountPoints = Get-RMSelectedMount -MountPoints $SourceMountPoints -DifferenceList $MountPoints -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 $ResizeMountPoints -and $ResizeMountPoints -gt 0) { $MountsResize, $MountsResizeErrors = Get-RMResizeMountsPoint -ResizeMountPoints $ResizeMountPoints -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) if ($Source.os_type -eq "windows" -and "" -ne $EnableDestinationNetworkIsolation -and $EnableDestinationNetworkIsolation) { if ([string]::IsNullOrEmpty($IPType)) { $IPType = "dhcp" } else { $IPType = $IPType.ToLower() } $UserInput.Add("IPType", $IPType) if ($IPType -ieq "static") { $UserInput.Add("IPAddress", $IPAddress) $UserInput.Add("Netmask", $Netmask) $UserInput.Add("DefaultGateway", $DefaultGateway) $UserInput.Add("PrimaryDNS", $PrimaryDNS) $UserInput.Add("SecondaryDNS", $SecondaryDNS) } $DestinationNetworkName, $DvSwitchName = Get-RMDestinationNetworkAndDvSwitchName -DestinationNetworkName $DestinationNetworkName -IsInteractive $false $UserInput.Add("DestinationNetworkName", $DestinationNetworkName) $UserInput.Add("DvSwitchName", $DvSwitchName) [string[]] $networkNames = $IsolatedNetworkName -split "/" if ($networkNames.Count -eq 2) { $IsolatedNetworkName = $networkNames[1] $IsolatedDvSwitchName = $networkNames[0] } $UserInput.Add("IsolatedNetworkName", $IsolatedNetworkName) $UserInput.Add("IsolatedDvSwitchName", $IsolatedDvSwitchName) if ([string]::IsNullOrEmpty($IsolatedIPType)) { $IsolatedIPType = "dhcp" } else { $IsolatedIPType = $IsolatedIPType.ToLower() } $UserInput.Add("IsolatedIPType", $IsolatedIPType) if ($IsolatedIPType -ieq "static") { $UserInput.Add("IsolatedIPAddress", $IsolatedIPAddress) $UserInput.Add("IsolatedNetmask", $IsolatedNetmask) $UserInput.Add("IsolatedDefaultGateway", $IsolatedDefaultGateway) $UserInput.Add("IsolatedPrimaryDNS", $IsolatedPrimaryDNS) $UserInput.Add("IsolatedSecondaryDNS", $IsolatedSecondaryDNS) } } else { $DestinationNetworkName, $DvSwitchName = Get-RMDestinationNetworkAndDvSwitchName -DestinationNetworkName $DestinationNetworkName -IsInteractive $false $UserInput.Add("DestinationNetworkName", $DestinationNetworkName) $UserInput.Add("DvSwitchName", $DvSwitchName) if ([string]::IsNullOrEmpty($IPType)) { $IPType = "dhcp" } else { $IPType = $IPType.ToLower() } $UserInput.Add("IPType", $IPType) if ($IPType -ieq "static") { $UserInput.Add("IPAddress", $IPAddress) $UserInput.Add("Netmask", $Netmask) $UserInput.Add("DefaultGateway", $DefaultGateway) $UserInput.Add("PrimaryDNS", $PrimaryDNS) $UserInput.Add("SecondaryDNS", $SecondaryDNS) } } $UserInput.Add("ClusterName", $ClusterName) $UserInput.Add("ResourcePoolName", $ResourcePoolName) $UserInput.Add("FolderName", $FolderName) $UserInput.Add("DatastoreClusterName", $DatastoreClusterName) $DiskProvisioningTypes = Get-DiskProvisioningTypeBySource -Source $Source -DiskProvisioningTypes $DiskProvisioningTypes -IsInteractive $false $UserInput.Add("DatastoreLocations", $DatastoreNames) $UserInput.Add("DisksProvisioningType", $DiskProvisioningTypes) $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 { $MigrationInstructionsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $MigrationInstructions -ParameterName "MigrationInstructions" } 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) Add-RMOSUpgrade -UserParameter $PSBoundParameters -UpdatedParameter $UserInput -Source $Source $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"] $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationErrors) $Response = New-RMVSphereMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Post" Uri = $Uri.Value + "/migrationprofiles/" + $Response.id + "/migrations" Headers = $Headers ContentType = "application/json" } $MigrationResponse = Invoke-RMRestMethod -Params $Params return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled } function Start-RMInteractiveVSphereOSBasedMigration { param( ) $Entitlement = Get-RMEntitlement $CloudAccount = Read-RMCloudAccount -AccountType "rivermeadow_standalone" $TargetInventory = Get-RMTargetInventory -CloudAccount $CloudAccount $Source = Read-RMSource $IgnoreValidationErrors = Read-RMBoolean -UserMessage "Ignore validation errors" -DefaultValue "false" [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Source, $ShouldExit = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { 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 -Source $Source -MountPoints $MountPoints $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 if ($Source.os_type -eq "windows") { $EnableDestinationNetworkIsolation = Read-RMBoolean -UserMessage "Enable destination network isolation" -DefaultValue "false" if ($EnableDestinationNetworkIsolation) { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-RMMigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-RMDestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames ` -IsInteractive $true $IsolatedNetworkName = Read-RMString -UserMessage "Enter isolated network name" -Options $NetworkNames ` -ParameterName "Isolated network name" -IsRequired $true [string[]] $networkNamesArray = $IsolatedNetworkName -split "/" if ($networkNamesArray.Count -eq 2) { $IsolatedNetworkName = $networkNamesArray[1] $IsolatedDvSwitchName = $networkNamesArray[0] } $IsolatedIPType = "dhcp" $IPType = (Read-RMString -UserMessage "Enter isolated network IP type" -Options "static", "DHCP" -DefaultValue "DHCP" ` -ParameterName "Isolated network IP type" -IsRequired $false).ToLower() if ($IPType -ieq "static") { $IsolatedIPType = $IPType $IsolatedIPAddress = Read-RMIPAddress -UserMessage "Enter isolated network IP address" ` -ParameterName "Isolated network IP address" -IsRequired $true $IsolatedNetmask = Read-RMIPAddress -UserMessage "Enter isolated network netmask" ` -ParameterName "Isolated network netmask" -IsRequired $true $IsolatedDefaultGateway = Read-RMIPAddress -UserMessage "Enter isolated network default gateway" ` -ParameterName "Isolated network default gateway" -IsRequired $true $IsolatedPrimaryDNS = Read-RMIPAddress -UserMessage "Enter isolated network primary DNS" ` -ParameterName "Isolated network primary DNS" -IsRequired $true $IsolatedSecondaryDNS = Read-RMIPAddress -UserMessage "Enter isolated network secondary DNS" ` -ParameterName "Isolated network secondary DNS" -DefaultValue "None" -IsRequired $false } } else { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-RMMigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-RMDestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames -IsInteractive $true } } else { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-RMMigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-RMDestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames -IsInteractive $true } $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 $FolderName = Read-RMString -UserMessage "Enter VM folder name" -DefaultValue "None" ` -ParameterName "VM folder name" -IsRequired $false $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 $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-RMOSMUpgradeOption -Source $Source -UpdatedUserInput $OSMUpgradeUserInput $UpgradeOSVersion = $OSMUpgradeUserInput["UpgradeOSVersion"] $InPlaceUpgrade = $OSMUpgradeUserInput["InPlaceUpgrade"] $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" $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 DestinationNetworkName = $DestinationNetworkName IPType = $IPType IPAddress = $IPAddress Netmask = $Netmask DefaultGateway = $DefaultGateway PrimaryDNS = $PrimaryDNS SecondaryDNS = $SecondaryDNS IsolatedNetworkName = $IsolatedNetworkName IsolatedDvSwitchName = $IsolatedDvSwitchName IsolatedIPType = $IsolatedIPType IsolatedIPAddress = $IsolatedIPAddress IsolatedNetmask = $IsolatedNetmask IsolatedDefaultGateway = $IsolatedDefaultGateway IsolatedPrimaryDNS = $IsolatedPrimaryDNS IsolatedSecondaryDNS = $IsolatedSecondaryDNS DvSwitchName = $DvSwitchName 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 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) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Post" Uri = $Uri.Value + "/migrationprofiles/" + $Response.id + "/migrations" Headers = $Headers ContentType = "application/json" } $MigrationResponse = Invoke-RMRestMethod -Params $Params return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse -RMMigrationReturn $RMMigrationReturn ` -IsScheduledMigration $IsScheduled } 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-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-RMMigrationNetworkIPConfig { $IPType = "dhcp" $IPType = (Read-RMString -UserMessage "Enter IP type" -Options "static", "DHCP" -DefaultValue "DHCP" ` -ParameterName "IP Type" -IsRequired $false).ToLower() if ($IPType -ieq "dhcp") { return $IPType, "", "", "", "", "" } $IPAddress = Read-RMIPAddress -UserMessage "Enter IP address" -ParameterName "IP address" -IsRequired $true $Netmask = Read-RMIPAddress -UserMessage "Enter netmask" -ParameterName "Netmask" -IsRequired $true $DefaultGateway = Read-RMIPAddress -UserMessage "Enter default gateway" -ParameterName "Default gateway" -IsRequired $true $PrimaryDNS = Read-RMIPAddress -UserMessage "Enter primary DNS" -ParameterName "Primary DNS" -IsRequired $true $SecondaryDNS = Read-RMIPAddress -UserMessage "Enter secondary DNS" -ParameterName "Secondary DNS" -DefaultValue "None" -IsRequired $false return $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS } 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" } } 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 if (!$UserParameter.ContainsKey("DatacenterName") -or [string]::IsNullOrEmpty($UserParameter["DatacenterName"])) { $Errors += "DatacenterName is required." } if (!$UserParameter.ContainsKey("DestinationNetworkName") -or [string]::IsNullOrEmpty($UserParameter["DestinationNetworkName"])) { $Errors += "DestinationNetworkName is required." } if ($UserParameter.ContainsKey("IPType") -and $UserParameter["IPType"] -ieq "static") { if (!$UserParameter.ContainsKey("IPAddress") -or [string]::IsNullOrEmpty($UserParameter["IPAddress"])) { $Errors += "IpAddress is required." } else { $IsValidIPAddress = Confirm-RMIPAddress -IPAddress $UserParameter.IPAddress if (!$IsValidIPAddress) { $Errors += "Invalid IP address." } } if (!$UserParameter.ContainsKey("Netmask") -or [string]::IsNullOrEmpty($UserParameter["Netmask"])) { $Errors += "Netmask is required." } else { $IsValidNetmask = Confirm-RMIPAddress -IPAddress $UserParameter.Netmask if (!$IsValidNetmask) { $Errors += "Invalid Netmask." } } if (!$UserParameter.ContainsKey("DefaultGateway") -or [string]::IsNullOrEmpty($UserParameter["DefaultGateway"])) { $Errors += "DefaultGateway is required." } else { $IsValidDefaultGateway = Confirm-RMIPAddress -IPAddress $UserParameter.DefaultGateway if(!$IsValidDefaultGateway) { $Errors += "Invalid Default Gateway." } } if (!$UserParameter.ContainsKey("PrimaryDNS") -or [string]::IsNullOrEmpty($UserParameter["PrimaryDNS"])) { $Errors += "PrimaryDNS is required." } else { $IsValidPrimaryDNS = Confirm-RMIPAddress -IPAddress $UserParameter.PrimaryDNS if (!$IsValidPrimaryDNS) { $Errors += "Invalid Primary DNS." } } if ($UserParameter.ContainsKey("SecondaryDNS") -and ![string]::IsNullOrEmpty($UserParameter["SecondaryDNS"])) { $IsValidSecondaryDNS = Confirm-RMIPAddress -IPAddress $UserParameter.SecondaryDNS if (!$IsValidSecondaryDNS) { $Errors += "Invalid Secondary DNS." } } } if (!$UserParameter.ContainsKey("ClusterName") -or [string]::IsNullOrEmpty($UserParameter["ClusterName"])) { $Errors += "ClusterName is required" } return $Errors, $Warnings, $IsSourceAndTargetCloudPresent } function Confirm-RMvSphereFullMigrationParameterWithSource { param ( [hashtable] $UserParameter, [System.Object] $Source ) $Errors = @() if ($Source.os_type -ieq "windows" -and $UserParameter.ContainsKey("EnableDestinationNetworkIsolation") ` -and $UserParameter["EnableDestinationNetworkIsolation"] -eq $true) { if (!$UserParameter.ContainsKey("IsolatedNetworkName") -or [string]::IsNullOrEmpty($UserParameter["IsolatedNetworkName"])) { $Errors += "IsolatedNetworkName is required." } if ($UserParameter.ContainsKey("IsolatedIPType") -and $UserParameter["IsolatedIPType"] -ieq "static") { if (!$UserParameter.ContainsKey("IsolatedIPAddress") -or [string]::IsNullOrEmpty($UserParameter["IsolatedIPAddress"])) { $Errors += "IsolatedIpAddress is required." } else { $IsValidIsolatedIpAddress = Confirm-RMIPAddress -IPAddress $UserParameter.IsolatedIPAddress if (!$IsValidIsolatedIpAddress) { $Errors += "Invalid Isolated IP address." } } if (!$UserParameter.ContainsKey("IsolatedNetmask") -or [string]::IsNullOrEmpty($UserParameter["IsolatedNetmask"])) { $Errors += "IsolatedNetmask is required." } else { $IsValidIsolatedNetmask = Confirm-RMIPAddress -IPAddress $UserParameter.IsolatedNetmask if (!$IsValidIsolatedNetmask) { $Errors += "Invalid Isolated Netmask." } } if (!$UserParameter.ContainsKey("IsolatedDefaultGateway") -or [string]::IsNullOrEmpty($UserParameter["IsolatedDefaultGateway"])) { $Errors += "IsolatedDefaultGateway is required." } else { $IsValidIsolatedDefaultGatewayk = Confirm-RMIPAddress -IPAddress $UserParameter.IsolatedDefaultGateway if (!$IsValidIsolatedDefaultGatewayk) { $Errors += "Invalid Isolated Default Gateway." } } if (!$UserParameter.ContainsKey("IsolatedPrimaryDNS") -or [string]::IsNullOrEmpty($UserParameter["IsolatedPrimaryDNS"])) { $Errors += "IsolatedPrimaryDNS is required." } else { $IsValidIsolatedPrimaryDNS = Confirm-RMIPAddress -IPAddress $UserParameter.IsolatedPrimaryDNS if (!$IsValidIsolatedPrimaryDNS) { $Errors += "Invalid Isolated Primary DNS." } } if ($UserParameter.ContainsKey("IsolatedSecondaryDNS") -and ![string]::IsNullOrEmpty($UserParameter["IsolatedSecondaryDNS"])) { $IsValidIsolatedSecondaryDNS = Confirm-RMIPAddress -IPAddress $UserParameter.IsolatedSecondaryDNS if (!$IsValidIsolatedSecondaryDNS) { $Errors += "Invalid Isolated Secondary DNS." } } } } $HasDynamicDisks = Test-RMSourceHasDynamicDisks -Source $Source if ($HasDynamicDisks) { if (!$UserParameter.ContainsKey("DatastoreNames") -or [string]::IsNullOrEmpty($UserParameter["DatastoreNames"])) { $Errors += "DatastoreNames is required and since the source has dynamic disk(s), please provide only one datastore name." } elseif($UserParameter["DatastoreNames"].Count -gt 1) { $Errors += "Source has dynamic disks, please provide only one datastore name." } } else { if (!$UserParameter.ContainsKey("DatastoreNames") -or [string]::IsNullOrEmpty($UserParameter["DatastoreNames"])) { $Errors += "DatastoreNames is required." } } $Errors += Confirm-RMCommonParameterWithSource -UserParameter $UserParameter -Source $Source return $Errors } 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 |