Migration/GCP/GCP.psm1
using module '../../Common/Result' Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath MigrationProfile | Join-Path -ChildPath GCPMigrationProfile) 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 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 Common | Join-Path -ChildPath Common) 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 Common | Join-Path -ChildPath Wrappers | Join-Path -ChildPath Wrappers) Import-Module -Name @(Join-Path $PSScriptRoot GCPUtil) function Start-RMGCPOSBasedInteractiveMigration { param() $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "gcp" -UserMessage "Enter target cloud" $UserInput.Add("CloudAccount", $CloudAccount) $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount $Entitlement = Get-RMEntitlement $UserInput.Add("Entitlement", $Entitlement) $CloudAttributesSummary = Get-CloudAttributesSummary -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 "gcp" if ($ShouldExit) { return $RMMigrationReturn } $UserInput.Add("Source", $Source) 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.hostname ` -ParameterName "Target VM Name" -IsRequired $false $UserInput.Add("TargetVMName", $TargetVMName) #Placement Settings $ProjectMapping = Get-RMProjectIDToNameMapping -CloudAttribute $CloudAttributesSummary $DefaultProject = "" if ($ProjectMapping.ContainsKey($CloudAccount.appliance.cloud_properties.project_id)) { $DefaultProject = $ProjectMapping[$CloudAccount.appliance.cloud_properties.project_id] } $ProjectName = Read-RMString -UserMessage "Enter project name" -DefaultValue $DefaultProject -Options $ProjectMapping.values ` -ParameterName "Project Name" -IsRequired $false $ProjectId = ($ProjectMapping.GetEnumerator() | Where-Object {$_.Value -ieq $ProjectName}).Key $UserInput.Add("ProjectId", $ProjectId) $RegionsAndZones = Get-RMCloudAttributesByProjectId -CloudAccount $CloudAccount -ProjectId $ProjectId $RegionAndZoneMapping = Get-RMRegionToZonesMapping -RegionAndZone $RegionsAndZones.properties.projects[0].regions $Region = Read-RMString -UserMessage "Enter region name" -DefaultValue $CloudAccount.appliance.cloud_properties.region -Options $RegionAndZoneMapping.Keys ` -ParameterName "Region Name" -IsRequired $false $UserInput.Add("Region", $Region) $Zone = "" if ($Region -ieq $CloudAccount.appliance.cloud_properties.region) { $Zone = Read-RMString -UserMessage "Enter zone name" -DefaultValue $CloudAccount.appliance.cloud_properties.az ` -Options $RegionAndZoneMapping[$Region] -ParameterName "Zone Name" -IsRequired $false } else { $Zone = Read-RMString -UserMessage "Enter zone name" -Options $RegionAndZoneMapping[$Region] ` -ParameterName "Zone Name" -IsRequired $true } $UserInput.Add("Zone", $Zone) $UserInput.Add("NodeGroupName", (Read-RMNodeGroupName -CloudAttribute $CloudAttributes)) $UserInput.Add("MachineType", (Read-RMMachineType -CloudAttribute $CloudAttributes)) $MountPoint = Get-MountPoint -Source $Source if (0 -eq $MountPoint.count) { throw "Source has no mount points, cannot be migrated" } $MountPointsAsString = $MountPoint.values -join ", " Write-Output "Mount points to be migrated [$MountPointsAsString]" | Out-Host $ExcludedMountPoint = Get-RMExcludedMountPoint -OSType $Source.os_type -MountPoints $MountPoints.Values $SelectedMountPoint = $MountPoint if ("" -ne $ExcludedMountPoint) { $ExcludedList = $ExcludedMountPoint.Split(",").Trim() $SelectedMountPoint = Get-RMSelectedMount -MountPoints $MountPoints -DifferenceList $ExcludedList -IncludeEqual $false } $UserInput.Add("SelectedMount", $SelectedMountPoint) $UserInput.Add("DiskType", (Get-RMDiskTypeBySource -Source $Source -IsInteractive $true)) $DefaultNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name if ($Region -ine $CloudAccount.appliance.cloud_properties.region -or ` $Zone -ine $CloudAccount.appliance.cloud_properties.az -or ` $ProjectId -ine $CloudAccount.appliance.cloud_properties.project_id) { $CloudAttributes = Get-RMCloudAttributesByProjectIdAndRegionAndZone -CloudAccount $CloudAccount ` -ProjectId $ProjectId -Region $Region -Zone $Zone $DefaultNetworkName = "" } $NetworksWithSubnets = Get-RMNetworkToSubnetMapping -CloudAttribute $CloudAttributes $DestinationNetworkName = "" if ([string]::IsNullOrWhiteSpace($DefaultNetworkName)) { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" ` -Options $NetworksWithSubnets.keys -ParameterName "Destination Network Name" -IsRequired $true } else { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" ` -Options $NetworksWithSubnets.keys -DefaultValue $DefaultNetworkName ` -ParameterName "Destination Network Name" -IsRequired $false } $UserInput.Add("DestinationNetworkName", (Get-RMNetworkNameByUserInput -NetworkName $DestinationNetworkName)) if ($null -eq $NetworksWithSubnets) { Throw "No networks were found, please check if the networks exist in the selected project, region and zone" } $DefaultSubnetName = "" if ($DestinationNetworkName -ieq $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name) { $DefaultSubnetName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.internal_subnet_id } $SubnetNames = Get-RMSubnetNameByNetworkName -NetworkName $DestinationNetworkName -NetworkToSubnetMapping $NetworksWithSubnets if ([string]::IsNullOrWhiteSpace($DefaultSubnetName)) { $SubnetName = Read-RMString -UserMessage "Enter subnet name" -Options $SubnetNames ` -ParameterName "Subnet Name" -IsRequired $true } else { $SubnetName = Read-RMString -UserMessage "Enter subnet name" -DefaultValue $DefaultSubnetName ` -Options $SubnetNames -ParameterName "Subnet Name" -IsRequired $false } $UserInput.Add("SubnetName", $SubnetName) $IPType = "Ephemeral_Automatic" $IPtype = Read-RMString -UserMessage "Enter primary internal IP type" -Options "Ephemeral_Automatic", "Ephemeral_Custom" ` -DefaultValue "Ephemeral_Automatic" -ParameterName "Primary Internal IP" -IsRequired $false if ($IPtype -ieq "Ephemeral_Custom") { $UserInput.Add("CustomPrimaryInternalIPType", $true) #TODO: validate that the given IP address is in subnet's cidr block $PrimaryInternalIP = Read-RMIPAddress -UserMessage "Enter custom Ephemeral IP address" -IsRequired $true ` -ParameterName "Custom Ephemeral IP Address" $UserInput.Add("PrimaryInternalIP", $PrimaryInternalIP) } $ReadValue = Read-RMString -UserMessage "Do you want to assign external IP address to the target machine" ` -Options "None", "Automatic" -DefaultValue "None" -ParameterName "External IP Address" -IsRequired $false if ($ReadValue -ieq "Automatic") { $UserInput.Add("AssignPublicIP", $true) $UserInput.Add("NetworkTier", (Read-RMString -UserMessage "Enter network tier" -Options "Premium", "Standard" ` -DefaultValue "Premium" -ParameterName "Network Tier" -IsRequired $false).ToUpper()) } $ReadValue = Read-RMPair -UserMessage "Enter one or more instance labels in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue "None" $UserInput.Add("InstanceLabel", (Get-RMStringAsHashtable -InputString $ReadValue)) #Optimization Settings: $UserInput.Add("NetBIOSName", (Read-RMString -UserMessage "Enter NetBIOS name" -DefaultValue $Source.hostname ` -ParameterName "NetBIOS Name" -IsRequired $false)) $ProjectSettingsResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $KMSActivation = Read-RMBoolean -UserMessage "Enable KMS Activation" -DefaultValue "false" $KMSKey = $null if ($KMSActivation) { $KMSKey = "kms.windows.googlecloud.com" if ($null -ne $ProjectSettingsResponse.gcp.kms_fqdn) { $KMSKey = $ProjectSettingsResponse.gcp.kms_fqdn } } $UserInput.Add("KMSKey", $KMSKey) $Sysprep = $false if ("windows" -ieq $Source.os_type) { $Sysprep = Read-RMBoolean -UserMessage "Enable sysprep" -DefaultValue "false" } $UserInput.Add("GeneralizeSystem", $Sysprep) $MountsResize = @{} $ResizeMountPointsFlag = Read-RMBoolean -UserMessage "Resize mount points" -DefaultValue "false" if ($ResizeMountPointsFlag) { $MountsResize = Get-RMInteractiveMountsResize -SelectedMountPoints $SelectedMountPoint -Source $Source } $UserInput.Add("ResizeMountPoint", $MountsResize) $LinuxOSLicensing = $true $WindowsOSLicensing = $false if ("linux" -ieq $Source.os_type) { $LinuxOSLicensing = Read-RMBoolean -UserMessage "Premium OS licensing" -DefaultValue "true" } else { $WindowsOSLicensing = Read-RMBoolean -UserMessage "Bring your own OS license" -DefaultValue "false" } if (!$LinuxOSLicensing -or $WindowsOSLicensing) { $UserInput.Add("OSBYOL", "byol") } else { $UserInput.Add("OSBYOL", "") } if ("windows" -ieq $Source.os_type) { $SQLLicenses = Get-RMSQLLicenseMapping $SQLLicense = Read-RMString -UserMessage "Enter SQL license" -Options $SQLLicenses.Keys ` -DefaultValue "None" -IsRequired $false -ParameterName "SQL License" $UserInput.Add("SQLLicense", $SQLLicenses[$SQLLicense]) } else { $UserInput.Add("SQLLicense", "") } $MigrationExtensionResponse = Get-RMMigrationExtension -OrganizationId $CloudAccount.organization_id $MigrationExtensionArray, $MigrationExtensionOSMArray = Get-RMMigrationExtensionFromStep -MigrationExtensionArray $MigrationExtensionResponse.content Read-RMMigrationExtension -CloudAccount $CloudAccount -MigrationExtension $MigrationExtensionArray ` -MigrationExtensionObject $MigrationExtensionResponse.content -UpdatedUserInput $UserInput if ("windows" -ieq $Source.os_type -and !$KMSActivation) { $KMSItopia = Read-RMBoolean -UserMessage "Enable itopia KMS" -DefaultValue "false" if ($KMSItopia) { $UserInput["KMSKey"] = $ProjectSettingsResponse.gcp.itopia_kms_fqdn } } #Modernization Settings Read-RMOSUpgradeOption -Source $Source -UpdatedUserInput $UserInput if ($null -ne $UserInput['UpgradeOSVersion']) { Read-RMMigrationExtensionOSM -MigrationExtensionOSM $MigrationExtensionOSMArray -MigrationExtensionObject $MigrationExtensionResponse.content ` -UpdatedUserInput $UserInput } $SQLServerUpgrade = Read-RMSQLServerUpgradeOption -Source $Source $UserInput.Add("SQLServerUpgrade", $SQLServerUpgrade) #Security Settings $EnforceTargetNetworkIsolation = Read-RMBoolean -UserMessage "Enforce target network isolation" -DefaultValue "true" if (!$EnforceTargetNetworkIsolation) { $NetworkNameToNetworkTagsMapping = Get-RMNetworkNameToNetworkTagsMapping -CloudAttribute $CloudAttributes $NetworkTagOptions = $NetworkNameToNetworkTagsMapping[$DestinationNetworkName] $NetworkTagOptions += "rivermeadow-tw" $DefaultValue = "" if ("windows" -ieq $Source.os_type) { $NetworkTagOptions += "rivermeadow-ft-windows" $DefaultValue = "rivermeadow-tw, rivermeadow-ft-windows" } else { if ($null -ne $Source.control_connection_type -and "agent" -ieq $Source.control_connection_type) { $NetworkTagOptions += "rivermeadow-agent", "rivermeadow-ft-linux" $DefaultValue = "rivermeadow-tw, rivermeadow-agent, rivermeadow-ft-linux" } else { $NetworkTagOptions += "rivermeadow-ft-linux" $DefaultValue = "rivermeadow-tw, rivermeadow-ft-linux" } } $ReadValue = Read-RMToken -UserMessage "Enter one or more network tags separated by commas" ` -Options $NetworkTagOptions -DefaultValue $DefaultValue -Separator "," ` -ParameterName "Network Tags" -IsRequired $false if ($ReadValue -is [string]) { $NetworkTags += @($ReadValue.split(",").Trim()) } else { $NetworkTags += $ReadValue } if ("linux" -ieq $Source.os_type -and $NetworkTags -notcontains "rivermeadow-agent") { $NetworkTags += "rivermeadow-agent" } if ($NetworkTags -notcontains "rivermeadow-tw") { $NetworkTags += "rivermeadow-tw" } } else { $NetworkTags += "rivermeadow-tw" if ("linux" -ieq $Source.os_type) { if ($null -ne $Source.control_connection_type -and "agent" -ieq $Source.control_connection_type) { $NetworkTags += "rivermeadow-agent" } } } $UserInput.Add("NetworkTag", $NetworkTags) $UserInput.Add("EnforceTargetNetworkIsolation", $EnforceTargetNetworkIsolation) $UserInput.Add("EnableSerialPortAccess", (Read-RMBoolean -UserMessage "Enable remote access through serial port" -DefaultValue "false")) $NetworkTags = @() if ((Read-RMBoolean -UserMessage "Allow HTTP traffic through firewalls" -DefaultValue "false")) { $NetworkTags += "http-server" } if ((Read-RMBoolean -UserMessage "Allow HTTPS traffic through firewalls" -DefaultValue "false")) { $NetworkTags += "https-servers" } Read-RMOSHardening -UpdatedUserInput $UserInput -Source $Source #Advanced Settings: $TransferMethod = "file-based" if (!$ResizeMountPointsFlag) { $TransferMethod = (Get-RMTransferMethod -Source $Source -SelectedMountPoints $SelectedMountPoint -IsInteractive $true)[0] } $UserInput.Add("TransferMethod", $TransferMethod) $UserInput.Add("RemoveRMSAgent", (Read-RMBoolean -UserMessage "Remove RMS agent post migration" -DefaultValue "false")) $DisableTargetDNSRegistration = $false if ("windows" -ieq $Source.os_type) { $DisableTargetDNSRegistration = Read-RMBoolean -UserMessage "Disable automatic DNS registration on the target" -DefaultValue "false" } $UserInput.Add("DisableAutomaticDNSRegistrationOnTheTarget", $DisableTargetDNSRegistration) $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")) $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 ([string]::IsNullOrWhiteSpace($ReadValue)) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstructions = Get-RMStringAsHashtable -InputString $ReadValue $UserInput.Add("MigrationInstruction", $MigrationInstructions) $UserInput.Add("EnableNetAppFileMigration", (Read-RMBoolean -UserMessage "Enable NetApp file migration" -DefaultValue "false")) $UserInput.Add("MTUSize", $ProjectSettingsResponse.gcp.mtu_size) $Response = New-RMGCPMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrWhiteSpace($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMGCPOSBasedNonInteractiveMigration { param( [string] $TargetCloud, [string] $SourceIP, [string] $ScheduledAt, [string] $TargetVMName, [string[]] $MountPoint, [string[]] $ResizeMountPoint, [string] $ConvertFileSystem, [string] $TransferMethod, [string] $Project, [string] $Region, [string] $Zone, [bool] $MigrateToSoleTenantNode, [string] $NodeGroupName, [string] $MachineType, [string[]] $DiskType, [string[]] $InstanceLabel, [string] $DestinationNetworkName, [string] $SubnetName, [string] $PrimaryInternalIP, [string] $CustomEphemeralIPAddress, [string] $ExternalIP, [string] $NetworkTier, [bool] $DisableTargetDNSRegistration, [bool] $EnableSerialPortAccess, [bool] $AllowHTTPTraffic, [bool] $AllowHTTPSTraffic, [bool] $EnforceTargetNetworkIsolation, [string[]] $NetworkTag, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $OSBYOL, [string] $SQLLicense, [string] $OSModernization, [string] $UpgradeOSVersion, [string] $MigrationExtension, [string] $MigrationExtensionOSM, [hashtable[]] $UpgradeSQLServer, [bool] $RemoveRMSAgent, [string[]] $MigrationInstruction, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration, [bool] $EnableNetAppFileMigration, [string] $NetBIOSName, [bool] $KMSActivation, [bool] $Sysprep, [bool] $KMSItopia, [bool] $EnableOSHardening, [bool] $Level1Server, [bool] $Level2Server, [bool] $Level1Computer, [bool] $Level2Computer, [bool] $Level1User, [bool] $Level2User, [string] $AdministratorName, [string] $GuestName, [string] $LegalNoticeCaption, [string] $LegalNoticeText ) $CloudAccount = $null $Source = $null $IsSourceAndTargetCloudPresent = $true $Errors = @() $UserInput = @{} [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid = Confirm-RMGCPFullMigrationParameter $PSBoundParameters try { if (![string]::IsNullOrWhiteSpace($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "gcp" if (![string]::IsNullOrWhiteSpace($ErrorString)) { $Errors += $ErrorString $IsSourceAndTargetCloudPresent = $false } else { #TODO: Move this call after adding validation of user input through FE endpoint, at that time # this call should be just before we trigger validation. $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount } } } catch [System.Management.Automation.ItemNotFoundException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } $ShouldExit = $false try { if (![string]::IsNullOrWhiteSpace($SourceIP)) { $Source = Get-RMSourceByIP -IPAddress $SourceIP } } catch [System.Management.Automation.ItemNotFoundException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } 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 -RMMigrationReturn $RMMigrationReturn -AccountType "gcp" 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 } $MigrationExtensionResponse = Get-RMMigrationExtension -OrganizationId $CloudAccount.organization_id $MigrationExtensionArray, $MigrationExtensionOSMArray = Get-RMMigrationExtensionFromStep -MigrationExtensionArray $MigrationExtensionResponse.content $Entitlement = Get-RMEntitlement $SourceSQLServerMapping = Get-RMSQLMMappingBySource -Source $Source $Errors += Confirm-RMGCPFullMigrationParameterWithSource -UserParameter $PSBoundParameters ` -Source $Source -SourceSQLServerMapping $SourceSQLServerMapping -MigrationExtension $MigrationExtensionArray ` -MigrationExtensionOSM $MigrationExtensionOSMArray $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $CloudAttributesErrors += Confirm-RMCloudAttributes -UserParameter $PSBoundParameters -CloudAttribute $CloudAttributesSummary $ProjectId = $CloudAccount.appliance.cloud_properties.project_id $CloudAttributesProjectErrors = @() if ($CloudAttributesErrors.Count -eq 0) { if (![string]::IsNullOrWhiteSpace($Project)) { $ProjectObject = Get-RMProjectIdentifierByProjectName -ProjectObject $CloudAttributesSummary.properties.projects ` -ProjectName $Project $ProjectId = $ProjectObject.identifier } $CloudAttributesProject = Get-RMCloudAttributesByProjectId -CloudAccount $CloudAccount -ProjectId $ProjectId $CloudAttributesProjectErrors += Confirm-RMCloudAttributesProject -UserParameter $PSBoundParameters ` -CloudAttribute $CloudAttributesSummary -CloudAttributesProject $CloudAttributesProject if ($CloudAttributesProjectErrors.Count -gt 0) { $Errors += $CloudAttributesProjectErrors } } else { $Errors += $CloudAttributesErrors } if ([string]::IsNullOrWhiteSpace($TargetVMName)) { $TargetVMName = $Source.hostname } $SelectedMountPoint = $null $SourceMountPoint = Get-MountPoint -Source $Source if ($MountPoint.Count -gt 0) { $SelectedMountPoint = Get-RMSelectedMount -MountPoints $SourceMountPoint -DifferenceList $MountPoint -IncludeEqual $true } else { # If no mount points are given then take all mount points on the source as the selected mount points $SelectedMountPoint = $SourceMountPoint } $MountsResize = @{} if ($null -ne $ResizeMountPoint -and $ResizeMountPoint.Count -gt 0) { $MountsResize, $MountsResizeErrors = Get-RMResizeMountsPoint -ResizeMountPoints $ResizeMountPoint -SelectedMountPoints $SelectedMountPoint -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 $SelectedMountPoint ` -TransferMethod $TransferMethod if (![string]::IsNullOrWhiteSpace($ErrorString)) { $Errors += $ErrorString } } if ($CloudAttributes.properties.projects[0].identifier -ieq $ProjectId) { if ([string]::IsNullOrWhiteSpace($Region)) { $Region = $CloudAttributes.properties.projects[0].regions[0].name } if ([string]::IsNullOrWhiteSpace($Zone)) { $Zone = $CloudAttributes.properties.projects[0].regions[0].zones[0].name } } if ($CloudAttributesProjectErrors.Count -eq 0) { $CloudAttributesProject = Get-RMCloudAttributesByProjectIdAndRegionAndZone -CloudAccount $CloudAccount ` -ProjectId $ProjectId -Region $Region -Zone $Zone $Errors += Confirm-RMCloudAttributesProjectAndRegionAndZone -UserParameter $PSBoundParameters ` -CloudAttributesProject $CloudAttributesProject } $DiskType = Get-RMDiskTypeBySource -Source $Source -IsInteractive $false -DiskTypeName $DiskType -IsVM $false $InstanceLabelAsHashtable = @{} try { $InstanceLabelAsHashtable = Get-RMStringArrayAsHashtable -InputItems $InstanceLabel -ParameterName "InstanceLabel" } catch { $Errors += $PSItem.Exception.Message } Add-RMOSUpgrade -UserParameter $PSBoundParameters -UpdatedParameter $UserInput -Source $Source Add-RMMigrationExtension -UpdatedParameter $UserInput -MigrationExtension $MigrationExtension ` -MigrationExtensionOSM $MigrationExtensionOSM -MigrationExtensionResponse $MigrationExtensionResponse if ([string]::IsNullOrWhiteSpace($DestinationNetworkName)) { $DestinationNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } if ([string]::IsNullOrWhiteSpace($SubnetName)) { $SubnetName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.internal_subnet_id } if (!$MigrateToSoleTenantNode) { $NodeGroupName = $null } $CustomPrimaryInternalIPType = $false if ("Ephemeral-custom" -ieq $PrimaryInternalIP) { $CustomPrimaryInternalIPType = $true } else { $CustomEphemeralIPAddress = $null } $AssignPublicIP = $false if ("automatic" -ieq $ExternalIP) { $AssignPublicIP = $true } if ([string]::IsNullOrWhiteSpace($NetworkTier)) { $NetworkTier = "PREMIUM" } $LicenseType = "" if ("linux" -ieq $Source.os_type) { if ($OSBYOL -eq $false) { $LicenseType = "byol" } } if ("windows" -ieq $Source.os_type) { if ($OSBYOL -eq $true) { $LicenseType = "byol" } } if ("windows" -ieq $Source.os_type -and ![string]::IsNullOrWhiteSpace($SQLLicense)) { $SQLLicenses = Get-RMSQLLicenseMapping $SQLLicense = $SQLLicenses[$SQLLicense] } if("windows" -ine $Source.os_type) { $DisableTargetDNSRegistration = $false } $DefaultNetworkTags = @() $DefaultNetworkTags += "rivermeadow-tw" if ("linux" -ieq $Source.os_type) { if ("agent" -ieq $Source.control_connection_type) { $DefaultNetworkTags += "rivermeadow-agent" } } if (!$EnforceTargetNetworkIsolation) { $NetworkTag = $DefaultNetworkTags if ("linux" -ieq $Source.os_type) { $NetworkTag += "rivermeadow-ft-linux" } else { $NetworkTag += "rivermeadow-ft-windows" } } else { $NetworkTag += $DefaultNetworkTags } if ($AllowHTTPTraffic) { $NetworkTag += "http-server" } if ($AllowHTTPSTraffic) { $NetworkTag += "https-server" } $SQLServerUpgrade = Get-RMUpgradeSQLServer -UpgradeSQLServer $UpgradeSQLServer -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping $ErrorsOSHardening = Add-RMOSHardening -Source $Source -UpdatedParameter $UserInput -UserParameter $PSBoundParameters if ($null -ne $ErrorsOSHardening) { $Errors += $ErrorsOSHardening } $MigrationInstructionAsHashTable = $null try { if (($IgnoreValidationError -and $OverrideExistingMigration) -or ` (!$IgnoreValidationError -and $OverrideExistingMigration) -or ` $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionAsHashTable = Get-RMStringArrayAsHashtable -InputItems $MigrationInstruction -ParameterName "MigrationInstruction" } catch { $Errors += $PSItem.Exception.Message } if ([string]::IsNullOrWhiteSpace($ScheduledAt)) { $ScheduledAt = "" } else { # We are confirming the date time format here again, as we have observed that if the previous parameter is an # array and the content of the array is in invalid format and the "ScheduledAt" is getting the value from the # elements of the array with bad input and it will cause 'Convert-RMDateTimeToUTC' to throw an exception, catching # that exception is of no use as the user may not have used the "ScheduledAt" parameter and the error is very cryptic. # e.g. -InstanceLabel t1=v1, t2 = v2 (these excess spaces is causing the array to misbehave) if ((Confirm-RMDateFormat -InputDate $ScheduledAt -DateFormat "MM/dd/yyyy HH:mm")) { $ScheduledAt = Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt } } $ProjectSettingsResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $MTUSize = $ProjectSettingsResponse.gcp.mtu_size Add-RMConvertFileSystem -Source $Source -UpdatedUserInput $UserInput -ConvertFileSystem $ConvertFileSystem if ([string]::IsNullOrEmpty($NetBIOSName)) { $NetBIOSName = $Source.hostname } $KMSKey = $null if ($KMSActivation) { $KMSKey = "kms.windows.googlecloud.com" if ($null -ne $ProjectSettingsResponse.gcp.kms_fqdn) { $KMSKey = $ProjectSettingsResponse.gcp.kms_fqdn } } elseif ($KMSItopia) { $KMSKey = $ProjectSettingsResponse.gcp.itopia_kms_fqdn } Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings if ($Errors.Count -gt 0 -or $ShouldExit) { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } $HashArguments = @{ CloudAccount = $CloudAccount Entitlement = $Entitlement CloudAttributes = $CloudAttributes ScheduledAt = $ScheduledAt Source = $Source TargetVMName = $TargetVMName SelectedMount = $SelectedMountPoint ResizeMountPoint = $MountsResize TransferMethod = $TransferMethod ProjectId = $ProjectId Region = $Region Zone = $Zone NodeGroupName = $NodeGroupName MachineType = $MachineType DiskType = $DiskType InstanceLabel = $InstanceLabelAsHashtable DestinationNetworkName = $DestinationNetworkName SubnetName = $SubnetName CustomPrimaryInternalIPType = $CustomPrimaryInternalIPType PrimaryInternalIP = $CustomEphemeralIPAddress AssignPublicIP = $AssignPublicIP NetworkTier = $NetworkTier DisableAutomaticDNSRegistrationOnTheTarget = $DisableTargetDNSRegistration EnableSerialPortAccess = $EnableSerialPortAccess AllowHTTPTraffic = $AllowHTTPTraffic AllowHTTPSTraffic = $AllowHTTPSTraffic EnforceTargetNetworkIsolation = $EnforceTargetNetworkIsolation NetworkTag = $NetworkTag SQLServerUpgrade = $SQLServerUpgrade ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget RemoveRMSAgent = $RemoveRMSAgent OSBYOL = $LicenseType SQLLicense = $SQLLicense MigrationInstruction = $MigrationInstructionAsHashTable IgnoreValidationError = $IgnoreValidationError OverrideExistingMigration = $OverrideExistingMigration MTUSize = $MTUSize EnableNetAppFileMigration = $EnableNetAppFileMigration NetBIOSName = $NetBIOSName KMSKey = $KMSKey GeneralizeSystem = $Sysprep } $HashArguments += $UserInput $Response = New-RMGCPMigrationProfile @HashArguments $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrWhiteSpace($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMInteractiveGCPVMBasedMigration { param () $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "gcp" ` -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 [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 } $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount $IgnoreValidationError = Read-RMBoolean -UserMessage "Ignore validation errors" -DefaultValue "false" $SourceAttributeResult = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn ` -AccountType "gcp" $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = $SourceAttributeResult if ($ShouldExit) { return $RMMigrationReturn } if ($OverrideExistingMigrationError) { $OverrideExistingMigrationError = Read-RMBoolean -UserMessage "Would you like to override the previous migration attempt" -DefaultValue $false if (!$IgnoreValidationError -and !$OverrideExistingMigrationError) { return $RMMigrationReturn } } $TargetVMName = Read-RMString -UserMessage "Enter target VM Name" -DefaultValue $Source.host ` -ParameterName "Target VM Name" -IsRequired $false $CloudSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount #Placement Settings $DefaultProject = Get-RMDefaultProjectByIdentifier -ProjectObject $CloudSummary.properties.projects ` -Identifier $CloudAttributes.properties.projects[0].name $ProjectName = Read-RMString -UserMessage "Enter project name" -ParameterName "Project Name" ` -Options $CloudSummary.properties.projects.name -DefaultValue $DefaultProject.name -IsRequired $false Write-Output "Getting cloud attributes for project $ProjectName ..." | Out-Host $ProjectIdentifier = Get-RMProjectIdentifierByProjectName -ProjectObject $CloudSummary.properties.projects -ProjectName $ProjectName $CloudAttributesProject = Get-RMCloudAttributesByProjectId -CloudAccount $CloudAccount -ProjectId $ProjectIdentifier.identifier $HasProjectChanged = $false if ($CloudAttributes.properties.projects[0].identifier -ieq $ProjectIdentifier.identifier) { $DefaultRegion = $CloudAttributes.properties.projects[0].regions[0].name $DefaultZone = $CloudAttributes.properties.projects[0].regions[0].zones[0].name } else { $HasProjectChanged = $true } if ($HasProjectChanged) { $RegionName = Read-RMString -UserMessage "Enter region name" -ParameterName "Region Name" ` -Options $CloudAttributesProject.properties.projects.regions.name -IsRequired $true $RegionObject = Get-RMRegionByRegionName -RegionName $RegionName -Region $CloudAttributesProject.properties.projects.regions $Zone = Read-RMString -UserMessage "Enter zone name" -ParameterName "Zone Name" -Options $RegionObject.zones.name -IsRequired $true } else { $RegionName = Read-RMString -UserMessage "Enter region name" -ParameterName "Region Name" ` -Options $CloudAttributesProject.properties.projects.regions.name -DefaultValue $DefaultRegion -IsRequired $false $RegionObject = Get-RMRegionByRegionName -RegionName $RegionName -Region $CloudAttributesProject.properties.projects.regions if ($DefaultRegion -ieq $RegionName) { $Zone = Read-RMString -UserMessage "Enter zone name" -ParameterName "Zone Name" -Options $RegionObject.zones.name ` -DefaultValue $DefaultZone -IsRequired $false } else { $Zone = Read-RMString -UserMessage "Enter zone name" -ParameterName "Zone Name" -Options $RegionObject.zones.name -IsRequired $true } } $CloudAttributesProject = Get-RMCloudAttributesByProjectIdAndRegionAndZone -CloudAccount $CloudAccount -ProjectId $ProjectIdentifier.identifier ` -Region $RegionName -Zone $Zone $NodeGroupName = Read-RMNodeGroupName -CloudAttribute $CloudAttributes $MachineType = Read-RMMachineType -CloudAttribute $CloudAttributesProject 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 $SelectedDisk = @() $ReturnedValue = Get-RMSelectedDisk -Source $Source if ($SelectedDisk -is [hashtable]) { $SelectedDisk += $ReturnedValue } else { $SelectedDisk = $ReturnedValue } $DiskType = Get-RMDiskTypeBySource -Source $Source -IsInteractive $true -IsVM $true $NetworkObject = $CloudAttributesProject.properties.projects.regions.networks if ($HasProjectChanged -or $RegionName -ine $CloudAccount.appliance.cloud_properties.region -or ` $Zone -ine $CloudAccount.appliance.cloud_properties.az) { $Network = Read-RMString -UserMessage "Enter destination network name" -Parameter "Destination Network Name" -Options $NetworkObject.name ` -IsRequired $true } else { $Network = Read-RMString -UserMessage "Enter destination network name" -Parameter "Destination Network Name" -Options $NetworkObject.name ` -DefaultValue $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name -IsRequired $false } $SubnetObject = Get-RMSubnetByNetworkName -NetworkName $Network -NetworkObject $NetworkObject if ($Network -ieq $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name) { $Subnet = Read-RMString -UserMessage "Enter subnet name" -Parameter "Subnet Name" -Options $SubnetObject.name -IsRequired $false ` -DefaultValue $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.internal_subnet_id } else { $Subnet = Read-RMString -UserMessage "Enter subnet name" -Parameter "Subnet Name" -Options $SubnetObject.name -IsRequired $true } $PrimaryInternalIPType = $false $PrimaryInternalIP = Read-RMString -UserMessage "Enter the primary internal ip" -Options "Ephemeral_Automatic", "Ephemeral_Custom" ` -DefaultValue "Ephemeral_Automatic" -IsRequired $false -ParameterName "Primary Internal IP Type" if ("Ephemeral_Custom" -ieq $PrimaryInternalIP) { $PrimaryInternalIPType = $true $CustomEphemeralIPAddress = Read-RMIPAddress -UserMessage "Enter custom Ephemeral IP address" -IsRequired $true ` -ParameterName "Custom Ephemeral IP Address" } $ExternalIP = Read-RMString -UserMessage "Do you want to assign external IP address to the target machine" -Options "None", "Automatic" ` -DefaultValue "None" -IsRequired $false -ParameterName "External IP Address" $NetworkTier = "PREMIUM" $AssignPublicIP = $false if ("Automatic" -ieq $ExternalIP) { $AssignPublicIP = $true $NetworkTier = Read-RMString -UserMessage "Enter network tier" -Options "Premium", "Standard" -DefaultValue "Premium" -IsRequired $false ` -ParameterName "Network Tier" $NetworkTier = Get-RMNetworkTier -NetworkTierName $NetworkTier } $InstanceLabel = Read-RMPair -UserMessage "Enter one or more instance labels in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue "None" $InstanceLabelAsHashtable = Get-RMStringAsHashtable -InputString $InstanceLabel #Optimization Settings if ("windows" -ieq $Source.os_type) { $OSLicensing = Read-RMBoolean -UserMessage "BYOL" -DefaultValue $false $SQLLicenseOptions = Get-RMSQLLicenseMapping $SQLLicense = Read-RMString -UserMessage "Enter sql license" -Options $SQLLicenseOptions.Keys -DefaultValue "None" ` -ParameterName "SQL Licensing" -IsRequired $false $SQLLicense = $SQLLicenseOptions[$SQLLicense] } else { $OSLicensing = Read-RMBoolean -UserMessage "Premium license" -DefaultValue $false $OSLicensing = !$OSLicensing } $MigrationExtensionResponse = Get-RMMigrationExtension -OrganizationId $CloudAccount.organization_id $MigrationExtensionArray, $MigrationExtensionOSMArray = Get-RMMigrationExtensionFromStep -MigrationExtensionArray $MigrationExtensionResponse.content Read-RMMigrationExtension -CloudAccount $CloudAccount -MigrationExtension $MigrationExtensionArray ` -MigrationExtensionObject $MigrationExtensionResponse.content -UpdatedUserInput $UserInput #Security Settings $EnforceTargetNetworkIsolation = Read-RMBoolean -UserMessage "Enforce target network isolation" -DefaultValue $true $NetworkTag = @() if (!$EnforceTargetNetworkIsolation) { $NetworkTagObject = Get-RMNetworkByNertworkName -NetworkObject $NetworkObject -NetworkName $Network $Options = $NetworkTagObject.target_tags $Options += "rivermeadow-tw" $DefaultValue = "rivermeadow-tw" if ("linux" -ieq $Source.os_type) { $Options += "rivermeadow-ft-linux" $DefaultValue = $DefaultValue + ", rivermeadow-ft-linux" if ("agent" -ieq $Source.control_connection_type) { $Options += "rivermeadow-agent" $DefaultValue = $DefaultValue + ", rivermeadow-agent" } } else { $Options += "rivermeadow-ft-windows" $DefaultValue = $DefaultValue + ", rivermeadow-ft-windows" } $NetworkTag = Read-RMToken -UserMessage "Enter network tags, separated by commas" -ParameterName "Network Tag" ` -DefaultValue $DefaultValue -Options $Options -IsRequired $false -Separator "," } else { $NetworkTag += "rivermeadow-tw" if ("linux" -ieq $Source.os_type -and "agent" -ieq $Source.control_connection_type) { $NetworkTag += "rivermeadow-agent" } } $EnableSerialPortAccess = Read-RMBoolean -UserMessage "Enable remote access through serial port" -DefaultValue $false $FirewallsHTTP = Read-RMBoolean -UserMessage "Allow HTTP traffic through firewalls" -DefaultValue $false $FirewallsHTTPS = Read-RMBoolean -UserMessage "Allow HTTPS traffic through firewalls" -DefaultValue $false if ($FirewallsHTTP) { $NetworkTag += "http-server" } if ($FirewallsHTTPS) { $NetworkTag += "https-server" } #Advanced Settings $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" $FinalizeMigration = Read-RMBoolean -UserMessage "Removes the 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 (($IgnoreValidationError -and $OverrideExistingMigrationError) -or (!$IgnoreValidationError -and $OverrideExistingMigrationError) -or $OverrideExistingMigrationWarning) { if ("" -eq $ReadValue) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstruction = Get-RMStringAsHashtable -InputString $ReadValue $MTUSizeResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $MTUSize = $MTUSizeResponse.gcp.mtu_size $HashArguments = @{ CloudAccount = $CloudAccount Entitlement = $Entitlement ScheduledAt = $ScheduledAt Source = $Source TargetVMName = $TargetVMName SelectedDisk = $SelectedDisk ProjectId = $ProjectIdentifier.identifier Region = $RegionName Zone = $Zone NodeGroupName = $NodeGroupName MachineType = $MachineType DiskType = $DiskType InstanceLabel = $InstanceLabelAsHashtable DestinationNetworkName = $Network SubnetName = $Subnet PrimaryInternalIPType = $PrimaryInternalIPType PrivateIPAddress = $CustomEphemeralIPAddress AssignPublicIP = $AssignPublicIP NetworkTier = $NetworkTier EnableSerialPortAccess = $EnableSerialPortAccess EnforceTargetNetworkIsolation = $EnforceTargetNetworkIsolation NetworkTag = $NetworkTag FinalizeMigration = $FinalizeMigration ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget OSBYOL = $OSLicensing SQLLicense = $SQLLicense MigrationInstruction = $MigrationInstruction IgnoreValidationError = $IgnoreValidationError MTUSize = $MTUSize } $HashArguments += $UserInput $Response = New-RMGCPVMBasedMigrationProfile @HashArguments $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrWhiteSpace($ScheduledAt) $MigrationResponse = Invoke-RMMigrationPost -MigrationProfileResponse $Response return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMNonInteractiveGCPVMBasedMigration { param( [string] $SourceVMName, [string] $SourceVMFolderPath, [string] $TargetCloud, [string] $ScheduledAt, [string] $TargetVMName, [string[]] $SelectedDiskLabel, [string] $Project, [string] $Region, [string] $Zone, [bool] $MigrateToSoleTenantNode, [string] $NodeGroupName, [string] $MachineType, [string[]] $DiskType, [string[]] $InstanceLabel, [string] $DestinationNetworkName, [string] $SubnetName, [string] $PrimaryInternalIP, [string] $CustomEphemeralIPAddress, [string] $ExternalIP, [string] $MigrationExtension, [bool] $EnableSerialPortAccess, [bool] $AllowHTTPTraffic, [bool] $AllowHTTPSTraffic, [bool] $EnforceTargetNetworkIsolation, [string[]] $NetworkTag, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $OSBYOL, [string] $SQLLicense, [string] $OSModernization, [bool] $RemoveRMSAgent, [bool] $FinalizeMigration, [string[]] $MigrationInstruction, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration ) $CloudAccount = $null $Source = $null $Errors = @() $UserInput = @{} $ShouldExit = $false [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Errors, $Warnings, $IsSourceAndTargetCloudPresent = Confirm-RMGCPVMBasedFullMigrationParameter $PSBoundParameters try { if (![string]::IsNullOrWhiteSpace($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "gcp" -VMBasedAppliancesOnly $true if (![string]::IsNullOrWhiteSpace($ErrorString)) { $Errors += $ErrorString $IsSourceAndTargetCloudPresent = $false } else { $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount } } } catch [System.Management.Automation.ItemNotFoundException] { $Errors += $PSItem.Exception.Message $IsSourceAndTargetCloudPresent = $false } try { if (![string]::IsNullOrWhiteSpace($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-RMGCPOSBasedMigration'." 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 } $Entitlement = Get-RMEntitlement try { $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = ` Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn ` -AccountType "gcp" 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 } 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 } $MigrationExtensionResponse = Get-RMMigrationExtension -OrganizationId $CloudAccount.organization_id $MigrationExtensionArray, $MigrationExtensionOSMArray = Get-RMMigrationExtensionFromStep -MigrationExtensionArray $MigrationExtensionResponse.content $SourceErrors = Confirm-RMGCPVMBasedFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source ` -MigrationExtension $MigrationExtensionArray if ($SourceErrors.Count -gt 0) { $Errors += $SourceErrors } $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $CloudAttributesErrors += Confirm-RMCloudAttributes -UserParameter $PSBoundParameters -CloudAttribute $CloudAttributesSummary if ($CloudAttributesErrors.Count -eq 0) { if ([string]::IsNullOrWhiteSpace($Project) ) { $ProjectIdentifier = $CloudAttributes.properties.projects } else { $ProjectIdentifier = Get-RMProjectIdentifierByProjectName -ProjectObject $CloudAttributesSummary.properties.projects ` -ProjectName $Project } $CloudAttributesProject = Get-RMCloudAttributesByProjectId -CloudAccount $CloudAccount -ProjectId $ProjectIdentifier.identifier $CloudAttributesProjectErrors += Confirm-RMCloudAttributesProject -UserParameter $PSBoundParameters ` -CloudAttribute $CloudAttributesSummary -CloudAttributesProject $CloudAttributesProject if ($CloudAttributesProjectErrors.Count -gt 0) { $Errors += $CloudAttributesProjectErrors } } else { $Errors += $CloudAttributesErrors } } if ([string]::IsNullOrWhiteSpace($ScheduledAt)) { $ScheduledAt = "" } else { $ScheduledAt = Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt } if ([string]::IsNullOrWhiteSpace($TargetVMName)) { $TargetVMName = $Source.host } Add-RMMigrationExtension -UpdatedParameter $UserInput -MigrationExtension $MigrationExtension ` -MigrationExtensionOSM $MigrationExtensionOSM -MigrationExtensionResponse $MigrationExtensionResponse $SelectedDisk = Get-RMSelectedDiskByDiskLabel -DiskLabel $SelectedDiskLabel -Source $Source if ($CloudAttributes.properties.projects[0].identifier -ieq $ProjectIdentifier.identifier) { if ([string]::IsNullOrWhiteSpace($Region)) { $Region = $CloudAttributes.properties.projects[0].regions[0].name } if ([string]::IsNullOrWhiteSpace($Zone)) { $Zone = $CloudAttributes.properties.projects[0].regions[0].zones[0].name } } if ($CloudAttributesProjectErrors.Count -eq 0) { $CloudAttributesProject = Get-RMCloudAttributesByProjectIdAndRegionAndZone -CloudAccount $CloudAccount -ProjectId $ProjectIdentifier.identifier ` -Region $Region -Zone $Zone $CloudAttributesProjectAndRegionAndZoneErrors += Confirm-RMCloudAttributesProjectAndRegionAndZone -UserParameter $PSBoundParameters ` -CloudAttributesProject $CloudAttributesProject if ($CloudAttributesProjectAndRegionAndZoneErrors.Count -gt 0) { $Errors += $CloudAttributesProjectAndRegionAndZoneErrors } } $DiskType = Get-RMDiskTypeBySource -Source $Source -IsInteractive $false -DiskTypeName $DiskType -IsVM $true -SelectedDiskLabel $SelectedDiskLabel if ([string]::IsNullOrWhiteSpace($DestinationNetworkName)) { $DestinationNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } if ([string]::IsNullOrWhiteSpace($SubnetName)) { $SubnetName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.internal_subnet_id } $PrimaryInternalIPType = $false if ("Ephemeral-custom" -ieq $PrimaryInternalIP) { $PrimaryInternalIPType = $true } if (!$MigrateToSoleTenantNode) { $NodeGroupName = $null } if ("windows" -ieq $Source.os_type -and ![string]::IsNullOrWhiteSpace($SQLLicense)) { $SQLLicenses = Get-RMSQLLicenseMapping $SQLLicense = $SQLLicenses[$SQLLicense] } $AssignPublicIP = $false if ("Automatic" -ieq $ExternalIP) { $AssignPublicIP = $true } if ([string]::IsNullOrWhiteSpace($NetworkTier)) { $NetworkTier = "PREMIUM" } if ("linux" -ieq $Source.os_type) { $OSBYOL = !$OSBYOL } $NetworkTag += "rivermeadow-tw" if ("linux" -ieq $Source.os_type -and "agent" -ieq $Source.control_connection_type) { $NetworkTag += "rivermeadow-agent" } if (!$EnforceTargetNetworkIsolation) { if ("linux" -ieq $Source.os_type) { $NetworkTag += "rivermeadow-ft-linux" } else { $NetworkTag += "rivermeadow-ft-windows" } } if ($AllowHTTPTraffic) { $NetworkTag += "http-server" } if ($AllowHTTPSTraffic) { $NetworkTag += "https-server" } $MigrationInstructionAsHashTable = $null try { if (($IgnoreValidationError -and $OverrideExistingMigration) -or ` (!$IgnoreValidationError -and $OverrideExistingMigration) -or ` $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionAsHashTable = Get-RMStringArrayAsHashtable -InputItems $MigrationInstruction -ParameterName "MigrationInstruction" } catch { $Errors += $PSItem.Exception.Message } $MTUSizeResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $MTUSize = $MTUSizeResponse.gcp.mtu_size Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings if ($Errors.Count -gt 0 -or $ShouldExit) { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } $HashArguments = @{ CloudAccount = $CloudAccount Entitlement = $Entitlement ScheduledAt = $ScheduledAt Source = $Source TargetVMName = $TargetVMName SelectedDisk = $SelectedDisk ProjectId = $ProjectIdentifier.identifier Region = $Region Zone = $Zone MigrateToSoleTenantNode = $TenantZones NodeGroupName = $NodeGroupName MachineType = $MachineType DiskType = $DiskType InstanceLabel = $InstanceLabelAsHashtable DestinationNetworkName = $DestinationNetworkName SubnetName = $SubnetName PrimaryInternalIPType = $PrimaryInternalIPType PrivateIPAddress = $CustomEphemeralIPAddress AssignPublicIP = $AssignPublicIP NetworkTier = $NetworkTier EnableSerialPortAccess = $EnableSerialPortAccess EnforceTargetNetworkIsolation = $EnforceTargetNetworkIsolation NetworkTag = $NetworkTag FinalizeMigration = $FinalizeMigration ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget OSBYOL = $OSBYOL SQLLicense = $SQLLicense MigrationInstruction = $MigrationInstructionAsHashTable IgnoreValidationError = $IgnoreValidationError MTUSize = $MTUSize } $HashArguments += $UserInput $Response = New-RMGCPVMBasedMigrationProfile @HashArguments $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 Confirm-RMGCPFullMigrationParameter { param( [hashtable] $UserParameter ) $Errors = @() $Errors, $Warnings, $IsSourceAndTargetCloudPresent = Confirm-RMCommonParameter -UserParameter $UserParameter $GCPOSErrors, $GCPWarnings = Confirm-RMGCPParameter -UserParameter $UserParameter $Errors += $GCPOSErrors $Warnings += $GCPWarnings return $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid } function Confirm-RMGCPFullMigrationParameterWithSource { param( [hashtable] $UserParameter, [System.Object] $Source, [System.Object] $SourceSQLServerMapping, [System.Array] $MigrationExtension, [System.Array] $MigrationExtensionOSM ) $Errors = @() $Errors += Confirm-RMCommonParameterWithSource -UserParameter $UserParameter -Source $Source -SourceSQLServerMapping $SourceSQLServerMapping ` -MigrationExtension $MigrationExtension -MigrationExtensionOSM $MigrationExtensionOSM -CloudType 'gcp' $Errors += Confirm-RMSQLLicense -UserParameter $UserParameter -Source $Source if ($Source.os_type -ne 'windows' -and $UserParameter["DisableTargetDNSRegistration"]) { $Errors += "DisableTargetDNSRegistration can be 'true', only if the source OS type is 'Windows'." } $DiskTypeCnt = $UserParameter['DiskType'].Count $DiskCnt = $Source.attributes.storage.disks.psobject.Properties.Value.device.Count if ($DiskTypeCnt -ne $DiskCnt) { $Errors += "The source has '$DiskCnt' disks and the number of disk types given by the parameter 'DiskType' are '$DiskTypeCnt'. The number of disk types given should be equal to the number of disks on the source." } return $Errors } function Confirm-RMGCPVMBasedFullMigrationParameter { param ( [hashtable] $UserParameter ) $Errors = @() $Errors, $Warnings, $IsSourcePresent = Confirm-RMVMBasedCommonParameter -UserParameter $UserParameter $GCPErrors, $GCPWarnings = Confirm-RMGCPParameter -UserParameter $UserParameter $Errors += $GCPErrors $Warnings += $GCPWarnings return $Errors, $Warnings, $IsSourcePresent } function Confirm-RMGCPVMBasedFullMigrationParameterWithSource { param ( [hashtable] $UserParameter, [System.Object] $Source, [System.Object] $MigrationExtension ) $Errors = @() $SourceDiskLabels = Get-RMVMBasedSourceDiskLabel -Source $Source $DiskLabelsNotFound = @() foreach ($DiskLabel in $UserParameter["SelectedDiskLabel"]) { if ($SourceDiskLabels -notcontains $DiskLabel) { $DiskLabelsNotFound += $DiskLabel } } if ($UserParameter.ContainsKey("MigrationExtension") -and ![string]::IsNullOrWhiteSpace($UserParameter["MigrationExtension"])) { $MigrationExtensionValue = $UserParameter["MigrationExtension"] if ($MigrationExtension -notcontains $MigrationExtensionValue) { $Errors += "MigrationExtension '$MigrationExtensionValue' does not exist." } } 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 ($UserParameter.ContainsKey("DiskType") -and ![string]::IsNullOrWhiteSpace($UserParameter["DiskType"])) { $ErrorString = Confirm-RMDiskType -SelectedDiskLabel $SelectedDiskLabel -DiskType $UserParameter["DiskType"] if (![string]::IsNullOrEmpty($ErrorString)) { $Errors += $ErrorString } } $Errors += Confirm-RMSQLLicense -UserParameter $UserParameter -Source $Source return $Errors } function Confirm-RMSQLLicense { param( [hashtable] $UserParameter, [System.Object] $Source ) $Errors = @() if ($Source.os_type -ieq 'windows') { if ($UserParameter.ContainsKey("SQLLicense") -and ![string]::IsNullOrWhiteSpace($UserParameter["SQLLicense"])) { $SQLLicenses = Get-RMSQLLicenseMapping if ($SQLLicenses.Keys -notcontains $UserParameter["SQLLicense"]) { $SQLLicensesAsString = $SQLLicenses.Keys -join ", " $Errors = "SQLLicense should be one of '$SQLLicensesAsString'." } } } else { if ($UserParameter.ContainsKey("SQLLicense") -and ![string]::IsNullOrWhiteSpace($UserParameter["SQLLicense"])) { $Errors = "SQLLicense can be used for a Windows source only." } } return $Errors } function Confirm-RMGCPParameter { param ( [hashtable] $UserParameter ) $Errors = @() $Warnings = @() if (!$UserParameter.ContainsKey("MachineType") -or [string]::IsNullOrWhiteSpace($UserParameter["MachineType"])) { $Errors += "MachineType is required." } if (!$UserParameter.ContainsKey("DiskType") -or [string]::IsNullOrWhiteSpace($UserParameter["DiskType"])) { $Errors += "DiskType is required." } if ($UserParameter.ContainsKey("PrimaryInternalIP") -and ![string]::IsNullOrWhiteSpace($UserParameter["PrimaryInternalIP"]) -and ` "Ephemeral-custom" -ieq $UserParameter["PrimaryInternalIP"]) { if (!$UserParameter.ContainsKey("CustomEphemeralIPAddress") -or ` [string]::IsNullOrWhiteSpace($UserParameter["CustomEphemeralIPAddress"])) { $Errors += "CustomEphemeralIPAddress is required, when 'PrimaryInternalIP' is 'Ephemeral-custom'." } elseif (!(Confirm-RMIPAddress -IPAddress $UserParameter["CustomEphemeralIPAddress"])){ $Errors += "Invalid custom ephemeral IP address" } } if ($UserParameter.ContainsKey("NetworkTier") -and ![string]::IsNullOrWhiteSpace($UserParameter["NetworkTier"]) -and ` "Premium" -ine $UserParameter["NetworkTier"] -and ` $UserParameter.ContainsKey("ExternalIP") -and ![string]::IsNullOrWhiteSpace($UserParameter["ExternalIP"]) -and ` "none" -ieq $UserParameter["ExternalIP"]) { $Errors += "'NetworkTier' has to be 'Premium', when 'ExternalIP' is 'none'." } if ($UserParameter.ContainsKey("EnforceTargetNetworkIsolation") -and ` $UserParameter["EnforceTargetNetworkIsolation"] -and ` $UserParameter.ContainsKey("NetworkTag") -and ` $UserParameter["NetworkTag"].Count -gt 0) { $Warnings += "EnforceTargetNetworkIsolation is true, the network tags given in the parameter 'NetworkTag' will be ignored." } if (!$UserParameter["MigrateToSoleTenantNode"] -and $UserParameter.ContainsKey("NodeGroupName") -and ` ![string]::IsNullOrWhiteSpace($UserParameter["NodeGroupName"])) { $Warnings += "'MigrateToSoleTenantNode' is false, the node group name given in the parameter 'NodeGroupName' will be ignored." } return $Errors, $Warnings } function Confirm-RMCloudAttributes { param( [hashtable] $UserParameter, [System.Object] $CloudAttribute ) $Errors = @() if ($UserParameter.ContainsKey("Project") -or ![string]::IsNullOrWhiteSpace($UserParameter["Project"])) { $ValidProject = Confirm-RMProject -ProjectName $UserParameter["Project"] -CloudAttribute $CloudAttribute if (!$ValidProject) { $Errors += "Invalid Project Name" } } return $Errors } function Confirm-RMCloudAttributesProject { param ( [hashtable] $UserParameter, [System.Object] $CloudAccount, [System.Object] $CloudAttribute, [System.Object] $CloudAttributesProject ) $Errors = @() $DefaultProject = Get-RMDefaultProjectByIdentifier -ProjectObject $CloudAttribute.properties.projects ` -Identifier $CloudAttributes.properties.projects[0].name if (!$UserParameter.ContainsKey("Project") -or [string]::IsNullOrWhiteSpace($UserParameter["Project"]) -or ` $DefaultProject.name -ieq $UserParameter["Project"]) { if ($UserParameter.ContainsKey("Region") -and ![string]::IsNullOrWhiteSpace($UserParameter["Region"])) { $RegionIsValid = Confirm-RMRegion -RegionName $UserParameter["Region"] -CloudAttributesProject $CloudAttributesProject if (!$RegionIsValid) { $Errors += "Invalid Region Name" } } if ($UserParameter.ContainsKey("Zone") -and ![string]::IsNullOrWhiteSpace($UserParameter["Zone"])) { $RegionObject = Get-RMRegionByRegionName -RegionName $UserParameter["Region"] ` -Region $CloudAttributesProject.properties.projects.regions $ZoneIsValid = Confirm-RMZone -ZoneName $UserParameter["Zone"] -Region $RegionObject if (!$ZoneIsValid) { $Errors += "Invalid Zone" } } if (($UserParameter.ContainsKey("Region") -and ![string]::IsNullOrWhiteSpace($UserParameter["Region"]) -and ` $UserParameter["Region"] -ine $CloudAccount.appliance.cloud_properties.region) -or ` ($UserParameter.ContainsKey("Zone") -and ![string]::IsNullOrWhiteSpace($UserParameter["Zone"]) -and ` $UserParameter["Zone"] -ine $CloudAccount.appliance.cloud_properties.az) -and ` (!$UserParameter.ContainsKey("DestinationNetworkName") -or ` [string]::IsNullOrWhiteSpace($UserParameter["DestinationNetworkName"]))) { $Errors += "DestinationNetworkName is required" } if ($UserParameter.ContainsKey("DestinationNetworkName") -and ` ![string]::IsNullOrWhiteSpace($UserParameter["DestinationNetworkName"]) -and ` $UserParameter["DestinationNetworkName"] -ine $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name -and ` (!$UserParameter.ContainsKey("SubnetName") -or [string]::IsNullOrWhiteSpace($UserParameter["SubnetName"])) ) { $Errors += "SubnetName is required" } } else { if ($DefaultProject.name -ine $UserParameter["Project"]) { if ($UserParameter.ContainsKey("Region") -and ![string]::IsNullOrWhiteSpace($UserParameter["Region"])) { $RegionIsValid = Confirm-RMRegion -RegionName $UserParameter["Region"] -CloudAttributesProject $CloudAttributesProject if (!$RegionIsValid) { $Errors += "Invalid Region Name" } } else { $Errors += "Region is required." } if ($UserParameter.ContainsKey("Zone") -and ![string]::IsNullOrWhiteSpace($UserParameter["Zone"])) { $RegionObject = Get-RMRegionByRegionName -RegionName $UserParameter["Region"] ` -Region $CloudAttributesProject.properties.projects.regions $ZoneIsValid = Confirm-RMZone -ZoneName $UserParameter["Zone"] -Region $RegionObject if (!$ZoneIsValid) { $Errors += "Invalid Zone" } } else { $Errors += "Zone is required." } if (!$UserParameter.ContainsKey("DestinationNetworkName") -or ` [string]::IsNullOrWhiteSpace($UserParameter["DestinationNetworkName"])) { $Errors += "DestinationNetworkName is required" } if (!$UserParameter.ContainsKey("SubnetName") -or ` [string]::IsNullOrWhiteSpace($UserParameter["SubnetName"])) { $Errors += "SubnetName is required" } } } return $Errors } function Confirm-RMCloudAttributesProjectAndRegionAndZone { param( [hashtable] $UserParameter, [System.Object] $CloudAttributesProject ) $Errors = @() if ($UserParameter.ContainsKey("MigrateToSoleTenantNode") -and $UserParameter["MigrateToSoleTenantNode"]) { if (!$UserParameter.ContainsKey("NodeGroupName") -or ` [string]::IsNullOrWhiteSpace($UserParameter["NodeGroupName"])) { $Errors += "'NodeGroupName' is required, when 'MigrateToSoleTenantNode' is 'true'" } else { $NodeGroupNames = Get-RMAvailableNodeGroupName -CloudAttribute $CloudAttributesProject if ($null -eq $NodeGroupNames) { $RegionName = $CloudAttributesProject.properties.projects[0].regions[0].name $ZoneName = $CloudAttributesProject.properties.projects[0].regions[0].zones[0].name $Errors += "No node groups were found in region '$RegionName' and zone '$ZoneName', please create a node group and try again" } else { $NodeGroupNameIsValid = Confirm-RMNodeGroupName -NodeGroupName $UserParameter["NodeGroupName"] ` -NodeGroupNameArray $NodeGroupNames if (!$NodeGroupNameIsValid) { $Errors += "Invalid NodeGroupName" } } } } if ($UserParameter.ContainsKey("MachineType") -and ![string]::IsNullOrWhiteSpace($UserParameter["MachineType"])) { $MachineTypeIsValid = Confirm-RMMachineType -MachineType $UserParameter["MachineType"] ` -CloudAttributesProject $CloudAttributesProject if (!$MachineTypeIsValid) { $Errors += "Invalid MachineType" } } if ($UserParameter.ContainsKey("DestinationNetworkName") -and ` ![string]::IsNullOrWhiteSpace($UserParameter["DestinationNetworkName"])) { $DestinationNetworkNameIsValid = Confirm-RMDestinationNetworkName ` -DestinationNetworkName $UserParameter["DestinationNetworkName"] ` -CloudAttributesProject $CloudAttributesProject if (!$DestinationNetworkNameIsValid) { $Errors += "Invalid DestinationNetworkName" } } if ($UserParameter.ContainsKey("SubnetName") -and ![string]::IsNullOrWhiteSpace($UserParameter["SubnetName"])) { $SubnetObject = Get-RMSubnetByNetworkName -NetworkName $UserParameter["DestinationNetworkName"] ` -NetworkObject $CloudAttributesProject.properties.projects.regions.networks $SubnetNameIsValid = Confirm-RMSubnetName -SubnetName $UserParameter["SubnetName"] -Subnet $SubnetObject if (!$SubnetNameIsValid) { $Errors += "Invalid SubnetName" } } return $Errors } function Confirm-RMProject { param( [string] $ProjectName, [System.Object] $CloudAttribute ) $ValidProject = $true if ($CloudAttribute.properties.projects.name -notcontains $ProjectName) { $ValidProject = $false } return $ValidProject } function Confirm-RMRegion { param ( [string] $RegionName, [System.Object] $CloudAttributesProject ) $RegionIsValid = $true if ($CloudAttributesProject.properties.projects.regions.name -notcontains $RegionName) { $RegionIsValid = $false } return $RegionIsValid } function Confirm-RMZone { param ( [string] $ZoneName, [System.Object] $Region ) $ZoneIsValid = $true if ($Region.zones.name -notcontains $ZoneName) { $ZoneIsValid = $false } return $ZoneIsValid } function Confirm-RMNodeGroupName { param ( [string] $NodeGroupName, [array] $NodeGroupNameArray ) $NodeGroupIsValid = $true if ($NodeGroupNameArray -notcontains $NodeGroupName) { $NodeGroupIsValid = $false } return $NodeGroupIsValid } function Confirm-RMMachineType { param( [string] $MachineType, [System.Object] $CloudAttributesProject ) $MachineTypeIsValid = $true if ($CloudAttributesProject.properties.projects[0].regions[0].zones[0].machine_types.name -notcontains $MachineType) { $MachineTypeIsValid = $false } return $MachineTypeIsValid } function Confirm-RMDestinationNetworkName { param( [string] $DestinationNetworkName, [System.Object] $CloudAttributesProject ) $DestinationNetworkNameIsValid = $true if ($CloudAttributesProject.properties.projects.regions.networks.name -notcontains $DestinationNetworkName ) { $DestinationNetworkNameIsValid = $false } return $DestinationNetworkNameIsValid } function Confirm-RMSubnetName { param ( [string] $SubnetName, [System.Object] $Subnet ) $SubnetNameIsValid = $true if ($Subnet.name -notcontains $SubnetName) { $SubnetNameIsValid = $false } return $SubnetNameIsValid } function Confirm-RMDiskType { param ( [string[]] $SelectedDiskLabel, [string[]] $DiskType ) $DiskTypeCnt = $DiskType.Count $DisksCnt = $SelectedDiskLabel.Count if ($DiskTypeCnt -ne $DisksCnt) { $ErrorString += "The source has '$DisksCnt' disks and the number of volume types given by the parameter 'DiskType' are '$DiskTypeCnt'. The number of disk types given should be equal to the number of disks on the source." } return $ErrorString } Export-ModuleMember -Function Start-RMGCPOSBasedInteractiveMigration, Start-RMInteractiveGCPVMBasedMigration, Start-RMNonInteractiveGCPVMBasedMigration, ` Start-RMGCPOSBasedNonInteractiveMigration |