Migration/AWS/AWS.psm1
using module '../../Common/Result' Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath MigrationProfile | Join-Path -ChildPath AWSMigrationProfile) 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 MigrationProfile | Join-Path -ChildPath AWSMigrationProfile) 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 CloudAccount | Join-Path -ChildPath CloudAccount) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath RiverMeadow.Release.Source | Join-Path -ChildPath SourceUtil | Join-Path -ChildPath SourceUtil) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Common | Join-Path -ChildPath Wrappers | Join-Path -ChildPath Wrappers) Import-Module -Name @(Join-Path $PSScriptRoot AWSUtil) function Start-RMAWSOSBasedInteractiveMigration { param () $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "aws" -UserMessage "Enter target cloud" $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount $Entitlement = Get-RMEntitlement $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 $IgnoreValidationError = Read-RMBoolean -UserMessage "Ignore validation errors" -DefaultValue "false" [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn -AccountType "aws" 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 } } $ScheduledAt = Read-RMMigrationSchedule $TargetVMName = Read-RMString -UserMessage "Enter target VM Name" -DefaultValue $Source.hostname ` -ParameterName "Target VM Name" -IsRequired $false #Placement Settings $RegionArray = $CloudAttributesSummary.properties.regions.name $RegionDefaultValue = $CloudAccount.appliance.cloud_properties.region $Region = Read-RMRegion -UserMessage "Enter Region name, e.g. us-east-1" -Options $RegionArray -IsRequired $false -DefaultValue $RegionDefaultValue if ($RegionDefaultValue -ne $Region) { $CloudAttributesRegion = Get-RMCloudAttributesByRegion -CloudAccount $CloudAccount -RegionName $Region } else { $CloudAttributesRegion = Get-CachedCloudAttribute -CloudAccount $CloudAccount } $InstanceType = Read-RMInstanceType -CloudAttributes $CloudAttributesRegion -VMMigration $false $ReadValue = Read-RMPair -UserMessage "Enter one or more instance Tags in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue "None" $InstanceTagAsHashTable = Get-RMStringAsHashtable -InputString $ReadValue $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 } $SupportVolumeType = Confirm-RMSupportVolumeType -Source $Source $VolumeTypeArray = @("GP2", "GP3", "Magnetic") if ($SupportVolumeType) { $VolumeTypeArray += @("IO1", "IO2") } $ReadValue = Read-RMString -UserMessage "Enter volume type" -Options $VolumeTypeArray -ParameterName "Volume Type" ` -IsRequired $false -DefaultValue "GP2" $VolumeType = Get-RMVolumeType -VolumeType $ReadValue -SupportVolumeType $SupportVolumeType if ("io1" -ieq $VolumeType) { $IOPS = Read-RMInt -UserMessage "Enter the IOPS value" -OptionsRange @(100,700) -ParameterName "IOPS" -IsRequired $true } elseif ("io2" -ieq $VolumeType) { $IOPS =Read-RMInt -UserMessage "Enter the IOPS value" -OptionsRange @(100,7000) -ParameterName "IOPS" -IsRequired $true } if ($RegionDefaultValue -ne $Region) { $VPCArray = $CloudAttributesRegion.properties.regions.vpcs.id $VPCID = Read-RMString -UserMessage "Enter VPC ID" -Options $VPCArray -ParameterName "VPC ID" -IsRequired $true $VPCArray = $CloudAttributesRegion.properties.regions.vpcs $VPCObject = Get-ValidVPCData -VPCObject $VPCArray -VPCID $VPCID $SubnetIDArray = $VPCObject.subnets.id $SubnetID = Read-RMString -UserMessage "Enter Subnet ID" -Options $SubnetIDArray -ParameterName "Subnet ID" -IsRequired $true } else { $VPCIDDefaultValue = $CloudAccount.appliance.cloud_properties.vpc $VPCArray = $CloudAttributesRegion.properties.regions.vpcs $VPCID = Read-RMString -UserMessage "Enter VPC ID" -Options $VPCArray.id -ParameterName "VPC ID" ` -DefaultValue $VPCIDDefaultValue -IsRequired $false $VPCObject = Get-ValidVPCData -VPCObject $VPCArray -VPCID $VPCID $SubnetIDArray = $VPCObject.subnets.id if ($VPCIDDefaultValue -ne $VPCID) { $SubnetID = Read-RMString -UserMessage "Enter Subnet ID" -Options $SubnetIDArray -ParameterName "Subnet" -IsRequired $true } else { $SubnetIDDefaultValue = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name $SubnetID = Read-RMString -UserMessage "Enter Subnet ID" -Options $SubnetIDArray -ParameterName "Subnet ID" ` -IsRequired $false -DefaultValue $SubnetIDDefaultValue } } $Subnet = Get-RMSubnetBySubnetIDAndVPC -SubnetID $SubnetID -VPC $VPCObject $AutoAssignPublicIP = Read-RMBoolean -UserMessage "Auto-assign Public IP" -DefaultValue $Subnet.map_public_ip $StaticPrivateIP = Read-RMString -UserMessage "Enter Static Private IP" -ParameterName "Static Private IP" -DefaultValue "None" -IsRequired $false #Optimization Settings $NetBIOSName = Read-RMString -UserMessage "Enter NetBIOS name" -DefaultValue $Source.hostname ` -ParameterName "NetBIOS Name" -IsRequired $false $ProjectSettingsResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $ReplaceWindowsLicense, $ReplaceWindowsLicenseKey = Read-RMReplaceWindowsLicense -Source $Source -ProjectSettingsResponse $ProjectSettingsResponse -CloudType "aws" $KMSActivation = Read-RMBoolean -UserMessage "Enable KMS Activation" -DefaultValue "false" $KMSName = $null if ($KMSActivation) { $KMSName = "169.254.169.250" if ($null -ne $ProjectSettingsResponse.aws.kms_fqdn) { $KMSName = $ProjectSettingsResponse.aws.kms_fqdn } } $Sysprep = $false if ("windows" -ieq $Source.os_type) { $Sysprep = Read-RMBoolean -UserMessage "Enable sysprep" -DefaultValue "false" } $MountsResize = @{} $ResizeMountPointsFlag = Read-RMBoolean -UserMessage "Do you want to resize mount points" -DefaultValue "false" if ($ResizeMountPointsFlag) { $MountsResize = Get-RMInteractiveMountsResize -SelectedMountPoints $SelectedMountPoint -Source $Source } $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 #Modernization Settings Read-RMOSUpgradeOption -Source $Source -UpdatedUserInput $UserInput -ReplaceWindowsLicenseKey $ReplaceWindowsLicenseKey ` -MigrationExtensionOSMArray $MigrationExtensionOSMArray -MigrationExtensionResponse $MigrationExtensionResponse $SQLServerUpgrade = Read-RMSQLServerUpgradeOption -Source $Source #Security Settings $EncryptVolume = Read-RMBoolean -UserMessage "Enable EBS encryption on all volumes" -DefaultValue "false" $KMSKey = "" if ($EncryptVolume) { $ReadValue = Read-RMString -UserMessage "Enter disk encryption type" -Options "platform-managed-key" , "customer-managed-key" ` -DefaultValue "platform-managed-key" -ParameterName "Encryption Type" -IsRequired $false if ("customer-managed-key" -ieq $ReadValue) { $KMSKeyArray = $CloudAttributes.properties.regions.kms_keys.alias_name $ReadValue = Read-RMString -UserMessage "Enter KMS Key" -DefaultValue "None" -ParameterName "KMS Key" ` -IsRequired $false -Options $KMSKeyArray $KMSKey = Get-RMARNByKMSKey -KMSKeyObject $CloudAttributes.properties.regions.kms_keys -KMSName $ReadValue } } $EnforceTargetNetworkIsolation = Read-RMBoolean -UserMessage "Enforce Target Network Isolation" -DefaultValue $true $VPCIDToSecurityGroup = Get-RMVPCAndSecurityGroupMapping -CloudAttributes $CloudAttributes [array] $RMRequiredSG = $VPCIDToSecurityGroup[$VPCID].name | Where-Object {$_ -clike ("RM-Migration-TargetWorker-*")} if (!$EnforceTargetNetworkIsolation) { $UserSecurityGroups = @() if ($null -eq $RMRequiredSG) { $UserSecurityGroups = Read-RMToken -UserMessage "Enter one or more security group names, separated by commas" ` -ParameterName "Security group names" -Options $VPCIDToSecurityGroup[$VPCID].name -IsRequired $true -Separator "," } else { $SecurityGroupDefaultValue = $RMRequiredSG -join ", " $ReadValue = Read-RMToken -UserMessage "Enter one or more security group names, separated by commas" ` -ParameterName "Security group names" -Options $VPCIDToSecurityGroup[$VPCID].name -DefaultValue $SecurityGroupDefaultValue ` -IsRequired $false -Separator "," if ($ReadValue -is [string]) { $UserSecurityGroups += @($ReadValue.split(",").Trim()) } else { $UserSecurityGroups += $ReadValue } foreach ($SG in $RMRequiredSG) { if ($UserSecurityGroups -notcontains $SG) { $UserSecurityGroups += $SG } } } } else { $UserSecurityGroups = $RMRequiredSG } $SecurityGroupMapping = Get-RMSecurityGroupIDToNameMapping -SelectedSecurityGroupName $UserSecurityGroups ` -SecurityGroup $VPCIDToSecurityGroup[$VPCID] $IAMNameToARNMapping = Get-RMIAMRoleToARNMapping -CloudAttributes $CloudAttributes $IAMRole = Read-RMString -UserMessage "Enter the IAM role name that you want to add to the target VM" ` -ParameterName "IAM role name" -Options $IAMNameToARNMapping.Keys -DefaultValue "None" -IsRequired $false if (![string]::IsNullOrWhiteSpace($IAMRole)) { $RoleARN = $IAMNameToARNMapping[$IAMRole] } Read-RMOSHardening -UpdatedUserInput $UserInput -Source $Source #Advanced Settings $TransferMethod = "file-based" if (!$ResizeMountPointsFlag) { $TransferMethod = (Get-RMTransferMethod -Source $Source -SelectedMountPoints $SelectedMountPoint -IsInteractive $true)[0] } $CreateAMI = Read-RMBoolean -UserMessage "Create AMI from the target instance" -DefaultValue "false" $RemoveRMSAgent = Read-RMBoolean -UserMessage "Remove RMS Agent post migration" -DefaultValue "false" $DisableTargetDNSRegistration = $false if ("windows" -ieq $Source.os_type) { $DisableTargetDNSRegistration = Read-RMBoolean -UserMessage "Disable target DNS registration" -DefaultValue "false" } $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" $MigrationInstructionResponse = Get-RMMigrationInstruction -OrganizationId $CloudAccount.organization_id $MigrationInstructionDefaultValue = "None" if ($null -ne $MigrationInstructionResponse.aws) { $MigrationInstructionDefaultValue = $MigrationInstructionResponse.aws -replace ":", "=" ` -replace "@", "" -replace "{", "" -replace "}", "" } $ReadValue = Read-RMPair -UserMessage "Enter migration instructions in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue $MigrationInstructionDefaultValue if (($IgnoreValidationError -and $OverrideExistingMigrationError) -or (!$IgnoreValidationError -and $OverrideExistingMigrationError) -or $OverrideExistingMigrationWarning) { if ("" -eq $ReadValue) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstructionAsHashTable = Get-RMStringAsHashtable -InputString $ReadValue $EnableNetAppFileMigration = Read-RMBoolean -UserMessage "Enable NetApp file migration" -DefaultValue "false" $MTUSize = $ProjectSettingsResponse.aws.mtu_size $HashArguments = @{ CloudAccount = $CloudAccount Entitlement = $Entitlement CloudAttributes = $CloudAttributes ScheduledAt = $ScheduledAt Source = $Source TargetVMName = $TargetVMName SelectedMount = $SelectedMountPoint EncryptVolume = $EncryptVolume VolumeType = $VolumeType ResizeMountPoint = $MountsResize TransferMethod = $TransferMethod IOPS = $IOPS Region = $Region VPCID = $VPCID SubnetID = $SubnetID AutoAssignPublicIP = $AutoAssignPublicIP StaticPrivateIP = $StaticPrivateIP Tenancy = $Tenancy InstanceType = $InstanceType EnforceTargetNetworkIsolation = $EnforceTargetNetworkIsolation SecurityGroup = $SecurityGroupMapping IAMRole = $RoleARN ShouldCreateAMI = $CreateAMI InstanceTag = $InstanceTagAsHashTable SQLServerUpgrade = $SQLServerUpgrade DisableTargetDNSRegistration = $DisableTargetDNSRegistration ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget RemoveRMSAgent = $RemoveRMSAgent MigrationInstruction = $MigrationInstructionAsHashTable IgnoreValidationError = $IgnoreValidationError KMSKey = $KMSKey EnableNetAppFileMigration = $EnableNetAppFileMigration MTUSize = $MTUSize NetBIOSName = $NetBIOSName KMSName = $KMSName GeneralizeSystem = $Sysprep ReplaceWindowsLicense = $ReplaceWindowsLicense } $HashArguments += $UserInput $Response = New-RMAWSMigrationProfile @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-RMAWSOSBasedNonInteractiveMigration { param ( [string] $TargetCloud, [string] $SourceIP, [string] $ScheduledAt, [string] $TargetVMName, [System.Object[]] $MountPoint, [bool] $EncryptAllVolume, [string] $DiskEncryptionType, [string] $KMSKeyAliasName, [string] $VolumeType, [string[]] $ResizeMountPoint, [string] $TransferMethod, [string] $IOPS, [string] $Region, [string] $VPCID, [string] $SubnetID, [string] $AssignPublicIP, [string] $StaticPrivateIP, [string] $Tenancy, [string] $InstanceType, [bool] $EnforceTargetNetworkIsolation, [string[]] $SecurityGroup, [bool] $DisableTargetDNSRegistration, [string] $IAMRole, [bool] $ShouldCreateAMI, [string[]] $InstanceTag, [string] $UpgradeOSVersion, [string] $MigrationExtension, [string] $MigrationExtensionOSM, [string] $ConvertFileSystem, [hashtable[]] $UpgradeSQLServer, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $RemoveRMSAgent, [string[]] $MigrationInstruction, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration, [bool] $EnableNetAppFileMigration, [string] $NetBIOSName, [bool] $KMSActivation, [bool] $Sysprep, [bool] $EnableOSHardening, [bool] $Level1Server, [bool] $Level2Server, [bool] $Level1Computer, [bool] $Level2Computer, [bool] $Level1User, [bool] $Level2User, [string] $AdministratorName, [string] $GuestName, [string] $LegalNoticeCaption, [string] $LegalNoticeText, [string] $ReplaceWindowsLicense ) $CloudAccount = $null $Source = $null $IsSourceAndTargetCloudPresent = $true $Errors = @() [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid = Confirm-RMAWSFullMigrationParameter $PSBoundParameters try { if (![string]::IsNullOrWhiteSpace($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "aws" 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 "aws" 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 $SourceSQLServerMapping = Get-RMSQLMMappingBySource -Source $Source $ProjectSettingsResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $WindowsLicense = Get-RMWindowsKMSKeyMapping -WindowsLicense $ProjectSettingsResponse.aws.windows_license_keys $Errors += Confirm-RMAWSFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping -MigrationExtension $MigrationExtensionArray ` -MigrationExtensionOSM $MigrationExtensionOSMArray -WindowsLicense $WindowsLicense $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $CloudAttributesErrors = Confirm-RMCloudAttributes -UserParameter $PSBoundParameters -CloudAccount $CloudAccount -Source $Source -CloudAttributes $CloudAttributes ` -CloudAttributesSummary $CloudAttributesSummary $Errors += $CloudAttributesErrors $Entitlement = Get-RMEntitlement if ([string]::IsNullOrWhiteSpace($TargetVMName)) { $TargetVMName = $Source.hostname } if (![string]::IsNullOrWhiteSpace($KMSKeyAliasName)) { $KMSKeyAliasName = Get-RMARNByKMSKey -KMSKeyObject $CloudAttributes.properties.regions.kms_keys -KMSName $KMSKeyAliasName } $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 } if ([string]::IsNullOrWhiteSpace($VolumeType)) { $VolumeType = "ssd2" } else { try { $ValidVolumeType = Confirm-RMSupportVolumeType -Source $Source $VolumeType = Get-RMVolumeType -VolumeType $VolumeType -SupportVolumeType $ValidVolumeType } catch { $Errors += $PSItem.Exception.Message } } $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 ([string]::IsNullOrWhiteSpace($Region) -or $Region -ieq $CloudAccount.appliance.cloud_properties.region) { $Region = $CloudAccount.appliance.cloud_properties.region if ([string]::IsNullOrWhiteSpace($VPCID)) { $VPCID = $CloudAccount.appliance.cloud_properties.vpc } if ([string]::IsNullOrWhiteSpace($SubnetID)) { $SubnetID = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } } if ("windows" -ne $Source.os_type) { $DisableTargetDNSRegistration = $false } $VPCIDToSecurityGroup = Get-RMVPCAndSecurityGroupMapping -CloudAttributes $CloudAttributes [array] $DefaultSecurityGroup = $VPCIDToSecurityGroup[$VPCID].name | Where-Object {$_ -clike ("RM-Migration-TargetWorker-*")} if ($EnforceTargetNetworkIsolation) { $SecurityGroup = $DefaultSecurityGroup } else { foreach ($SG in $DefaultSecurityGroup) { if ($SecurityGroup -notcontains $SG) { $SecurityGroup += $SG } } } $SecurityGroupMapping = Get-RMSecurityGroupIDToNameMapping -SelectedSecurityGroupName $SecurityGroup ` -SecurityGroup $VPCIDToSecurityGroup[$VPCID] if (![string]::IsNullOrWhiteSpace($IAMRole)) { $RoleARN = Get-RMARN -CloudAttributesSummary $CloudAttributesSummary -IAMRoleName $IAMRole } if ([string]::IsNullOrWhiteSpace($AssignPublicIP)) { $AssignPublicIP = "Use-subnet-setting" } $AutoAssignPublicIPBool = Get-RMAutoAssignPublicIP -AutoAssignPublicIPName $AssignPublicIP ` -SubnetObject $CloudAttributes.properties.regions[0].vpcs.subnets -SubnetId $SubnetID $UserInput = @{} Add-RMOSUpgrade -UserParameter $PSBoundParameters -UpdatedParameter $UserInput -Source $Source if (![string]::IsNullOrWhiteSpace($ReplaceWindowsLicense)) { $ReplaceWindowsLicense = $WindowsLicense[$ReplaceWindowsLicense] } Add-RMMigrationExtension -UpdatedParameter $UserInput -MigrationExtension $MigrationExtension ` -MigrationExtensionOSM $MigrationExtensionOSM -MigrationExtensionResponse $MigrationExtensionResponse $SQLServerUpgrade = Get-RMUpgradeSQLServer -UpgradeSQLServer $UpgradeSQLServer -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping $InstanceTagAsHashTable = $null try { $InstanceTagAsHashTable = Get-RMStringArrayAsHashtable -InputItems $InstanceTag -ParameterName "InstanceTag" } catch { $Errors += $PSItem.Exception.Message } $ErrorsOSHardening = Add-RMOSHardening -Source $Source -UpdatedParameter $UserInput -UserParameter $PSBoundParameters if ($null -ne $ErrorsOSHardening) { $Errors += $ErrorsOSHardening } if (($IgnoreValidationError -and $OverrideExistingMigration) -or ` (!$IgnoreValidationError -and $OverrideExistingMigration) -or ` $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionsAsHashTable, $MigrationInstructionErrors = Get-RMMigrationInstructionAsHashTable -OrganizationId $CloudAccount.organization_id ` -MigrationInstruction $MigrationInstruction -AccountType "aws" if ($null -ne $MigrationInstructionErrors) { $Errors += $MigrationInstructionErrors } if ([string]::IsNullOrWhiteSpace($ScheduledAt)) { $ScheduledAt = "" } else { $ScheduledAt = Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt } $MTUSize = $ProjectSettingsResponse.aws.mtu_size $UserInput.Add("MTUSize", $MTUSize) Add-RMConvertFileSystem -Source $Source -UpdatedUserInput $UserInput -ConvertFileSystem $ConvertFileSystem if ([string]::IsNullOrEmpty($NetBIOSName)) { $NetBIOSName = $Source.hostname } $KMSName = $null if ($KMSActivation) { $KMSName = "169.254.169.250" if ($null -ne $ProjectSettingsResponse.aws.kms_fqdn) { $KMSName = $ProjectSettingsResponse.aws.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 EncryptVolume = $EncryptAllVolume VolumeType = $VolumeType ResizeMountPoint = $MountsResize TransferMethod = $TransferMethod IOPS = $IOPS Region = $Region VPCID = $VPCID SubnetID = $SubnetID AutoAssignPublicIP = $AutoAssignPublicIPBool StaticPrivateIP = $StaticPrivateIP Tenancy = $Tenancy InstanceType = $InstanceType EnforceTargetNetworkIsolation = $EnforceTargetNetworkIsolation SecurityGroup = $SecurityGroupMapping IAMRole = $RoleARN ShouldCreateAMI = $ShouldCreateAMI InstanceTag = $InstanceTagAsHashTable SQLServerUpgrade = $SQLServerUpgrade DisableTargetDNSRegistration = $DisableTargetDNSRegistration ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget RemoveRMSAgent = $RemoveRMSAgent MigrationInstruction = $MigrationInstructionAsHashTable IgnoreValidationError = $IgnoreValidationError KMSKey = $KMSKeyAliasName EnableNetAppFileMigration = $EnableNetAppFileMigration NetBIOSName = $NetBIOSName KMSName = $KMSName GeneralizeSystem = $Sysprep ReplaceWindowsLicense = $ReplaceWindowsLicense } $HashArguments += $UserInput $Response = New-RMAWSMigrationProfile @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 Confirm-RMAWSFullMigrationParameter { param( [hashtable] $UserParameter ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent = Confirm-RMCommonParameter -UserParameter $UserParameter $AWSErrors, $IsRequiredParametersPresentAndValid = Confirm-RMAWSParameter -UserParameter $UserParameter $Errors += $AWSErrors return $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid } function Confirm-RMAWSParameter { param( [hashtable] $UserParameter ) $Errors = @() $IsRequiredParametersPresentAndValid = $true if (!$UserParameter.ContainsKey("InstanceType") -or [string]::IsNullOrWhiteSpace($UserParameter["InstanceType"])) { $Errors += "InstanceType is required." $IsRequiredParametersPresentAndValid = $false } if (($UserParameter.ContainsKey("EnforceTargetNetworkIsolation") -and !$UserParameter["EnforceTargetNetworkIsolation"] -or !$UserParameter.ContainsKey("EnforceTargetNetworkIsolation"))-and (!$UserParameter.ContainsKey("SecurityGroup") -or [string]::IsNullOrWhiteSpace($UserParameter["SecurityGroup"]))) { $Errors += "SecurityGroup is required, when parameter 'EnforceTargetNetworkIsolation' is false." } if ($UserParameter.ContainsKey("EncryptAllVolume") -and $UserParameter["EncryptAllVolume"] -and ( !$UserParameter.ContainsKey("KMSKeyAliasName") -or [string]::IsNullOrWhiteSpace($UserParameter["KMSKeyAliasName"]))) { $Errors += "KMSKeyAliasName is required, when parameter 'EncryptAllVolume' is true." $IsRequiredParametersPresentAndValid = $false } return $Errors, $IsRequiredParametersPresentAndValid } function Confirm-RMAWSRegionParameter { param ( [hashtable] $UserParameter, [System.Object] $CloudAccount ) $Errors = @() $IsRequiredParametersPresentAndValid = $true if ($UserParameter.ContainsKey("Region") -and ![string]::IsNullOrWhiteSpace($UserParameter["Region"]) -and $UserParameter["Region"] -ne $CloudAccount.appliance.cloud_properties.region) { if (!$UserParameter.ContainsKey("VPCID") -or [string]::IsNullOrWhiteSpace($UserParameter["VPCID"])) { $Errors += "VPCID is required." $IsRequiredParametersPresentAndValid = $false } if (!$UserParameter.ContainsKey("SubnetID") -or [string]::IsNullOrWhiteSpace($UserParameter["SubnetID"])) { $Errors += "SubnetID is required." $IsRequiredParametersPresentAndValid = $false } } return $Errors, $IsRequiredParametersPresentAndValid } function Confirm-RMAWSFullMigrationParameterWithSource { param( [hashtable] $UserParameter, [System.Object] $Source, [System.Object] $SourceSQLServerMapping, [System.Array] $MigrationExtension, [System.Array] $MigrationExtensionOSM, [hashtable] $WindowsLicense ) $Errors = Confirm-RMCommonParameterWithSource -UserParameter $UserParameter -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping -MigrationExtension $MigrationExtension ` -MigrationExtensionOSM $MigrationExtensionOSM -WindowsLicense $WindowsLicense if ($Source.os_type -ne 'windows' -and $UserParameter["DisableTargetDNSRegistration"]) { $Errors += "DisableTargetDNSRegistration can only be 'true', if the source type is 'windows'." } return $Errors } function Confirm-RMAWSVMBasedFullMigrationParameter { param ( [hashtable] $UserParameter ) $Errors, $Warnings, $IsSourcePresent = Confirm-RMVMBasedCommonParameter -UserParameter $UserParameter $AWSErrors, $IsRequiredParametersPresentAndValid = Confirm-RMAWSParameter -UserParameter $UserParameter $Errors += $AWSErrors return $Errors, $Warnings, $IsSourcePresent, $IsRequiredParametersPresentAndValid } function Confirm-RMAWSVMBasedFullMigrationParameterWithSource { param ( [hashtable] $UserParameter, [System.Object] $Source, [System.Object] $MigrationExtension ) $Errors = @() if ($UserParameter.ContainsKey("MigrationExtension") -and ![string]::IsNullOrWhiteSpace($UserParameter["MigrationExtension"])) { $MigrationExtensionValue = $UserParameter["MigrationExtension"] if ($MigrationExtension -notcontains $MigrationExtensionValue) { $Errors += "MigrationExtension '$MigrationExtensionValue' does not exist." } } $SourceDiskLabels = Get-RMVMBasedSourceDiskLabel -Source $Source $DiskLabelsNotFound = @() foreach ($DiskLabel in $UserParameter["SelectedDiskLabel"]) { if ($SourceDiskLabels -notcontains $DiskLabel) { $DiskLabelsNotFound += $DiskLabel } } if ($DiskLabelsNotFound.Count -gt 0) { $DiskLabelsNotFoundAsString = $DiskLabelsNotFound -join ", " $Errors += "The disk label(s) '$DiskLabelsNotFoundAsString' specified in the parameter 'SelectedDiskLabel' does not exist on the source" } return $Errors } function Confirm-RMRegion { param( [System.Object] $CloudAttributesSummary, [string] $RegionName ) $ValidRegion = $false [array] $RegionArray = $CloudAttributesSummary.properties.regions foreach($Region in $RegionArray) { if ($RegionName -ieq $Region.name) { $ValidRegion = $true break } } return $ValidRegion } function Confirm-RMVPCID { param( [System.Object] $VPCList, [string] $VPCID ) $ValidVPCID = $false foreach($VPC in $VPCList) { if ($VPCID -ieq $VPC.id) { $ValidVPCID = $true return $ValidVPCID , $VPC } } return $ValidVPCID , $null } function Confirm-RMSubnet { param( [System.Object] $VPC, [string] $SubnetId ) $ValidSubnet = $false $SubnetArray = $VPC.subnets foreach ($Subnet in $SubnetArray) { if ($SubnetId -ieq $Subnet.id) { $ValidSubnet = $true return $ValidSubnet, $Subnet } } return $ValidSubnet, $null } function Confirm-RMSecurityGroup { param ( [string[]] $UserSecurityGroupName, [string[]] $SecurityGroupName ) $ValidSecurityGroup = $true foreach($SecurityGroup in $UserSecurityGroupName) { if ($SecurityGroupName -notcontains $SecurityGroup) { $ValidSecurityGroup = $false break } } return $ValidSecurityGroup } function Confirm-RMInstanceType { param( [array] $InstanceTypeName, [string] $UserInstanceTypeName ) $ValidInstanceType = $false if ($InstanceTypeName -contains $UserInstanceTypeName) { $ValidInstanceType = $true } return $ValidInstanceType } function Confirm-RMSupportVolumeType { param( [System.Object] $Source ) $SupportVolumeType = $true $SourceMountPointObject = Get-RMMountPointObject -Source $Source foreach($MountPoint in $SourceMountPointObject) { $TotalSpace = [math]::round($MountPoint.size_kb/(1024 * 1024), 2) if ($TotalSpace -lt 4) { $SupportVolumeType = $false break } } return $SupportVolumeType } function Get-RMARN { param ( [System.Object] $CloudAttributesSummary, [string] $IAMRoleName ) $InstaceProfileArray = $CloudAttributesSummary.properties.instance_profiles foreach ($Profile in $InstaceProfileArray) { if ($IAMRoleName -ieq $Profile.name) { return $Profile.arn } } return $null } function Confirm-RMMigrationExtension { param ( [System.Object] $MigrationExtensionObject, [string] $MigrationExtensionName ) $ValidMigrationExtension = $false $MigrationExtensionArray = $MigrationExtensionObject.content foreach ($MigrationExtension in $MigrationExtensionArray) { if ($MigrationExtensionName -ieq $MigrationExtension.name) { $ValidMigrationExtension = $true return $ValidMigrationExtension, $MigrationExtension.id } } return $ValidMigrationExtension, $null } function Get-ValidVPCData { param( [array] $VPCObject, [string] $VPCID ) foreach ($VPC in $VPCObject) { if ($VPCID -ieq $VPC.id) { return $VPC } } return $null } function Get-RMARNByKMSKey { param ( [System.Object] $KMSKeyObject, [string] $KMSName ) foreach($KMSKey in $KMSKeyObject) { if ($KMSName -ieq $KMSKey.alias_name) { return $KMSKey.arn } } return $null } function Get-RMSubnetBySubnetIDAndVPC { param ( [string] $SubnetID, [System.Object] $VPCObject ) $SubnetObject = $VPCObject.subnets foreach ($Subnet in $SubnetObject) { if ($SubnetID -ieq $Subnet.id) { return $Subnet } } return $null } function Start-RMInteractiveAWSVMBasedMigration { param() $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "aws" ` -UserMessage "Enter target cloud that supports VM-based migrations" -VMBasedAppliancesOnly $true $Source = Read-RMVMBasedSource -UserMessage "Enter the VM name of the source machine to be migrated" ` -ParameterName "Source VM name" -IsRequired $true -CloudAccount $CloudAccount $Entitlement = Get-RMEntitlement $UserInput.Add("Entitlement", $Entitlement) [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() if ($null -eq $CloudAccount) { return Update-RMMigrationReturnAsError ` -Message "The migration appliance associated with the given source is not ready for use, cannot start the migration" ` -RMMigrationReturn $RMMigrationReturn } $UserInput.Add("CloudAccount", $CloudAccount) $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount $IgnoreValidationErrors = Read-RMBoolean -UserMessage "Ignore validation errors" -DefaultValue "false" $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationErrors) $UserInput.Add("CloudAttributes", $CloudAttributes) $SourceAttributeResult = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn ` -AccountType "aws" $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = $SourceAttributeResult $UserInput.Add("Source", $Source) if ($ShouldExit) { return $RMMigrationReturn } if ($OverrideExistingMigrationError) { $OverrideExistingMigrationError = Read-RMBoolean -UserMessage "Would you like to override the previous migration attempt" -DefaultValue $false if (!$IgnoreValidationErrors -and !$OverrideExistingMigrationError) { return $RMMigrationReturn } } $ScheduledAt = Read-RMMigrationSchedule $UserInput.Add("ScheduledAt", $ScheduledAt) $TargetVMName = Read-RMString -UserMessage "Enter target VM Name" -DefaultValue $Source.host ` -ParameterName "Target VM Name" -IsRequired $false $UserInput.Add("TargetVMName", $TargetVMName) #Placement Settings $CloudSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $RegionName = Read-RMString -UserMessage "Enter the region name where the source VM should be migrated to" ` -ParameterName "Region name" -Options $CloudSummary.properties.regions.name ` -DefaultValue $CloudAttributes.properties.regions[0].name -IsRequired $false $UserInput.Add("Region", $RegionName) $HasRegionChanged = $false if ($CloudAttributes.properties.regions[0].name -ine $RegionName) { Write-Output "Getting cloud attributes for region $RegionName ..." | Out-Host $CloudAttributes = Get-RMCloudAttributesByRegion -CloudAccount $CloudAccount -RegionName $RegionName $HasRegionChanged = $true } $UserInput.Add("InstanceType", (Read-RMInstanceType -CloudAttributes $CloudAttributes -VMMigration $true)) $ReadValue = Read-RMPair -UserMessage "Enter one or more instance tags in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue "None" $InstanceTags = Get-RMStringAsHashtable -InputString $ReadValue $UserInput.Add("InstanceTag", $InstanceTags) if (0 -eq $Source.attributes.storage.vm_disks.Count) { return Update-RMMigrationReturnAsError ` -Message "Source has no disks, cannot be migrated" -RMMigrationReturn $RMMigrationReturn } $SourceDisksAsString = "Disks to be migrated [" + ((Get-RMVMDiskProperty -Source $Source) -join ", ") + "]" Write-Output $SourceDisksAsString | Out-Host $SelectedDisks = @() $ReturnedValue = Get-RMSelectedDisk -Source $Source if ($SelectedDisks -is [hashtable]) { $SelectedDisks += $ReturnedValue } else { $SelectedDisks = $ReturnedValue } $UserInput.Add("SelectedDisk", $SelectedDisks) #TODO - Add check for source supports IO1 and IO2 (NEED TO FIND WHEN EACH VOL TYPE IS SUPPORTED, INCLUDING GP2 AND 3) $VolumeType = Read-RMString -UserMessage "Enter volume type" -ParameterName "Volume type" -Options "GP2", ` "GP3", "IO1", "IO2", "Magnetic" -DefaultValue "GP3" -IsRequired $false $UserInput.Add("VolumeType", (Get-RMVolumeTypeByUserInput -UserInputVolumeType $VolumeType)) $VPC = Get-RMVPCByCloudAttributes -CloudAttributes $CloudAttributes $VPCID = "" if ($HasRegionChanged) { $VPCID = Read-RMString -UserMessage "Enter the VPC ID" -ParameterName "VPC ID" ` -Options $VPC.Keys -IsRequired $true } else { $VPCID = Read-RMString -UserMessage "Enter the VPC ID" -ParameterName "VPC ID" ` -DefaultValue $CloudAccount.appliance.cloud_properties.vpc ` -Options $VPC.Keys -IsRequired $false } $UserInput.Add("VPCID", $VPCID) $SubnetIDs = Get-RMSubnetIDBySubnet -Subnet $VPC[$VPCID] $SubnetID = "" if ($HasRegionChanged) { $SubnetID = Read-RMString -UserMessage "Enter the subnet ID" -ParameterName "Subnet ID" ` -Option $SubnetIDs -IsRequired $true } else { $SubnetID = Read-RMString -UserMessage "Enter the subnet ID" -ParameterName "Subnet ID" ` -DefaultValue $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name ` -Option $SubnetIDs -IsRequired $false } $UserInput.Add("SubnetID", $SubnetID) $Subnet = Get-RMSubnetByVPCIDAndSubnetID -VPCID $VPCID -SubnetID $SubnetID -VPC $VPC $AutoAssignPublicIP = Read-RMBoolean -UserMessage "Auto assign public IP address" ` -DefaultValue ($Subnet.map_public_ip).ToString().ToLower() $UserInput.Add("AutoAssignPublicIP", $AutoAssignPublicIP) $UserInput.Add("AvailabilityZone", $Subnet.availability_zone) $UserInput.Add("StaticPrivateIP", (Read-RMString -UserMessage "Enter the static private IP address" ` -DefaultValue "None" -ParameterName "Static private IP address" -IsRequired $false)) #Optimization Settings $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 $EnableEBSEncryption = Read-RMBoolean -UserMessage "Enable EBS encryption on all volumes" -DefaultValue "false" $UserInput.Add("EncryptAllVolume", $EnableEBSEncryption) $KMSKey = "" if ($EnableEBSEncryption) { $ReadValue = Read-RMString -UserMessage "Enter disk encryption type" -Options "platform-managed-key" , "customer-managed-key" ` -DefaultValue "platform-managed-key" -ParameterName "Encryption Type" -IsRequired $false if ("customer-managed-key" -ieq $ReadValue) { $KMSKeyArray = $CloudAttributes.properties.regions.kms_keys.alias_name $ReadValue = Read-RMString -UserMessage "Enter KMS Key" -DefaultValue "None" -ParameterName "KMS Key" ` -IsRequired $false -Options $KMSKeyArray $KMSKey = Get-RMARNByKMSKey -KMSKeyObject $CloudAttributes.properties.regions.kms_keys -KMSName $ReadValue } } $UserInput.Add("KMSKey", $KMSKey) $EnforceTargetNetworkIsolation = Read-RMBoolean -UserMessage "Enforce target network isolation" -DefaultValue "true" $UserInput.Add("EnforceTargetNetworkIsolation", $EnforceTargetNetworkIsolation) $VPCIDToSecurityGroup = Get-RMVPCAndSecurityGroupMapping -CloudAttributes $CloudAttributes [array] $RMRequiredSG = $VPCIDToSecurityGroup[$VPCID].name | Where-Object {$_ -clike ("RM-Migration-TargetWorker-*")} if (!$EnforceTargetNetworkIsolation) { $UserSecurityGroups = @() if ($null -eq $RMRequiredSG) { $UserSecurityGroups = Read-RMToken -UserMessage "Enter one or more security group names, separated by commas" ` -ParameterName "Security group names" -Options $VPCIDToSecurityGroup[$VPCID].name -IsRequired $true -Separator "," } else { $DefaultSecurityGroup = $RMRequiredSG -join ", " $ReadValue = Read-RMToken -UserMessage "Enter one or more security group names, separated by commas" ` -ParameterName "Security group names" -Options $VPCIDToSecurityGroup[$VPCID].name -DefaultValue $DefaultSecurityGroup ` -IsRequired $false -Separator "," if ($ReadValue -is [string]) { $UserSecurityGroups += @($ReadValue.split(",").Trim()) } else { $UserSecurityGroups += $ReadValue } foreach ($SG in $RMRequiredSG) { if ($UserSecurityGroups -notcontains $SG) { $UserSecurityGroups += $SG } } } } else { $UserSecurityGroups += $RMRequiredSG } $SecurityGroupMapping = Get-RMSecurityGroupIDToNameMapping -SelectedSecurityGroupName $UserSecurityGroups ` -SecurityGroup $VPCIDToSecurityGroup[$VPCID] $UserInput.Add("SecurityGroup", $SecurityGroupMapping) if ($CloudAttributes.properties.instance_profiles.Count -gt 0) { $IAMNameToARNMapping = Get-RMIAMRoleToARNMapping -CloudAttributes $CloudAttributes $IAMRole = Read-RMString -UserMessage "Enter the IAM role name that you want to add to the target VM" ` -ParameterName "IAM role name" -Options $IAMNameToARNMapping.Keys -DefaultValue "None" -IsRequired $false if (![string]::IsNullOrWhiteSpace($IAMRole)) { $UserInput.Add("AddIAMRole", $IAMNameToARNMapping[$IAMRole]) } } #Advanced Settings $UserInput.Add("CreateAMI", (Read-RMBoolean -UserMessage "Create AMI from the target instance" -DefaultValue "false")) $UserInput.Add("ShutdownSource", (Read-RMBoolean -UserMessage "Shutdown source after data is fully migrated" -DefaultValue "false")) $UserInput.Add("ShutdownTarget", (Read-RMBoolean -UserMessage "Shutdown target after data is fully migrated" -DefaultValue "false")) $UserInput.Add("FinalizeMigration", (Read-RMBoolean -UserMessage "Remove snapshot(s) from the Target VM in preparation for a cutover" ` -DefaultValue "false")) $MigrationInstructionResponse = Get-RMMigrationInstruction -OrganizationId $CloudAccount.organization_id $MigrationInstructionDefaultValue = "None" if ($null -ne $MigrationInstructionResponse.aws) { $MigrationInstructionDefaultValue = $MigrationInstructionResponse.aws -replace ":", "=" ` -replace "@", "" -replace "{", "" -replace "}", "" } $ReadValue = Read-RMPair -UserMessage "Enter migration instructions in the format 'key=value' and separated by commas" ` -Separator "=" -DefaultValue $MigrationInstructionDefaultValue if (($IgnoreValidationErrors -and $OverrideExistingMigrationError) -or (!$IgnoreValidationErrors -and $OverrideExistingMigrationError) -or $OverrideExistingMigrationWarning) { if ("" -eq $ReadValue) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstructions = Get-RMStringAsHashtable -InputString $ReadValue $UserInput.Add("MigrationInstruction", $MigrationInstructions) $MTUSizeResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $MTUSize = $MTUSizeResponse.aws.mtu_size $UserInput.Add("MTUSize", $MTUSize) $Response = New-RMAWSVMBasedMigrationProfile @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-RMNonInteractiveAWSVMBasedMigration { param ( [string] $SourceVMName, [string] $SourceVMFolderPath, [string] $TargetCloud, [string] $ScheduledAt, [string] $TargetVMName, [string[]] $SelectedDiskLabel, [bool] $EncryptAllVolume, [string] $DiskEncryptionType, [string] $KMSKeyAliasName, [string] $VolumeType, [string] $IOPS, [string] $Region, [string] $VPCID, [string] $SubnetID, [string] $AssignPublicIP, [string] $StaticPrivateIP, [string] $InstanceType, [bool] $EnforceTargetNetworkIsolation, [string[]] $SecurityGroup, [string] $IAMRole, [bool] $CreateAMI, [string] $MigrationExtension, [string[]] $InstanceTag, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $FinalizeMigration, [string[]] $MigrationInstruction, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration ) $CloudAccount = $null $Source = $null $Errors = @() $UserInput = @{} $ShouldExit = $false [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Errors, $Warnings, $IsSourceAndTargetCloudPresent, $IsRequiredParametersPresentAndValid = Confirm-RMAWSVMBasedFullMigrationParameter $PSBoundParameters try { if (![string]::IsNullOrWhiteSpace($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "aws" -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-RMAWSOSBasedMigration'." 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 "aws" 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-RMAWSVMBasedFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source ` -MigrationExtension $MigrationExtensionArray $Errors += $SourceErrors $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $CloudAttributesErrors = Confirm-RMCloudAttributes -UserParameter $PSBoundParameters -CloudAccount $CloudAccount -Source $Source -CloudAttributes $CloudAttributes ` -CloudAttributesSummary $CloudAttributesSummary $Errors += $CloudAttributesErrors } Add-RMMigrationExtension -UpdatedParameter $UserInput -MigrationExtension $MigrationExtension ` -MigrationExtensionOSM $MigrationExtensionOSM -MigrationExtensionResponse $MigrationExtensionResponse if ([string]::IsNullOrWhiteSpace($ScheduledAt)) { $ScheduledAt = "" } else { $ScheduledAt = Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt } if ([string]::IsNullOrWhiteSpace($TargetVMName)) { $TargetVMName = $Source.host } $SelectedDisk = Get-RMSelectedDiskByDiskLabel -DiskLabel $SelectedDiskLabel -Source $Source if (![string]::IsNullOrWhiteSpace($KMSKeyAliasName)) { $KMSKeyAliasName = Get-RMARNByKMSKey -KMSKeyObject $CloudAttributes.properties.regions.kms_keys -KMSName $KMSKeyAliasName } if ([string]::IsNullOrWhiteSpace($VolumeType)) { $VolumeType = "ssd2" } else { try { $ValidVolumeType = Confirm-RMSupportVolumeType -Source $Source $VolumeType = Get-RMVolumeType -VolumeType $VolumeType -SupportVolumeType $ValidVolumeType } catch { $Errors += $PSItem.Exception.Message } } if ([string]::IsNullOrWhiteSpace($Region) -or $Region -ieq $CloudAccount.appliance.cloud_properties.region) { $Region = $CloudAccount.appliance.cloud_properties.region if ([string]::IsNullOrWhiteSpace($VPCID)) { $VPCID = $CloudAccount.appliance.cloud_properties.vpc } if ([string]::IsNullOrWhiteSpace($SubnetID)) { $SubnetID = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } } $VPCIDToSecurityGroup = Get-RMVPCAndSecurityGroupMapping -CloudAttributes $CloudAttributes $DefaultSecurityGroup = $VPCIDToSecurityGroup[$VPCID].name | Where-Object {$_ -clike ("RM-Migration-TargetWorker*")} if ($EnforceTargetNetworkIsolation) { $SecurityGroup = $DefaultSecurityGroup } else { foreach ($SG in $DefaultSecurityGroup) { if ($SecurityGroup -notcontains $SG) { $SecurityGroup += $SG } } } $SecurityGroupMapping = Get-RMSecurityGroupIDToNameMapping -SelectedSecurityGroupName $SecurityGroup ` -SecurityGroup $VPCIDToSecurityGroup[$VPCID] if ([string]::IsNullOrWhiteSpace($AssignPublicIP)) { $AssignPublicIP = "Use-subnet-setting" } $AutoAssignPublicIPBool = Get-RMAutoAssignPublicIP -AutoAssignPublicIPName $AssignPublicIP ` -SubnetObject $CloudAttributes.properties.regions[0].vpcs.subnets -SubnetId $SubnetID if (![string]::IsNullOrWhiteSpace($IAMRole)) { $RoleARN = Get-RMARN -CloudAttributesSummary $CloudAttributesSummary -IAMRoleName $IAMRole } $InstanceTagAsHashTable = $null try { $InstanceTagAsHashTable = Get-RMStringArrayAsHashtable -InputItems $InstanceTag -ParameterName "InstanceTag" } catch { $Errors += $PSItem.Exception.Message } if (($IgnoreValidationError -and $OverrideExistingMigration) -or ` (!$IgnoreValidationError -and $OverrideExistingMigration) -or ` $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionsAsHashTable, $MigrationInstructionErrors = Get-RMMigrationInstructionAsHashTable -OrganizationId $CloudAccount.organization_id ` -MigrationInstruction $MigrationInstruction -AccountType "aws" if ($null -ne $MigrationInstructionErrors) { $Errors += $MigrationInstructionErrors } $MTUSizeResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $MTUSize = $MTUSizeResponse.aws.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 CloudAttributes = $CloudAttributes Entitlement = $Entitlement Source = $Source SourceVMName = $SourceVMName ScheduledAt = $ScheduledAt TargetVMName = $TargetVMName SelectedDisk = $SelectedDisk EncryptAllVolume = $EncryptAllVolume KMSKey = $KMSKey VolumeType = $VolumeType IOPS = $IOPS Region = $Region VPCID = $VPCID SubnetID = $SubnetID AutoAssignPublicIP = $AutoAssignPublicIPBool StaticPrivateIP = $StaticPrivateIP InstanceType = $InstanceType EnforceTargetNetworkIsolation = $EnforceTargetNetworkIsolation SecurityGroup = $SecurityGroupMapping AddIAMRole = $RoleARN CreateAMI = $CreateAMI InstanceTag = $InstanceTagAsHashTable ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget FinalizeMigration = $FinalizeMigration MigrationInstruction = $MigrationInstructionAsHashTable IgnoreValidationError = $IgnoreValidationError OverrideExistingMigration = $OverrideExistingMigration MTUSize = $MTUSize } $HashArguments += $UserInput $Response = New-RMAWSVMBasedMigrationProfile @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-RMCloudAttributes { param ( [hashtable] $UserParameter, [System.Object] $CloudAccount, [System.Object] $Source, [System.Object] $CloudAttributes, [System.Object] $CloudAttributesSummary ) $Errors = @() $RegionParameterPresentAndValid = $true if ($UserParameter.ContainsKey("DiskEncryptionType") -and ![string]::IsNullOrWhiteSpace($UserParameter["DiskEncryptionType"]) -and ` $UserParameter.ContainsKey("KMSKeyAliasName") -and ![string]::IsNullOrWhiteSpace($UserParameter["KMSKeyAliasName"]) -and ` (!$UserParameter.ContainsKey("EncryptAllVolume") -or !$UserParameter["EncryptAllVolume"])) { $Errors += "EncryptAllVolume is required, when parameter 'DiskEncryptionType' and 'KMSKeyAliasName' parameters is specified." } elseif (($UserParameter.ContainsKey("EncryptAllVolume") -or $UserParameter["EncryptAllVolume"]) -and ` $UserParameter.ContainsKey("KMSKeyAliasName") -and ![string]::IsNullOrWhiteSpace($UserParameter["KMSKeyAliasName"]) -and ` (!$UserParameter.ContainsKey("DiskEncryptionType") -or [string]::IsNullOrWhiteSpace($UserParameter["DiskEncryptionType"]))) { $Errors += "DiskEncryptionType is required, when parameter 'EncryptAllVolume' is 'true' and 'KMSKeyAliasName' parameter is specified." } elseif ((!$UserParameter.ContainsKey("DiskEncryptionType") -or [string]::IsNullOrWhiteSpace($UserParameter["DiskEncryptionType"])) -and ` (!$UserParameter.ContainsKey("EncryptAllVolume") -or !$UserParameter["EncryptAllVolume"]) -and ` $UserParameter.ContainsKey("KMSKeyAliasName") -and ![string]::IsNullOrWhiteSpace($UserParameter["KMSKeyAliasName"])) { $Errors += "'EncryptAllVolume' and 'DiskEncryptionType' are required, when the 'KMSKeyAliasName' perimeter is specified." } elseif ($UserParameter.ContainsKey("KMSKeyAliasName") -and ![string]::IsNullOrWhiteSpace($UserParameter["KMSKeyAliasName"]) -and ` $UserParameter.ContainsKey("EncryptAllVolume") -and $UserParameter["EncryptAllVolume"] -and ` $UserParameter.ContainsKey("DiskEncryptionType") -and ![string]::IsNullOrWhiteSpace($UserParameter["DiskEncryptionType"])) { if ( "customer-managed-key" -ieq $UserParameter["DiskEncryptionType"]) { $KMSKeyArray = $CloudAttributes.properties.regions.kms_keys.alias_name if ($KMSKeyArray -notcontains $KMSKeyAliasName) { $Errors += "KMSKeyAliasName '$KMSKeyAliasName' does not exist." } } else { $Errors += "'DiskEncryptionType' can be 'customer-managed-key', when when parameter 'EncryptAllVolume' is 'true' and 'KMSKeyAliasName' parameter is specified." } } if ($UserParameter.ContainsKey("VolumeType") -and ![string]::IsNullOrWhiteSpace($UserParameter["VolumeType"])) { if (![string]::IsNullOrWhiteSpace($UserParameter["IOPS"])) { try { $IOPS = [int]$UserParameter["IOPS"] if ("io1" -ieq $UserParameter["VolumeType"] -and ($IOPS -lt 100 -or $IOPS -gt 700)) { $Errors += "IOPS should be in the range of 100 to 700" } elseif ("io2" -ieq $UserParameter["VolumeType"] -and ($IOPS -lt 100 -or $IOPS -gt 7000)) { $Errors += "IOPS should be in the range of 100 to 7000" } } catch { $Errors += "'IOPS' must be an integer value only." } } } if ($UserParameter.ContainsKey("Region") -and ![string]::IsNullOrWhiteSpace($UserParameter["Region"])) { $RegionErrors, $RegionParameterPresentAndValid = Confirm-RMAWSRegionParameter -UserParameter $UserParameter -CloudAccount $CloudAccount $Errors += $RegionErrors if ($RegionParameterPresentAndValid) { $ValidRegion = Confirm-RMRegion -CloudAttributesSummary $CloudAttributesSummary -RegionName $UserParameter["Region"] if (!$ValidRegion) { $Errors += "Invalid Region Name" } else { $RegionArray = Get-RMCloudAttributesByRegion -CloudAccount $CloudAccount -RegionName $UserParameter["Region"] } } } else { $Region = $CloudAccount.appliance.cloud_properties.region $RegionArray = Get-CachedCloudAttribute -CloudAccount $CloudAccount } if ($RegionParameterPresentAndValid) { if ($UserParameter.ContainsKey("VPCID") -and ![string]::IsNullOrWhiteSpace($UserParameter["VPCID"])) { $ValidVPCID, $VPC = Confirm-RMVPCID -VPCList $RegionArray.properties.regions.vpcs -VPCID $VPCID if (!$ValidVPCID) { $Errors += "VPCID '$VPCID' does not exist in region '$Region'" } else { if ($UserParameter.ContainsKey("SubnetID") -and ![string]::IsNullOrWhiteSpace($UserParameter["SubnetID"])) { $ValidSubnet, $Subnet = Confirm-RMSubnet -VPC $VPC -SubnetId $SubnetID if (!$ValidSubnet) { $Errors += "SubnetID '$SubnetID' does not exist in VPC with ID '$VPCID'" } } } } elseif ($UserParameter.ContainsKey("SubnetID") -and ![string]::IsNullOrWhiteSpace($UserParameter["SubnetID"])) { $Errors += "VPCID is required, when the 'SubnetID' perimeter is specified." } } if ($UserParameter.ContainsKey("IAMRole") -and ![string]::IsNullOrWhiteSpace($UserParameter["IAMRole"])) { if ($RegionArray.properties.instance_profiles.name -notcontains $UserParameter["IAMRole"]) { $Errors += "IAMRole does not exist" } } $ValidInstanceType = Confirm-RMInstanceType -InstanceTypeName $RegionArray.properties.regions.instance_types ` -UserInstanceTypeName $UserParameter["InstanceType"] if (!$ValidInstanceType) { $Errors += "Invalid InstanceType" } if ($UserParameter.ContainsKey("SecurityGroup") -and ![string]::IsNullOrWhiteSpace($UserParameter["SecurityGroup"])) { $VPCIDToSecurityGroup = Get-RMVPCAndSecurityGroupMapping -CloudAttributes $CloudAttributes if ([string]::IsNullOrWhiteSpace($UserParameter["VPCID"])) { $UserParameter["VPCID"] = $CloudAccount.appliance.cloud_properties.vpc } $ValidSecurityGroup = Confirm-RMSecurityGroup -UserSecurityGroupName $UserParameter["SecurityGroup"] -SecurityGroupName $VPCIDToSecurityGroup[$UserParameter["VPCID"]].name if (!$ValidSecurityGroup) { $Errors += "Invalid SecurityGroup" } } return $Errors } function Get-RMIAMRoleToARNMapping { param( [System.Object] $CloudAttributes ) $IAMNameToARNMapping = @{} foreach ($InstanceProfile in $CloudAttributes.properties.instance_profiles) { $IAMNameToARNMapping[$InstanceProfile.name] = $InstanceProfile.arn } return $IAMNameToARNMapping } function Get-VPCIDAndSubnetIDValue { param ( [system.Object] $RegionArray, [System.Object] $CloudAccount, [string] $VPCID, [string] $SubnetID ) $Errors = @() $ValidVPCID = $true if ([string]::IsNullOrWhiteSpace($VPCID)) { $VPCID = $CloudAccount.appliance.cloud_properties.vpc } $ValidVPCID, $VPC = Confirm-RMVPCID -VPCList $RegionArray.properties.regions.vpcs -VPCID $VPCID if (!$ValidVPCID) { $Errors += "VPCID '$VPCID' does not exist in region '$Region'" } else { if ([string]::IsNullOrWhiteSpace($SubnetID)) { $SubnetID = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } $ValidSubnet, $Subnet = Confirm-RMSubnet -VPC $VPC -SubnetId $SubnetID if (!$ValidSubnet) { $Errors += "SubnetID '$SubnetID' does not exist in VPC with ID '$VPCID" } } return $Errors, $VPC, $VPCID, $Subnet, $SubnetID } Export-ModuleMember -Function Start-RMAWSOSBasedNonInteractiveMigration, Start-RMAWSOSBasedInteractiveMigration, ` Start-RMInteractiveAWSVMBasedMigration, Start-RMNonInteractiveAWSVMBasedMigration |