Migration/vSphere/vSphere.psm1
Import-Module -Name $PSScriptRoot\..\..\MigrationProfile\VSphereMigrationProfile Import-Module -Name $PSScriptRoot\..\..\DifferentialProfile\DifferentialProfile Import-Module -Name $PSScriptRoot\..\..\Preflight\Preflight Import-Module -Name $PSScriptRoot\..\..\Util\Util Import-Module -Name $PSScriptRoot\..\..\Util\MigrationUtil Import-Module -Name $PSScriptRoot\..\..\CloudAccount\CloudAccount Import-Module -Name $PSScriptRoot\..\..\RiverMeadow.Source\SourceUtil\SourceUtil Import-Module -Name $PSScriptRoot\..\..\Validate\Validate Import-Module -Name $PSScriptRoot\..\..\Common\Common Import-Module -Name $PSScriptRoot\..\..\Common\Wrappers\Wrappers function Start-RMNonInteractiveVsphereOsBasedMigration { param ( [string] $CloudAccountName, [string] $SourceIP, [bool] $RefreshSourceAttributes, [string] $TargetVMName, [string[]] $MountPoints, [string[]] $ResizeMountPoints, [string] $TransferMethod, [string] $CoresPerSocket, [bool] $OverrideMemory, [int] $OverrideMemorySize, [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] $RemoveRMSAgent, [hashtable] $MigrationInstructions, [string] $UpgradeOSVersion ) $Errors, $Warnings = Confirm-RMvSphereFullMigrationParameter $PSBoundParameters $CloudAccount = $null $Source = $null try { if (![string]::IsNullOrEmpty($CloudAccountName)) { $CloudAccount = Get-RMCloudAccountByName -CloudAccountName $CloudAccountName } } catch [System.Management.Automation.ItemNotFoundException] { Write-RMError -Message $PSItem Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings # We cannot do much without a valid cloud account, hence return. return } try { if ($null -ne $CloudAccount -and ![string]::IsNullOrEmpty($SourceIP)) { $Source = Get-RMSourceWithAttribute -IPAddress $SourceIP -RefreshSourceAttributes $RefreshSourceAttributes -CloudAccount $CloudAccount } } catch [System.Management.Automation.ItemNotFoundException] { Write-RMError -Message $PSItem Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings # There is no migration without a source, hence return. return } if ($null -ne $Source) { $Errors += Confirm-RMvSphereFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source } Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings if ($Errors.Count -gt 0) { return } $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) $SourceMountPoints = Get-MountPoint -Source $Source Compare-RMMountPoint -Source $Source -SourceMountPoints $SourceMountPoints -UserInputMountPoints $MountPoints $SelectedMountPoints = Get-RMSelectedMount -MountPoints $SourceMountPoints -DifferenceList $MountPoints -IncludeEqual $true $UserInput.Add("SelectedMounts", $SelectedMountPoints) $MountsResize = @{} if (![string]::IsNullOrEmpty($ResizeMountPoints)) { $MountsResize = Get-RMResizeMountsPoint -ResizeMountPoints $ResizeMountPoints -SelectedMountPoints $SelectedMountPoints -Source $Source if ("" -ne $TransferMethod -and "block-based" -eq $TransferMethod ) { throw "Transfer method needs to be 'file-based' if you want to resize the mount points." } else { $TransferMethod = "file-based" } } elseif ("" -eq $TransferMethod) { $TransferMethod = Get-RMTransferMethod -Source $Source } $UserInput.Add("ResizeMountPoints", $MountsResize) $UserInput.Add("TransferType", $TransferMethod) if ("" -eq $CoresPerSocket) { $CoresPerSocket = 1 } $UserInput.Add("CoresPerSocket", $CoresPerSocket) $UserInput.Add("OverrideMemory", $OverrideMemory) $UserInput.Add("OverrideMemorySize", $OverrideMemorySize) 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-DestinationNetworkAndDvSwitchName -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-DestinationNetworkAndDvSwitchName -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) if ($DatastoreNames.Count -ne $Source.attributes.storage.disks.psobject.Properties.Value.Count) { Throw "The number of datastore names given are '" + $DatastoreNames.Count + "' but source has '" + $Source.attributes.storage.disks.psobject.Properties.Value.Count +"' disks" } $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) { Throw "Invalid hardware version: $HardwareVersion" } } $UserInput.Add("HardwareVersion", $HardwareVersion) $UserInput.Add("ToolsPackage", $ToolsPackage) if ("" -eq $MigrationInstructions) { $MigrationInstructions = @{} } $UserInput.Add("MigrationInstructions", $MigrationInstructions) $UserInput.Add("ShutdownSource", $ShutdownSource) $UserInput.Add("ShutdownTarget", $ShutdownTarget) $UserInput.Add("RemoveRMSAgent", $RemoveRMSAgent) if ("" -ne $UpgradeOSVersion) { $SourceOSMMapping = Get-RMOSMMappingBySource -Source $Source $UpgradeOSVersion = $UpgradeOSVersion.Trim('"') $UpgradeOSVersion = $UpgradeOSVersion.Trim("'") $UserInput.Add("UpgradeOSVersion", $SourceOSMMapping[$UpgradeOSVersion]) $UserInput.Add("InPlaceUpgrade", $true) } else { $UserInput.Add("UpgradeOSVersion", $null) $UserInput.Add("InPlaceUpgrade", $false) } $Valid = Confirm-RMVSphereValidateOSBasedMigrationProfile @UserInput if (!$Valid) { return } $UserInput["DisksProvisioningType"] = Update-DiskProvisioningTypeForME -DiskProvisioningTypes $UserInput["DisksProvisioningType"] $Response = New-RMVSphereMigrationProfile @UserInput $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" } $Response = Invoke-RMRestMethod -Params $Params Out-MigrationIdFromResponse -Response $Response } function Start-RMInteractiveVSphereOSBasedMigration { param( ) $Entitlement = Get-RMEntitlement $CloudAccountName = Read-Host "Enter cloud account name" $CloudAccount = Get-RMCloudAccountByName -CloudAccountName $CloudAccountName if ($null -eq $CloudAccount) { $ProjectName = Get-Variable -Name "RMContext-CurrentProjectName" -ValueOnly $OrgName = Get-Variable -Name "RMContext-CurrentOrganizationName" -ValueOnly throw "Cloud account '$CloudAccountName' does not exist in current project '$ProjectName' of organization '$OrgName'" } $Source = $null $SourceIP = Read-Host "Enter the IP address of the source machine to be migrated" if ("" -eq $SourceIP) { throw "Source IP address is required to start a migration." } $RefreshSourceAttributes = $false $ReadValue = Read-Host "Refresh source attributes (true/false)[false]" if ("" -ne $ReadValue) { $RefreshSourceAttributes = [System.Convert]::ToBoolean($ReadValue) } $Source = Get-RMSourceWithAttribute -IPAddress $SourceIP -RefreshSourceAttributes $RefreshSourceAttributes -CloudAccount $CloudAccount $TargetInventory = Get-RMTargetInventory -CloudAccount $CloudAccount $TargetVMName = $Source.hostname $ReadValue = Read-Host "Enter target VM Name [$TargetVMName]" if ("" -ne $ReadValue) { $TargetVMName = $ReadValue } $MountPoints = Get-MountPoint -Source $Source if (0 -eq $MountPoints.count) { Write-RMError -Message "Source has no mount points, cannot be migrated" return } $MountPointsAsString = $MountPoints.values -join ", " Write-Output "Mount points to be migrated [$MountPointsAsString]" | Out-Host $ExcludedMountPoints = Get-RMExcludedMountPoint -Source $Source $SelectedMountPoints = $MountPoints if ("" -ne $ExcludedMountPoints) { $ExcludedList = $ExcludedMountPoints.Split(",").Trim() $SelectedMountPoints = Get-RMSelectedMount -MountPoints $MountPoints -DifferenceList $ExcludedList -IncludeEqual $false } $ReadValue = Read-Host "Resize mount points (true/false) [false]" $MountsResize = @{} $ResizeMountsBool = $false if ("" -ne $ReadValue) { $ReadValue = [System.Convert]::ToBoolean($ReadValue) if ($ReadValue) { $ResizeMountsBool = $true $MountsResize = Get-RMInteractiveMountsResize -SelectedMountPoints $SelectedMountPoints -Source $Source } } if (!$ResizeMountsBool) { $TransferType = Get-RMTransferMethod -Source $Source $ReadValue = Read-Host "Enter transfer type (file-based/block-based)[$TransferType]" if ("" -ne $ReadValue) { $TransferType = $ReadValue } } else { $TransferType = "file-based" } $CoresPerSocket = 1 $ReadValue = Read-Host "Enter cores per socket (1,2)[1]" if ("" -ne $ReadValue) { if (!($ReadValue -eq "1" -or $ReadValue -eq "2")) { Throw "Cores per socket can be 1 or 2" } $CoresPerSocket = $ReadValue } $OverrideMemory = $false $ReadValue = Read-Host "Override memory (true/false)[false]" if ("" -ne $ReadValue) { $OverrideMemory = [System.Convert]::ToBoolean($ReadValue) if ($OverrideMemory) { $OverrideMemorySize = Read-Host "Enter the memory in GB" } } $DatacenterNames = Get-DatacenterList -TargetInventory $TargetInventory $DatecenterNamesAsString = $DatacenterNames -join ", " $DatacenterName = Read-Host "Enter datacenter name ($DatecenterNamesAsString)" if ("" -eq $DatacenterName) { Throw "Datacenter name is required" } elseif (!($DatacenterName -in $DatacenterNames)) { Throw "Datacenter '$DatacenterName' does not exists." } $NetworkNames = Get-NetworkName -TargetInventory $TargetInventory -datacenterName $DatacenterName $NetworkNamesAsString = $NetworkNames -join ", " $EnableDestinationNetworkIsolation = $false if ($Source.os_type -eq "windows") { $ReadValue = Read-Host "Enable Destination network isolation (true/false)[false]" if ("" -ne $ReadValue) { $EnableDestinationNetworkIsolation = [System.Convert]::ToBoolean($ReadValue) if ($EnableDestinationNetworkIsolation) { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-MigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-DestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames -NetworkNamesAsString $NetworkNamesAsString -IsInteractive $true $IsolatedNetworkName = Read-Host "Enter isolated network name ($NetworkNamesAsString)" if ("" -eq $IsolatedNetworkName) { Throw "Isolated network name is required" } elseif(!($IsolatedNetworkName -in $NetworkNames)) { Throw "Isolated network name '$IsolatedNetworkName' does not exists." } [string[]] $networkNamesArray = $IsolatedNetworkName -split "/" if ($networkNamesArray.Count -eq 2) { $IsolatedNetworkName = $networkNamesArray[1] $IsolatedDvSwitchName = $networkNamesArray[0] } $IsolatedIPType = "dhcp" $ReadValue = Read-Host "Enter isolated IP type (static/DHCP)[DHCP]" if ("" -ne $ReadValue) { if (!($ReadValue -ieq "static" -or $ReadValue -ieq "DHCP")) { Throw "IP type can be 'static' or 'DHCP'" } $IPType = $ReadValue.ToLower() } if ($ReadValue -ieq "static") { $IsolatedIPType = $ReadValue $IsolatedIPAddress = Read-Host "Enter isolated IP address" $IsolatedNetmask = Read-Host "Enter isolated netmask" $IsolatedDefaultGateway = Read-Host "Enter isolated default gateway" $IsolatedPrimaryDNS = Read-Host "Enter isolated primary DNS" $IsolatedSecondaryDNS = Read-Host "Enter isolated Secondary DNS" } } else { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-MigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-DestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames -NetworkNamesAsString $NetworkNamesAsString -IsInteractive $true } } else { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-MigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-DestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames -NetworkNamesAsString $NetworkNamesAsString -IsInteractive $true } } else { $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS = Get-MigrationNetworkIPConfig $DestinationNetworkName, $DvSwitchName = Get-DestinationNetworkAndDvSwitchName -NetworkNames $NetworkNames -NetworkNamesAsString $NetworkNamesAsString -IsInteractive $true } if ($Source.os_type -eq "windows") { $DisableAutomaticDNSRegistrationOnTheTarget = $false $ReadValue = Read-Host "Disable automatic DNS registration on the Target (true/false)[false]" if ("" -ne $ReadValue) { $DisableAutomaticDNSRegistrationOnTheTarget = [System.Convert]::ToBoolean($ReadValue) } } else { $DisableAutomaticDNSRegistrationOnTheTarget = $false } $Clusters = Get-Cluster -TargetInventory $TargetInventory -datacenterName $DatacenterName $ClustersAsString = $Clusters -join ", " $ClusterName = Read-Host "Enter cluster name ($ClustersAsString)" if ("" -eq $ClusterName) { Throw "Cluster name is required" } elseif(!($ClusterName -in $Clusters)) { Throw "Cluster '$ClusterName' does not exists." } $ResourcePoolName = Read-Host "Enter resource pool [None]" $FolderName = Read-Host "Enter VM folder name [None]" $DatastoreClusters = Get-Datastore-Cluster -TargetInventory $TargetInventory -datacenterName $DatacenterName $DatastoreClustersAsString = $DatastoreClusters -join ", " $ReadValue = Read-Host "Enter datastore cluster ($DatastoreClustersAsString)[None]" if ("" -ne $ReadValue) { if (!($ReadValue -in $DatastoreClusters)) { Throw "Datastore cluster '$ReadValue' does not exists." } $DatastoreClusterName = $ReadValue } $Datastores = Get-Datastore -TargetInventory $TargetInventory -datacenterName $DatacenterName $SelectedDatastores = Get-DatastoreBySource -Source $Source -TargetDatastores $Datastores -IsInteractive $true $SelectedProvisioningTypes = Get-DiskProvisioningTypeBySource -Source $Source -IsInteractive $true $HardwareVersions, $DefaultHardwareVersion, $ToolsPackage = Get-RMHardwareVersionsAndToolsVersion -CloudAccount $CloudAccount $HardwareVersionString = $HardwareVersions -join ", " $HardwareVersion = Read-Host "Enter VM hardware version ($HardwareVersionString)[$DefaultHardwareVersion]" if ("" -eq $HardwareVersion) { $HardwareVersion = $DefaultHardwareVersion } $ShutdownSource = $false $ReadValue = Read-Host "Shutdown source after data is fully migrated (true/false)[false]" if ("" -ne $ReadValue) { $ShutdownSource = [System.Convert]::ToBoolean($ReadValue) } $ShutdownTarget = $false $ReadValue = Read-Host "Shutdown target after data is fully migrated (true/false)[false]" if ("" -ne $ReadValue) { $ShutdownTarget = [System.Convert]::ToBoolean($ReadValue) } $SourceOSMMapping = Get-RMOSMMappingBySource -Source $Source $OSMLabels = $SourceOSMMapping.keys -join ", " $ReadValue = Read-Host "Enter the OS version to upgrade to ($OSMLabels)[None]" if ("" -ne $ReadValue) { $ReadValue = $ReadValue.Trim('"') $ReadValue = $ReadValue.Trim("'") if ($SourceOSMMapping.keys -notcontains $ReadValue) { throw "Please enter one of $OSMLabels and try again" } $UpgradeOSVersion = $SourceOSMMapping[$ReadValue] $InPlaceUpgrade = $true } else { $UpgradeOSVersion = $null $InPlaceUpgrade = $false } $RemoveRMSAgent = $false $ReadValue = Read-Host "Remove RMS agent post migration (true/false)[false]" if ("" -ne $ReadValue) { $RemoveRMSAgent = [System.Convert]::ToBoolean($ReadValue) } $ReadValue = Read-Host "Enter migration instructions in the format 'key/value' and separated by commas [None]" $MigrationInstructions = Get-RMStringAsHashtable -InputString $ReadValue $HashArguments = @{ CloudAccount = $CloudAccount Entitlement = $Entitlement Source = $Source TargetVMName = $TargetVMName SelectedMounts = $SelectedMountPoints ResizeMountPoints = $MountsResize ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget RemoveRMSAgent = $RemoveRMSAgent 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 CoresPerSocket = $CoresPerSocket OverrideMemory = $OverrideMemory OverrideMemorySize = $OverrideMemorySize ResourcePoolName = $ResourcePoolName HardwareVersion = $HardwareVersion ToolsPackage = $ToolsPackage MigrationInstructions = $MigrationInstructions UpgradeOSVersion = $UpgradeOSVersion InPlaceUpgrade = $InPlaceUpgrade } $Response = New-RMVSphereMigrationProfile @HashArguments $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 Out-MigrationIdFromResponse -Response $MigrationResponse } function Start-RMVSphereOSBasedDifferentialMigration { param ( [string] $MigrationId ) Import-Module -Name $PSScriptRoot\..\..\DifferentialProfile\DifferentialProfile -Force $OrganizationId = Get-Variable -Name "RMContext-CurrentProjectId" -ValueOnly $Name = "PowerShell - Differential Profile - " + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() $Entitlement = Get-RMEntitlement $Migration = Get-RMMigrationByIdAndStatus -MigrationId $MigrationId -StatusOnly $true $MigrationProfile = Get-MigrationProfile -MigrationProfileId $Migration.migration_profile $Source = @{ "host" = $Migration.hostname } $TransferType = $Migration.transfer_type $TargetProperties = $Migration.target.properties $MigrationInstructions = $Migration.migration_instructions $HashArguments = @{ Name = $Name Entitlement = $Entitlement OrganizationId = $OrganizationId Description = $Description ApplianceId = $MigrationProfile.appliance_id Schedule = $Schedule TransferMode = $TransferMode MigrationId = $Migration.id SourceId = $Migration.source_id Target = $Target Source = $Source ShutdownSource = $false ShutdownTarget = $false RemoveTargetAgent = $false PublishMigrationHub = $false TransferType = $TransferType MigrationInstructions = $MigrationInstructions TargetProperties = $TargetProperties TargetIp = $Migration.target.ip } $Response = New-RMDifferentialProfile @HashArguments $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 + "/differentialprofiles/" + $Response.id + "/migrations" Headers = $Headers ContentType = "application/json" } return Invoke-RMRestMethod -Params $Params |Out-Null } 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-DatacenterList { param( [System.Object] $TargetInventory ) $DatacenterNames = @() foreach ($datacenterName in $TargetInventory.attributes.vSphere.datacenters) { $DatacenterNames += $datacenterName.name } return $DatacenterNames } function Get-NetworkName { 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) } } } } return $NetworkNames } function Get-Cluster { 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 } } } return $Clusters } function Get-Datastore-Cluster { 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 } } } return $DatastoreClusters } function Get-Datastore { param ( [System.Object] $TargetInventory, [string] $datacenterName ) $Datastores = @() foreach ($datacenter in $TargetInventory.attributes.vSphere.datacenters) { if ($datacenterName -eq $datacenter.name) { foreach($datastore in $datacenter.datastores) { $Datastores += $datastore.name } } } 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-MigrationNetworkIPConfig { $IPType = "dhcp" $ReadValue = Read-Host "Enter IP type (static/DHCP)[DHCP]" if ("" -ne $ReadValue) { if (!($ReadValue -ieq "static" -or $ReadValue -ieq "DHCP")) { Throw "IP type can be 'static' or 'DHCP'" } $IPType = $ReadValue.ToLower() } $IPAddress = "" $Netmask = "" $DefaultGateway = "" $PrimaryDNS = "" $SecondaryDNS = "" if ($IPType -ieq "static") { $IPAddress = Read-Host "Enter IP address" $Netmask = Read-Host "Enter netmask" $DefaultGateway = Read-Host "Enter default gateway" $PrimaryDNS = Read-Host "Enter primary DNS" $SecondaryDNS = Read-Host "Enter Secondary DNS" } return $IPType, $IPAddress, $Netmask, $DefaultGateway, $PrimaryDNS, $SecondaryDNS } function Get-DatastoreBySource { param( [System.Object] $Source, [string[]] $TargetDatastores, [bool] $IsInteractive ) if (!$IsInteractive) { Throw "The function Get-DatastoreBySource does not support non-interactive case" } if ($TargetDatastores.Count -eq 0) { Throw "No datastores were found, migration cannot be started." } $TargetDatastoresAsString = $TargetDatastores -join ", " $Datastores = @() $SortedDisks = $Source.attributes.storage.disks.psobject.Properties.Value | Sort-Object -property device foreach ($Disk in $SortedDisks) { if ($IsInteractive) { $Size = $Disk.size_kb/(1024*1024) $Size = [math]::round($Size, 2) $DefaultDatastore = $TargetDatastores[0] $ReadValue = Read-Host "Enter the datastore name for disk of size $Size GiB ($TargetDatastoresAsString)[$DefaultDatastore]" if ("" -ne $ReadValue) { if (!($ReadValue -in $TargetDatastores)) { Throw "Datastore '$ReadValue' does not exist in the given cluster" } $Datastores += $ReadValue.Trim() } else { $Datastores += $DefaultDatastore } } } 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) $ProvisioningTypesAsString = $ProvisioningTypes -join ", " $ReadValue = Read-Host "Enter disk provisioning type for disk of size $Size GiB ($ProvisioningTypesAsString)[thin]" if ("" -ne $ReadValue) { if (!($ReadValue -in $ProvisioningTypes)) { Throw "Disk provisioning type '$ReadValue' is not valid" } $ResultProvisioningTypes += $ReadValue.Trim() } else { $ResultProvisioningTypes += "thin" } } 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-DestinationNetworkAndDvSwitchName { param( [string[]] $NetworkNames, [string] $NetworkNamesAsString, [string] $DestinationNetworkName, [bool] $IsInteractive ) if ($IsInteractive) { $DestinationNetworkName = Read-Host "Enter destination network name ($NetworkNamesAsString)" if ([string]::IsNullOrEmpty($DestinationNetworkName)) { Throw "Destination network name is required" } elseif (!($DestinationNetworkName -in $NetworkNames)) { Throw "Destination network name '$DestinationNetworkName' does not exists." } } else { if ([string]::IsNullOrEmpty($DestinationNetworkName)) { Throw "Destination network name is required" } } $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 = Confirm-RMCommonParameter -UserParameter $UserParameter if ($UserParameter.ContainsKey("OverrideMemory") -and $UserParameter["OverrideMemory"] -eq $true ) { if (!$UserParameter.ContainsKey("OverrideMemorySize") -or $UserParameter["OverrideMemorySize"] -eq 0) { $Errors += "OverrideMemorySize is required, when the parameter 'OverrideMemory' is true." } } 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." } if (!$UserParameter.ContainsKey("Netmask") -or [string]::IsNullOrEmpty($UserParameter["Netmask"])) { $Errors += "Netmask is required." } if (!$UserParameter.ContainsKey("DefaultGateway") -or [string]::IsNullOrEmpty($UserParameter["DefaultGateway"])) { $Errors += "DefaultGateway is required." } if (!$UserParameter.ContainsKey("PrimaryDNS") -or [string]::IsNullOrEmpty($UserParameter["PrimaryDNS"])) { $Errors += "PrimaryDNS is required." } } if (!$UserParameter.ContainsKey("ClusterName") -or [string]::IsNullOrEmpty($UserParameter["ClusterName"])) { $Errors += "Cluster is required" } return $Errors, $Warnings } 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." } if (!$UserParameter.ContainsKey("IsolatedNetmask") -or [string]::IsNullOrEmpty($UserParameter["IsolatedNetmask"])) { $Errors += "IsolatedNetmask is required." } if (!$UserParameter.ContainsKey("IsolatedDefaultGateway") -or [string]::IsNullOrEmpty($UserParameter["IsolatedDefaultGateway"])) { $Errors += "IsolatedDefaultGateway is required." } if (!$UserParameter.ContainsKey("IsolatedPrimaryDNS") -or [string]::IsNullOrEmpty($UserParameter["IsolatedPrimaryDNS"])) { $Errors += "IsolatedPrimaryDNS is required." } } } $Errors += Confirm-RMCommonParameterWithSource -UserParameter $UserParameter -Source $Source return $Errors } Export-ModuleMember -Function Start-RMInteractiveVSphereOSBasedMigration, Start-RMNonInteractiveVsphereOsBasedMigration, ` Start-RMVSphereOSBasedDifferentialMigration |