Migration/AZURE/AZURE.psm1
using module '../../Common/Result' Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath MigrationProfile | Join-Path -ChildPath AzureMigrationProfile) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Preflight | Join-Path -ChildPath Preflight) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Util | Join-Path -ChildPath Util) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Util | Join-Path -ChildPath MigrationUtil) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath CloudAccount | Join-Path -ChildPath CloudAccount) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath RiverMeadow.Release.Source | Join-Path -ChildPath SourceUtil | Join-Path -ChildPath SourceUtil) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Common | Join-Path -ChildPath Common) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath .. | Join-Path -ChildPath Common | Join-Path -ChildPath Wrappers | Join-Path -ChildPath Wrappers) Import-Module -Name @(Join-Path $PSScriptRoot AZUREUtil) function Start-RMAzureOSBasedInteractiveMigration { param() $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "azure" -UserMessage "Enter target cloud" $CloudAttributes = Get-RMCloudAttribute -CloudAccount $CloudAccount $Entitlement = Get-RMEntitlement $UserInput.Add("CloudAccount", $CloudAccount) $UserInput.Add("CloudAttributes", $CloudAttributes) $UserInput.Add("Entitlement", $Entitlement) $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" $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationErrors) [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() $Source, $ShouldExit, $OverrideExistingMigrationWarning, $OverrideExistingMigrationError = Get-RMSourceWithAttribute -Source $Source -CloudAccount $CloudAccount ` -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn -AccountType "azure" 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 } } $UserInput.Add("Source", $Source) $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 $ResourceGroupRegion = "" $ReadValue = Read-RMBoolean -UserMessage "Create a new resource group" -DefaultValue "false" if ($ReadValue) { $ResourceGroup = Read-RMString -UserMessage "Enter the name of the resource group to be created" ` -ParameterName "Resource group name" -IsRequired $true $ResourceGroupRegion = Read-RMString -UserMessage "Enter the region name where the resource group will be created" ` -ParameterName "Resource group region name" -IsRequired $true } else { $ResourceGroup = $CloudAccount.appliance.cloud_properties.resource_group $ResourceGroupOptions = $CloudAttributes.properties.subscriptions.resource_groups.name $ResourceGroup = Read-RMString -UserMessage "Enter existing resource group name" -DefaultValue $ResourceGroup ` -ParameterName "Resource group name" -IsRequired $false -Options $ResourceGroupOptions } $UserInput.Add("ResourceGroup", $ResourceGroup) $UserInput.Add("ResourceGroupRegion", $ResourceGroupRegion) $VMSize = Read-VMSize -CloudAttributes $CloudAttributes $UserInput.Add("VMSize", $VMSize) $MountPoints = Get-MountPoint -Source $Source if (0 -eq $MountPoints.count) { throw "Source has no mount points, cannot be migrated" } $MountPointsAsString = $MountPoints.values -join ", " Write-Output "Mount points to be migrated [$MountPointsAsString]" | Out-Host $ExcludedMountPoints = Get-RMExcludedMountPoint -OSType $Source.os_type -MountPoints $MountPoints.Values $SelectedMountPoints = $MountPoints if ("" -ne $ExcludedMountPoints) { $ExcludedList = $ExcludedMountPoints.Split(",").Trim() $SelectedMountPoints = Get-RMSelectedMount -MountPoints $MountPoints -DifferenceList $ExcludedList -IncludeEqual $false } $UserInput.Add("MountPoints", $SelectedMountPoints) $DiskTypeMappings = @() $ReturnedValue = Get-DiskTypeMappingBySource -Source $Source -VMSize $VMSize -IsInteractive $true if ($ReturnedValue -is [hashtable]) { # The method "Get-DiskTypeMappingBySource" returns an array of hashtables, but it # has been observed that if the source contains a single disk, the returned value # is of type HashTable; hence we are checking the type and re-adding it to an array $DiskTypeMappings += $ReturnedValue } else { $DiskTypeMappings = $ReturnedValue } $UserInput.Add("DiskTypeMappings", $DiskTypeMappings) $VirtualNetwork = $CloudAccount.appliance.cloud_properties.virtual_network.name $VirualNetworkOptions = $CloudAttributes.properties.subscriptions.regions.networks.name $VirtualNetwork = Read-RMString -UserMessage "Enter virtual network name" -DefaultValue $VirtualNetwork ` -ParameterName "Virtual network name" -IsRequired $false -Options $VirualNetworkOptions $UserInput.Add("VirtualNetwork", $VirtualNetwork) $DestinationNetworkOptions = Get-RMDestinationNetworkName -CloudAttributes $CloudAttributes -VirtualNetworkName $VirtualNetwork $DestinationNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name if ($VirtualNetwork -ieq $CloudAccount.appliance.cloud_properties.virtual_network.name) { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" -DefaultValue $DestinationNetworkName ` -ParameterName "Destination network name" -IsRequired $false -Options $DestinationNetworkOptions.name } else { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" -ParameterName "Destination network name" ` -IsRequired $true -Options $DestinationNetworkOptions.name } $UserInput.Add("DestinationNetworkName", $DestinationNetworkName) $AssignPublicIP = Read-RMBoolean -UserMessage "Auto assign public IP" -DefaultValue "false" $UserInput.Add("AssignPublicIP", $AssignPublicIP) $StaticPrivateIP = Read-RMIPAddress -UserMessage "Enter static private IP to be assigned to target" -DefaultValue "None" ` -ParameterName "Static private IP" -IsRequired $false $UserInput.Add("StaticPrivateIP", $StaticPrivateIP) $AvailabilitySet = $null $AvailabilityZone = $null $FaultDomainCount = $null $UpdateDomainCount = $null if ("" -ieq $VMSize.availability_zones) { $ReadValue = Read-RMString -UserMessage "Enter availability option" -Options "None", "AvailabilitySet" ` -DefaultValue "None" -ParameterName "Availability option" -IsRequired $false } else { $ReadValue = Read-RMString -UserMessage "Enter availability option" -Options "None", "AvailabilityZone", "AvailabilitySet" ` -DefaultValue "None" -ParameterName "Availability option" -IsRequired $false } if ("" -ne $ReadValue -and "none" -ine $ReadValue) { if ("AvailabilityZone" -ieq $ReadValue) { $AvailabilityZone = Read-RMString -UserMessage "Enter the availability zone" -Options $VMSize.availability_zones ` -ParameterName "Availability zone" -IsRequired $true } else { $ReadValue = Read-RMBoolean -UserMessage "Create a new availability set" -DefaultValue "false" if ($ReadValue) { $AvailabilitySet = Read-RMString -UserMessage "Enter the name of the availability set to be created" ` -ParameterName "Availability set name" -IsRequired $true $FaultDomainCount = Read-RMInt -UserMessage "Enter fault domains" -OptionsRange 1, 3 ` -DefaultValue "2" -ParameterName "Fault domains" -IsRequired $false $UpdateDomainCount = Read-RMInt -UserMessage "Enter update domains" -OptionsRange 1, 20 ` -DefaultValue "5" -ParameterName "Update domains" -IsRequired $false } else { $AvailabilitySets = Get-RMAvailabilitySet -CloudAttributes $CloudAttributes -ResourceGroup $ResourceGroup if ($AvailabilitySets.Count -lt 1) { Write-RMError -Message "No existing availability sets in current resource group and location" } else { $AvailabilitySet = Read-RMString -UserMessage "Enter the existing availability set name" -Options $AvailabilitySets ` -ParameterName "Availability set name" -IsRequired $true } } } } $UserInput.Add("AvailabilityZone", $AvailabilityZone) $UserInput.Add("AvailabilitySet", $AvailabilitySet) $UserInput.Add("FaultDomainCount", $FaultDomainCount) $UserInput.Add("UpdateDomainCount", $UpdateDomainCount) $StorageAccount = $null $EnableBootDiagnostics = Read-RMBoolean -UserMessage "Enable boot diagnostics" -DefaultValue "false" if ($EnableBootDiagnostics) { $StorageAccount = Read-RMString -UserMessage "Enter azure storage account name for boot diagnostics" ` -Options $CloudAttributes.properties.subscriptions.regions.storage_accounts.name ` -ParameterName "Storage account name" -IsRequired $true } $UserInput.Add("EnableBootDiagnostics", $EnableBootDiagnostics) $UserInput.Add("StorageAccount", $StorageAccount) $EnableHybridUseBenefit = $false if("windows" -ieq $Source.os_type) { $EnableHybridUseBenefit = Read-RMBoolean -UserMessage "Enable Azure hybrid use benefit" -DefaultValue "false" } $UserInput.Add("EnableHybridUseBenefit", $EnableHybridUseBenefit) $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("InstanceTags", $InstanceTags) # 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.core.windows.net" if ($null -ne $ProjectSettingsResponse.azure.kms_fqdn) { $KMSKey = $ProjectSettingsResponse.azure.kms_fqdn } } $UserInput.Add("KMSKey", $KMSKey) $ReadValue = Read-RMBoolean -UserMessage "Storage Rightsizing" -DefaultValue "false" $MountsResize = @{} $TransferMethodFlag = $true if ($ReadValue) { $TransferMethodFlag = $false $MountsResize = Get-RMInteractiveMountsResize -SelectedMountPoints $SelectedMountPoints -Source $Source } $UserInput.Add("ResizeMountPoints", $MountsResize) $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 # OS Conf and add validation for system flag 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" $SecurityGroup = $null if (!$EnforceTargetNetworkIsolation) { $SecurityGroup = Read-RMSecurityGroup -CloudAttribute $CloudAttributes } $UserInput.Add("SecurityGroup", $SecurityGroup) $EncryptionSet = $null $ReadValue = Read-RMString -UserMessage "Enter disk encryption type" -Options "platform-managed", "customer-managed" ` -DefaultValue "platform-managed" -ParameterName "Disk encryption type" -IsRequired $false if ("customer-managed" -ieq $ReadValue) { $EncryptionSet = Read-RMString -UserMessage "Enter encryption set name" -ParameterName "Encryption set name" -IsRequired $true ` -Options $CloudAttributes.properties.subscriptions.regions.disk_encryption_sets.name } $UserInput.Add("EncryptionSet", $EncryptionSet) # Advanced Settings $TransferMethod = "file-based" if ($TransferMethodFlag) { $TransferMethod = (Get-RMTransferMethod -Source $Source -SelectedMountPoints $SelectedMountPoints -IsInteractive $true)[0] } $UserInput.Add("TransferMethod", $TransferMethod) $RemoveRMSAgentFromSource = Read-RMBoolean -UserMessage "Remove RMS agent post migration from source" -DefaultValue "false" $RemoveRMSAgentFromTarget = Read-RMBoolean -UserMessage "Remove RMS agent post migration from target" -DefaultValue "false" $UserInput.Add("RemoveRMSAgentFromSource", $RemoveRMSAgentFromSource) $UserInput.Add("RemoveRMSAgentFromTarget", $RemoveRMSAgentFromTarget) $DisableTargetDNSRegistration = $false if("windows" -ieq $Source.os_type) { $DisableTargetDNSRegistration = Read-RMBoolean -UserMessage "Disable automatic DNS registration" -DefaultValue "false" } $UserInput.Add("DisableTargetDNSRegistration", $DisableTargetDNSRegistration) $ShutdownSource = Read-RMBoolean -UserMessage "Shutdown source after data is fully migrated" -DefaultValue "false" $UserInput.Add("ShutdownSource", $ShutdownSource) $ShutdownTarget = Read-RMBoolean -UserMessage "Shutdown target after data is fully migrated" -DefaultValue "false" $UserInput.Add("ShutdownTarget", $ShutdownTarget) $ReadValue = Read-RMPair -UserMessage "Enter migration instructions in the format 'key=value' and separated by commas" -Separator "=" -DefaultValue "None" if (($IgnoreValidationErrors -and $OverrideExistingMigrationError) -or (!$IgnoreValidationErrors -and $OverrideExistingMigrationError) -or $OverrideExistingMigrationWarning) { if ("" -eq $ReadValue) { $ReadValue = "override_source_migration=true" } else { $ReadValue += ",override_source_migration=true" } } $MigrationInstructions = Get-RMStringAsHashtable -InputString $ReadValue $UserInput.Add("MigrationInstructions", $MigrationInstructions) $MTUSize = $ProjectSettingsResponse.azure.mtu_size $UserInput.Add("MTUSize", $MTUSize) $Response = New-RMAzureMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id -IgnoreValidationErrors $IgnoreValidationErrors -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Post" Uri = $Uri.Value + "/migrationprofiles/" + $Response.id + "/migrations" Headers = $Headers ContentType = "application/json" } $MigrationResponse = Invoke-RMRestMethod -Params $Params return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMAzureOSBasedNonInteractiveMigration { param( [string] $TargetCloud, [string] $SourceIP, [string] $ScheduledAt, [string] $TargetVMName, [string] $TransferMethod, [bool] $CreateResourceGroup, [string] $ResourceGroup, [string] $ResourceGroupRegion, [string] $VMSizeName, [string[]] $VolumeType, [string[]] $MountPoint, [string[]] $ResizeMountPoint, [string] $VirtualNetwork, [string] $DestinationNetworkName, [bool] $AssignPublicIP, [string] $StaticPrivateIP, [bool] $EnforceTargetNetworkIsolation, [string] $SecurityGroup, [bool] $DisableTargetDNSRegistration, [string[]] $InstanceTag, [string] $AvailabilityOption, [int] $AvailabilityZone, [bool] $CreateAvailabilitySet, [string] $AvailabilitySet, [int] $FaultDomain, [int] $UpdateDomain, [bool] $EnableBootDiagnostics, [string] $StorageAccount, [string] $DiskEncryptionType, [string] $EncryptionSet, [bool] $EnableHybridUseBenefit, [string] $UpgradeOSVersion, [string] $UpgradeOSConversion, [string] $MigrationExtension, [string] $MigrationExtensionOSM, [string] $ConvertFileSystem, [hashtable[]] $UpgradeSQLServer, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $RemoveRMSAgentFromSource, [bool] $RemoveRMSAgentFromTarget, [string[]] $MigrationInstruction, [bool] $IgnoreValidationError, [bool] $OverrideExistingMigration, [string] $NetBIOSName, [bool] $KMSActivation ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent = Confirm-RMAzureFullMigrationParameter $PSBoundParameters $CloudAccount = $null $CloudAttributes = $null $Source = $null [RMMigrationReturn] $RMMigrationReturn = [RMMigrationReturn]::new() try { if (![string]::IsNullOrEmpty($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "azure" if (![string]::IsNullOrEmpty($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]::IsNullOrEmpty($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 "azure" 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 } $MigrationExtensionResponse = Get-RMMigrationExtension -OrganizationId $CloudAccount.organization_id $MigrationExtensionArray, $MigrationExtensionOSMArray = Get-RMMigrationExtensionFromStep -MigrationExtensionArray $MigrationExtensionResponse.content $SourceSQLServerMapping = Get-RMSQLMMappingBySource -Source $Source $Errors += Confirm-RMAzureFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping -MigrationExtension $MigrationExtensionArray ` -MigrationExtensionOSM $MigrationExtensionOSMArray $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $VMSize = Get-VMSizeByName -VMSizeName $VMSizeName -CloudAttributes $CloudAttributes $ErrorsCloudAttributes = Confirm-RMCloudAttributes -UserParameter $PSBoundParameters -CloudAccount $CloudAccount ` -VMSize $VMSize -CloudAttribute $CloudAttributes -CloudAttributesSummary $CloudAttributesSummary $Errors += $ErrorsCloudAttributes $UserInput = @{} $Entitlement = Get-RMEntitlement $UserInput.Add("CloudAccount", $CloudAccount) $UserInput.Add("CloudAttributes", $CloudAttributes) $UserInput.Add("Entitlement", $Entitlement) $UserInput.Add("Source", $Source) if ([string]::IsNullOrEmpty($TargetVMName)) { $TargetVMName = $Source.hostname } $UserInput.Add("TargetVMName", $TargetVMName) if ([string]::IsNullOrWhiteSpace($ResourceGroup)) { $ResourceGroup = $CloudAccount.appliance.cloud_properties.resource_group } $UserInput.Add("ResourceGroup", $ResourceGroup) $UserInput.Add("ResourceGroupRegion", $ResourceGroupRegion) if ($null -eq $VMSize) { $Errors += "VM size by name '$VMSizeName' does not exists." } $UserInput.Add("VMSize", $VMSize) if ([string]::IsNullOrEmpty($VolumeType)) { $VolumeType = "Standard_SSD" } $UserInput.Add("VolumeType", $VolumeType) $SelectedMountPoints = $null $SourceMountPoints = Get-MountPoint -Source $Source if ($MountPoint.Count -gt 0) { $SelectedMountPoints = Get-RMSelectedMount -MountPoints $SourceMountPoints -DifferenceList $MountPoint -IncludeEqual $true } else { # If no mount points are given then take all mount points on the source as the selected mount points $SelectedMountPoints = $SourceMountPoints } $UserInput.Add("MountPoints", $SelectedMountPoints) $MountsResize = @{} if ($null -ne $ResizeMountPoint -and $ResizeMountPoint.Count -gt 0) { try { $ResizeMounts = Get-RMStringArrayAsHashtable -InputItems $ResizeMountPoint -ParameterName "ResizeMountPoint" } catch { $Errors += $PSItem.Exception.Message } if ($null -ne $ResizeMounts) { $MountsResize, $MountsResizeErrors = Add-RMResizeMount -SelectedMounts $SelectedMountPoints.values -ResizeMounts $ResizeMounts -Source $Source if ($null -eq $MountsResize) { $Errors += $MountsResizeErrors } } if ("" -ne $TransferMethod -and "block-based" -eq $TransferMethod ) { $Errors += "Transfer method needs to be 'file-based' if you want to resize the mount points." } $TransferMethod = "file-based" } else { $TransferMethod, $ErrorString = Get-RMTransferMethod -Source $Source -SelectedMountPoints $SelectedMountPoints ` -TransferMethod $TransferMethod if (![string]::IsNullOrEmpty($ErrorString)) { $Errors += $ErrorString } } $UserInput.Add("TransferMethod", $TransferMethod) $UserInput.Add("ResizeMountPoints", $MountsResize) if ([string]::IsNullOrWhiteSpace($VirtualNetwork)) { $VirtualNetwork = $CloudAccount.appliance.cloud_properties.virtual_network.name } $UserInput.Add("VirtualNetwork", $VirtualNetwork) if ([string]::IsNullOrWhiteSpace($DestinationNetworkName)) { $DestinationNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } $UserInput.Add("DestinationNetworkName", $DestinationNetworkName) $UserInput.Add("AssignPublicIP", $AssignPublicIP) $UserInput.Add("StaticPrivateIP", $StaticPrivateIP) if (!$EnforceTargetNetworkIsolation) { $UserInput.Add("SecurityGroup", $SecurityGroup) } if("windows" -ieq $Source.os_type) { $UserInput.Add("DisableTargetDNSRegistration", $DisableTargetDNSRegistration) } else { $UserInput.Add("DisableTargetDNSRegistration", $false) } $InstanceTagsAsHashTable = $null try { $InstanceTagsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $InstanceTag -ParameterName "InstanceTag" } catch { $Errors += $PSItem.Exception.Message } $UserInput.Add("InstanceTags", $InstanceTagsAsHashTable) if ("AvailabilitySet" -ieq $AvailabilityOption) { $UserInput.Add("AvailabilitySet", $AvailabilitySet) $UserInput.Add("AvailabilityZone", "") if ($CreateAvailabilitySet) { $UserInput.Add("FaultDomainCount", $FaultDomain.ToString()) $UserInput.Add("UpdateDomainCount", $UpdateDomain.ToString()) } else { $UserInput.Add("FaultDomainCount", $null) $UserInput.Add("UpdateDomainCount", $null) } } elseif("AvailabilityZone" -ieq $AvailabilityOption) { $UserInput.Add("AvailabilityZone", $AvailabilityZone.ToString()) $UserInput.Add("AvailabilitySet", "") $UserInput.Add("FaultDomainCount", $null) $UserInput.Add("UpdateDomainCount", $null) } $UserInput.Add("EnableBootDiagnostics", $EnableBootDiagnostics) $UserInput.Add("StorageAccount", $StorageAccount) if ([string]::IsNullOrWhiteSpace($EncryptionSet)) { $EncryptionSet = "platform-managed" } $UserInput.Add("EncryptionSet", $EncryptionSet) if("windows" -ieq $Source.os_type) { $UserInput.Add("EnableHybridUseBenefit", $EnableHybridUseBenefit) } else { $UserInput.Add("EnableHybridUseBenefit", $false) } if (![string]::IsNullOrWhiteSpace($UpgradeOSVersion)) { Add-RMOSUpgrade -UserParameter $PSBoundParameters -UpdatedParameter $UserInput -Source $Source } else { Add-RMOSConversionUpgrade -UserParameter $PSBoundParameters -UpdatedParameter $UserInput -Source $Source } Add-RMMigrationExtension -UpdatedParameter $UserInput -MigrationExtension $MigrationExtension ` -MigrationExtensionOSM $MigrationExtensionOSM -MigrationExtensionResponse $MigrationExtensionResponse $SQLServerUpgrade = Get-RMUpgradeSQLServer -UpgradeSQLServer $UpgradeSQLServer -Source $Source ` -SourceSQLServerMapping $SourceSQLServerMapping $UserInput.Add("SQLServerUpgrade", $SQLServerUpgrade) $UserInput.Add("ShutdownSource", $ShutdownSource) $UserInput.Add("ShutdownTarget", $ShutdownTarget) $UserInput.Add("RemoveRMSAgentFromSource", $RemoveRMSAgentFromSource) $UserInput.Add("RemoveRMSAgentFromTarget", $RemoveRMSAgentFromTarget) $MigrationInstructionsAsHashTable = $null try { if (($IgnoreValidationError -and $OverrideExistingMigration) -or (!$IgnoreValidationError -and $OverrideExistingMigration) -or $OverrideExistingMigrationWarning) { $MigrationInstruction += "override_source_migration=true" } $MigrationInstructionsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $MigrationInstruction -ParameterName "MigrationInstruction" } catch { $Errors += $PSItem.Exception.Message } $UserInput.Add("MigrationInstructions", $MigrationInstructionsAsHashTable) $UserInput.Add("IgnoreValidationErrors", $IgnoreValidationError) $ProjectSettingsResponse = Invoke-RMProjectSettings -OrganizationId $CloudAccount.organization_id $MTUSize = $ProjectSettingsResponse.azure.mtu_size $UserInput.Add("MTUSize", $MTUSize) Add-RMConvertFileSystem -Source $Source -UpdatedUserInput $UserInput -ConvertFileSystem $ConvertFileSystem if ([string]::IsNullOrEmpty($NetBIOSName)) { $NetBIOSName = $Source.hostname } $UserInput.Add("NetBIOSName", $NetBIOSName) $KMSKey = $null if ($KMSActivation) { $KMSKey = "kms.core.windows.net" if ($null -ne $ProjectSettingsResponse.azure.kms_fqdn) { $KMSKey = $ProjectSettingsResponse.azure.kms_fqdn } } $UserInput.Add("KMSKey", $KMSKey) Out-RMUserParameterResult -ErrorMessage $Errors -WarningMessage $Warnings if ($Errors.Count -gt 0 -or $ShouldExit) { Add-RMErrorAndWarning -RMReturnObject $RMMigrationReturn -ErrorMessage $Errors -WarningMessage $Warnings return $RMMigrationReturn } if ([string]::IsNullOrEmpty($ScheduledAt)) { $UserInput.Add("ScheduledAt", "") } else { $UserInput.Add("ScheduledAt", (Convert-RMDateTimeToUTC -InputDateTime $ScheduledAt)) } $Response = New-RMAzureMigrationProfile @UserInput $ShouldExit = Start-RMMigrationPreflight -MigrationProfileId $Response.id -IgnoreValidationErrors $IgnoreValidationError -RMMigrationReturn $RMMigrationReturn if ($ShouldExit) { return $RMMigrationReturn } $IsScheduled = ![string]::IsNullOrEmpty($ScheduledAt) $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" $Uri = Get-Variable -Name "RMContext-ReactorURI" $Headers = @{ Accept = "application/rm+json" "X-Auth-Token" = $RMLoginResult.Value.token } $Params = @{ Method = "Post" Uri = $Uri.Value + "/migrationprofiles/" + $Response.id + "/migrations" Headers = $Headers ContentType = "application/json" } $MigrationResponse = Invoke-RMRestMethod -Params $Params return Update-RMMigrationReturnAsSuccess -MigrationResponse $MigrationResponse ` -RMMigrationReturn $RMMigrationReturn -IsScheduledMigration $IsScheduled ` -ReturnMessage "Migration started successfully, migration ID" } function Start-RMInteractiveAzureVMBasedMigration { param () $UserInput = @{} $CloudAccount = Read-RMCloudAccount -AccountType "azure" ` -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 "azure" $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 } } $ScheduledAt = Read-RMMigrationSchedule $CloudSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $TargetVMName = Read-RMString -UserMessage "Enter target VM Name" -DefaultValue $Source.host ` -ParameterName "Target VM Name" -IsRequired $false #Placement Settings $ResourceGroupRegion = "" $ReadValue = Read-RMBoolean -UserMessage "Create a new resource group" -DefaultValue "false" if ($ReadValue) { $ResourceGroup = Read-RMString -UserMessage "Enter the name of the resource group to be created" ` -ParameterName "Resource group name" -IsRequired $true $ResourceGroupRegion = Read-RMResourceGroupRegion -CloudAttributeSummary $CloudSummary } else { $ExistingOptions = $CloudAttributes.properties.subscriptions.resource_groups.name $ResourceGroup = $CloudAccount.appliance.cloud_properties.resource_group $ResourceGroup = Read-RMString -UserMessage "Enter existing resource group name" -DefaultValue $ResourceGroup ` -ParameterName "Resource group name" -IsRequired $false -Options $ExistingOptions } $VMSize = Read-VMSize -CloudAttributes $CloudAttributes $DiskTypeMappings = @() $ReturnedValue = Get-DiskTypeMappingBySource -Source $Source -VMSize $VMSize -IsInteractive $true -IsVM $true if ($ReturnedValue -is [hashtable]) { # The method "Get-DiskTypeMappingBySource" returns an array of hashtables, but it # has been observed that if the source contains a single disk, the returned value # is of type HashTable; hence we are checking the type and re-adding it to an array $DiskTypeMappings += $ReturnedValue } else { $DiskTypeMappings = $ReturnedValue } 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 } $VirtualNetwork = $CloudAccount.appliance.cloud_properties.virtual_network.name $VirtualNetwork = Read-RMString -UserMessage "Enter virtual network name" -DefaultValue $VirtualNetwork ` -Options $CloudAttributes.properties.subscriptions.regions.networks.name ` -ParameterName "Virtual Network Name" -IsRequired $false $DestinationNetworkOptions = Get-RMDestinationNetworkName -CloudAttributes $CloudAttributes -VirtualNetworkName $VirtualNetwork $DestinationNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name if ($VirtualNetwork -ieq $CloudAccount.appliance.cloud_properties.virtual_network.name) { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" -DefaultValue $DestinationNetworkName ` -ParameterName "Destination network name" -IsRequired $false -Options $DestinationNetworkOptions.name } else { $DestinationNetworkName = Read-RMString -UserMessage "Enter destination network name" -ParameterName "Destination network name" ` -IsRequired $true -Options $DestinationNetworkOptions.name } $AssignPublicIP = Read-RMBoolean -UserMessage "Auto assign public IP" -DefaultValue $false $StaticPrivateIP = Read-RMIPAddress -UserMessage "Enter static private IP to be assigned to target" -DefaultValue "None" ` -ParameterName "Static private IP" -IsRequired $false if ("" -ieq $VMSize.availability_zones) { $ReadValue = Read-RMString -UserMessage "Enter availability option" -Options "None", "AvailabilitySet" ` -DefaultValue "None" -ParameterName "Availability option" -IsRequired $false } else { $ReadValue = Read-RMString -UserMessage "Enter availability option" -Options "None", "AvailabilityZone", "AvailabilitySet" ` -DefaultValue "None" -ParameterName "Availability option" -IsRequired $false } if ("" -ne $ReadValue -and "none" -ine $ReadValue) { if ("AvailabilityZone" -ieq $ReadValue) { $AvailabilityZone = Read-RMString -UserMessage "Enter the availability zone" -Options $VMSize.availability_zones ` -ParameterName "Availability zone" -IsRequired $true } else { $ReadValue = Read-RMBoolean -UserMessage "Create a new availability set" -DefaultValue "false" if ($ReadValue) { $AvailabilitySet = Read-RMString -UserMessage "Enter the name of the availability set to be created" ` -ParameterName "Availability set name" -IsRequired $true $FaultDomainCount = Read-RMInt -UserMessage "Enter fault domains" -OptionsRange 1, 3 ` -DefaultValue "2" -ParameterName "Fault domains" -IsRequired $false $UpdateDomainCount = Read-RMInt -UserMessage "Enter update domains" -OptionsRange 1, 20 ` -DefaultValue "5" -ParameterName "Update domains" -IsRequired $false } else { $AvailabilitySets = Get-RMAvailabilitySet -CloudAttributes $CloudAttributes -ResourceGroup $ResourceGroup if ($AvailabilitySets.Count -lt 1) { Write-RMError -Message "No existing availability sets in current resource group and location" } else { $AvailabilitySet = Read-RMString -UserMessage "Enter the existing availability set name" -Options $AvailabilitySets ` -ParameterName "Availability set name" -IsRequired $true } } } } $StorageAccount = $null $EnableBootDiagnostics = Read-RMBoolean -UserMessage "Enable boot diagnostics" -DefaultValue "false" if ($EnableBootDiagnostics) { $StorageAccount = Read-RMString -UserMessage "Enter azure storage account name for boot diagnostics" ` -Options $CloudAttributes.properties.subscriptions.regions.storage_accounts.name -IsRequired $true ` -ParameterName "Storage account name" } $ReadValue = Read-RMPair -UserMessage "Enter one or more instance tags in the format 'key=value', separated by commas" ` -Separator "=" -DefaultValue "None" $InstanceTag = Get-RMStringAsHashtable -InputString $ReadValue #Optimization Settings #Add Migration Extension part $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" $SecurityGroup = $null if (!$EnforceTargetNetworkIsolation) { $SecurityGroup = Read-RMSecurityGroup -CloudAttribute $CloudAttributes } $EncryptionSet = $null $ReadValue = Read-RMString -UserMessage "Enter disk encryption type" -Options "platform-managed", "customer-managed" ` -DefaultValue "platform-managed" -ParameterName "Disk encryption type" -IsRequired $false if ("customer-managed" -ieq $ReadValue) { $EncryptionSet = Read-RMString -UserMessage "Enter encryption set name" -ParameterName "Encryption set name" -IsRequired $true ` -Options $CloudAttributes.properties.subscriptions.regions.disk_encryption_sets.name } $EnableHybridUseBenefit = $false if("windows" -ieq $Source.os_type) { $EnableHybridUseBenefit = Read-RMBoolean -UserMessage "Enable Azure hybrid use benefit" -DefaultValue "false" } #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 $HashArguments = @{ CloudAccount = $CloudAccount CloudAttribute = $CloudAttributes Entitlement = $Entitlement Source = $Source ScheduledAt = $ScheduledAt TargetVMName = $TargetVMName TransferMethod = $TransferMethod ResourceGroup = $ResourceGroup ResourceGroupRegion = $ResourceGroupRegion VMSize = $VMSize DiskTypeMapping = $DiskTypeMappings VolumeType = $VolumeType SelectedDisk = $SelectedDisk VirtualNetwork = $VirtualNetwork DestinationNetworkName = $DestinationNetworkName AssignPublicIP = $AssignPublicIP StaticPrivateIP = $StaticPrivateIP SecurityGroup = $SecurityGroup InstanceTag = $InstanceTag AvailabilityZone = $AvailabilityZone AvailabilitySet = $AvailabilitySet FaultDomainCount = $FaultDomainCount UpdateDomainCount = $UpdateDomainCount EnableBootDiagnostics = $EnableBootDiagnostics StorageAccount = $StorageAccount EncryptionSet = $EncryptionSet EnableHybridUseBenefit = $EnableHybridUseBenefit ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget FinalizeMigration = $FinalizeMigration MigrationInstruction = $MigrationInstruction IgnoreValidationError = $IgnoreValidationError } $HashArguments += $UserInput $Response = New-RMAzureVMBasedMigrationProfile @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-RMNonInteractiveAzureVMBasedMigration { param ( [string] $SourceVMName, [string] $SourceVMFolderPath, [string] $TargetCloud, [string] $ScheduledAt, [string] $TargetVMName, [bool] $CreateResourceGroup, [string] $ResourceGroup, [string] $ResourceGroupRegion, [string] $VMSizeName, [string[]] $VolumeType, [string[]] $SelectedDiskLabel, [string] $VirtualNetwork, [string] $DestinationNetworkName, [bool] $AssignPublicIP, [string] $StaticPrivateIP, [bool] $EnforceTargetNetworkIsolation, [string] $SecurityGroup, [string[]] $InstanceTag, [string] $AvailabilityOption, [int] $AvailabilityZone, [bool] $CreateAvailabilitySet, [string] $AvailabilitySet, [int] $FaultDomain, [int] $UpdateDomain, [bool] $EnableBootDiagnostics, [string] $StorageAccount, [string] $DiskEncryptionType, [string] $EncryptionSet, [bool] $EnableHybridUseBenefit, [string] $MigrationExtension, [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 = Confirm-RMAzureVMBasedFullMigrationParameter $PSBoundParameters try { if (![string]::IsNullOrWhiteSpace($TargetCloud)) { $CloudAccount, $ErrorString = Get-RMCloudAccountByName -CloudAccountName $TargetCloud -AccountType "azure" -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 "azure" 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-RMAzureVMBasedFullMigrationParameterWithSource -UserParameter $PSBoundParameters -Source $Source ` -MigrationExtension $MigrationExtensionArray if ($SourceErrors.Count -gt 0) { $Errors += $SourceErrors } $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount $VMSize = Get-VMSizeByName -VMSizeName $VMSizeName -CloudAttributes $CloudAttributes $ErrorsCloudAttributes = Confirm-RMCloudAttributes -UserParameter $PSBoundParameters -CloudAccount $CloudAccount ` -VMSize $VMSize -CloudAttribute $CloudAttributes -CloudAttributesSummary $CloudAttributesSummary $Errors += $ErrorsCloudAttributes } 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 } if ([string]::IsNullOrWhiteSpace($ResourceGroup)) { $ResourceGroup = $CloudAccount.appliance.cloud_properties.resource_group } if ([string]::IsNullOrWhiteSpace($VirtualNetwork)) { $VirtualNetwork = $CloudAccount.appliance.cloud_properties.virtual_network.name } if ([string]::IsNullOrWhiteSpace($DestinationNetworkName)) { $DestinationNetworkName = $CloudAccount.appliance.cloud_properties.network.interfaces.eth0.network_name } if ([string]::IsNullOrWhiteSpace($EncryptionSet)) { $EncryptionSet = "platform-managed" } $AvailabilityZoneString = $null if ($AvailabilityZone -gt 0) { $AvailabilityZoneString = $AvailabilityZone.ToString() } $FaultDomainCount = $null if ($FaultDomain -gt 0) { $FaultDomainCount = $FaultDomain } $UpdateDomainCount = $null if ($UpdateDomain -gt 0) { $UpdateDomainCount = $UpdateDomain } $SelectedDisk = Get-RMSelectedDiskByDiskLabel -DiskLabel $SelectedDiskLabel -Source $Source $InstanceTagsAsHashTable = $null try { $InstanceTagsAsHashTable = Get-RMStringArrayAsHashtable -InputItems $InstanceTag -ParameterName "InstanceTag" } catch { $Errors += $PSItem.Exception.Message } $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 } 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 CloudAttribute = $CloudAttributes Entitlement = $Entitlement Source = $Source ScheduledAt = $ScheduledAt TargetVMName = $TargetVMName ResourceGroup = $ResourceGroup ResourceGroupRegion = $ResourceGroupRegion VMSize = $VMSize VolumeType = $VolumeType SelectedDisk = $SelectedDisk VirtualNetwork = $VirtualNetwork DestinationNetworkName = $DestinationNetworkName AssignPublicIP = $AssignPublicIP StaticPrivateIP = $StaticPrivateIP SecurityGroup = $SecurityGroup InstanceTag = $InstanceTagsAsHashTable AvailabilityZone = $AvailabilityZoneString AvailabilitySet = $AvailabilitySet FaultDomainCount = $FaultDomainCount UpdateDomainCount = $UpdateDomainCount EnableBootDiagnostic = $EnableBootDiagnostics StorageAccount = $StorageAccount EncryptionSet = $EncryptionSet EnableHybridUseBenefit = $EnableHybridUseBenefit ShutdownSource = $ShutdownSource ShutdownTarget = $ShutdownTarget FinalizeMigration = $FinalizeMigration MigrationInstruction = $MigrationInstructionAsHashTable IgnoreValidationError = $IgnoreValidationError } $HashArguments += $UserInput $Response = New-RMAzureVMBasedMigrationProfile @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 Get-RMAvailabilitySet { param( [System.Object] $CloudAttributes, [string] $ResourceGroup ) if ($null -eq $CloudAttributes -or 0 -eq $CloudAttributes.properties.subscriptions.Count -or 0 -eq $CloudAttributes.properties.subscriptions[0].regions) { throw "Internal error, cloud attributes doesn't exist" } $AvailabilitySets = @() foreach ($AvailabilitySet in $CloudAttributes.properties.subscriptions[0].regions[0].availability_sets) { if ($AvailabilitySet.resource_group -eq $ResourceGroup) { $AvailabilitySets += $AvailabilitySet.name } } return $AvailabilitySets } function Confirm-RMVolumeType { param ( [System.Object] $Source, [string[]] $VolumeType ) $VolumeTypeCnt = $VolumeType.Count $DisksCnt = $Source.attributes.storage.disks.psobject.Properties.Value.device.Count if ( $VolumeTypeCnt -ne $DisksCnt) { $ErrorString += "The source has '$DisksCnt' disks and the number of volume types given by the parameter 'VolumeType' are '$VolumeTypeCnt'. The number of volume types given should be equal to the number of disks on the source." } return $ErrorString } function Confirm-RMAzureFullMigrationParameter { param( [hashtable] $UserParameter ) $Errors, $Warnings, $IsSourceAndTargetCloudPresent = Confirm-RMCommonParameter -UserParameter $UserParameter $AzureErrors = Confirm-RMAzureParameter -UserParameter $UserParameter $Errors += $AzureErrors return $Errors, $Warnings, $IsSourceAndTargetCloudPresent } function Confirm-RMAzureVMBasedFullMigrationParameter { param ( [hashtable] $UserParameter ) $Errors = @() $Errors, $Warnings, $IsSourcePresent = Confirm-RMVMBasedCommonParameter -UserParameter $UserParameter $AzureErrors = Confirm-RMAzureParameter -UserParameter $UserParameter $Errors += $AzureErrors return $Errors, $Warnings, $IsSourcePresent } function Confirm-RMAzureParameter { param ( [hashtable] $UserParameter ) $Errors = @() if ($UserParameter.ContainsKey("CreateResourceGroup") -and $UserParameter["CreateResourceGroup"]) { if (!$UserParameter.ContainsKey("ResourceGroupRegion") -or [string]::IsNullOrEmpty($UserParameter["ResourceGroupRegion"])) { $Errors += "ResourceGroupRegion is required, when parameter 'CreateResourceGroup' is true." } } if (!$UserParameter.ContainsKey("VMSizeName") -or [string]::IsNullOrEmpty($UserParameter["VMSizeName"])) { $Errors += "VMSizeName is required." } if (!$UserParameter.ContainsKey("VolumeType") -or [string]::IsNullOrWhiteSpace($UserParameter["VolumeType"])) { $Errors += "VolumeType is required." } if($UserParameter.ContainsKey("EnforceTargetNetworkIsolation") -and !$UserParameter["EnforceTargetNetworkIsolation"]) { if (!$UserParameter.ContainsKey("SecurityGroup") -or [string]::IsNullOrEmpty($UserParameter["SecurityGroup"])) { $Errors += "SecurityGroup is required, when parameter 'EnforceTargetNetworkIsolation' is false." } } if ($UserParameter.ContainsKey("StaticPrivateIP") -and ![string]::IsNullOrEmpty($UserParameter["StaticPrivateIP"])) { $IsValidStaticPrivateIP = Confirm-RMIPAddress -IPAddress $UserParameter.StaticPrivateIP if (!$IsValidStaticPrivateIP) { $Errors += "Invalid Static Private IP" } } if ($UserParameter.ContainsKey("AvailabilityOption")) { if ($UserParameter.AvailabilityOption -ieq "AvailabilitySet") { if (!$UserParameter.ContainsKey("AvailabilitySet") -or [string]::IsNullOrEmpty($UserParameter["AvailabilitySet"])) { $Errors += "AvailabilitySet is required." } if ($UserParameter.ContainsKey("CreateAvailabilitySet") -and $UserParameter["CreateAvailabilitySet"] -eq $true) { if (!$UserParameter.ContainsKey("FaultDomain")) { $Errors += "FaultDomain is required, when parameter 'CreateAvailabilitySet' is true." } else { $FaultDomain = $UserParameter["FaultDomain"] if (-not($FaultDomain -ge 1 -and $FaultDomain -le 3)) { $Errors += "FaultDomain should be in the range 1 and 3." } } if (!$UserParameter.ContainsKey("UpdateDomain")) { $Errors += "UpdateDomain is required, when parameter 'CreateAvailabilitySet' is true." } else { $UpdateDomain = $UserParameter["UpdateDomain"] if (-not($UpdateDomain -ge 1 -and $UpdateDomain -le 20)) { $Errors += "UpdateDomain should be in the range 1 and 20." } } } } elseif ($UserParameter.AvailabilityOption -ieq "AvailabilityZone") { if (!$UserParameter.ContainsKey("AvailabilityZone")) { $Errors += "AvailabilityZone is required." } else { $AvailabilityZone = $UserParameter["AvailabilityZone"] if (-not($AvailabilityZone -ge 1 -and $AvailabilityZone -le 3)) { $Errors += "AvailabilityZone should be in the range 1 and 3." } } } } if($UserParameter.ContainsKey("EnableBootDiagnostics") -and $UserParameter["EnableBootDiagnostics"]) { if (!$UserParameter.ContainsKey("StorageAccount") -or [string]::IsNullOrEmpty($UserParameter["StorageAccount"])) { $Errors += "StorageAccount is required, when parameter 'EnableBootDiagnostics' is true." } } if ($UserParameter.ContainsKey("DiskEncryptionType") -and $UserParameter["DiskEncryptionType"] -ieq "customer-managed") { if (!$UserParameter.ContainsKey("EncryptionSet") -or [string]::IsNullOrEmpty($UserParameter["EncryptionSet"])) { $Errors += "EncryptionSet is required when parameter 'DiskEncryptionType' is 'customer-managed'" } } return $Errors } function Confirm-RMAzureFullMigrationParameterWithSource { 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 if (![string]::IsNullOrEmpty($UserParameter["VolumeType"])) { $ErrorString = Confirm-RMVolumeType -Source $Source -VolumeType $UserParameter["VolumeType"] if (![string]::IsNullOrEmpty($ErrorString)) { $Errors += $ErrorString } } return $Errors } function Confirm-RMAzureVMBasedFullMigrationParameterWithSource { param ( [hashtable] $UserParameter, [System.Object] $Source, [System.Array] $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("VolumeType") -and ![string]::IsNullOrWhiteSpace($UserParameter["VolumeType"])) { $ErrorString = Confirm-RMVMBasedVolumeType -SelectedDiskCount $UserParameter["SelectedDiskLabel"] -VolumeType $UserParameter["VolumeType"] if (![string]::IsNullOrEmpty($ErrorString)) { $Errors += $ErrorString } } return $Errors } function Confirm-RMCloudAttributes { param ( [hashtable] $UserParameter, [System.Object] $CloudAccount, [System.Object] $VMSize, [System.Object] $CloudAttribute, [System.Object] $CloudAttributesSummary ) $Errors = @() if ($UserParameter.ContainsKey("CreateResourceGroup") -and $UserParameter["CreateResourceGroup"] -and ` $UserParameter.ContainsKey("ResourceGroupRegion") -and ![string]::IsNullOrWhiteSpace($UserParameter["ResourceGroupRegion"])) { $ResourceGroupRegionIsValid = Confirm-RMResourceGroupRegion -CloudAttributesSummary $CloudAttributesSummary ` -ResourceGroupRegionName $UserParameter["ResourceGroupRegion"] if (!$ResourceGroupRegionIsValid) { $Errors += "Invalid ResourceGroupRegion" } } if ($UserParameter.ContainsKey("ResourceGroup") -and ![string]::IsNullOrWhiteSpace($UserParameter["ResourceGroup"])) { $ResourceGroupIsValid = Confirm-RMResourceGroup -CloudAttribute $CloudAttribute -ResourceGroup $UserParameter["ResourceGroup"] if (!$ResourceGroupIsValid) { $Errors += "Invalid ResourceGroup" } } if ($UserParameter.ContainsKey("VMSizeName") -and ![string]::IsNullOrWhiteSpace($UserParameter["VMSizeName"])) { $VMSizeIsValid = Confirm-RMVMSize -CloudAttribute $CloudAttribute -VMSize $UserParameter["VMSizeName"] if (!$VMSizeIsValid) { $Errors += "Invalid VMSizeName" } } $DefaultVirtualNetwork = $CloudAccount.appliance.cloud_properties.virtual_network.name if ($UserParameter.ContainsKey("VirtualNetwork") -and ![string]::IsNullOrWhiteSpace($UserParameter["VirtualNetwork"])) { if ($DefaultVirtualNetwork -ieq $UserParameter["VirtualNetwork"]) { if ($UserParameter.ContainsKey("DestinationNetworkName") -and ` ![string]::IsNullOrWhiteSpace($UserParameter["DestinationNetworkName"])) { $DestinationNetworkNameIsValid = Confirm-RMDestinationNetworkName -CloudAttribute $CloudAttribute ` -VirtualNetwork $UserParameter["VirtualNetwork"] -DestinationNetworkName $UserParameter["DestinationNetworkName"] if (!$DestinationNetworkNameIsValid) { $Errors += "Invalid DestinationNetworkName" } } } else { $VirtualNetworkIsValid = Confirm-RMVirtualNetwork -CloudAttribute $CloudAttribute -VirtualNetwork $UserParameter["VirtualNetwork"] if (!$VirtualNetworkIsValid) { $Errors += "Invalid VirtualNetwork" } else { if ($UserParameter.ContainsKey("DestinationNetworkName") -and ` ![string]::IsNullOrWhiteSpace($UserParameter["DestinationNetworkName"])) { $DestinationNetworkNameIsValid = Confirm-RMDestinationNetworkName -CloudAttribute $CloudAttribute ` -VirtualNetwork $UserParameter["VirtualNetwork"] -DestinationNetworkName $UserParameter["DestinationNetworkName"] if (!$DestinationNetworkNameIsValid) { $Errors += "Invalid DestinationNetworkName" } } else { $Errors += "DestinationNetworkName is required" } } } } if ($UserParameter.ContainsKey("SecurityGroup") -and ![string]::IsNullOrWhiteSpace($UserParameter["SecurityGroup"])) { $SecurityGroupIsValid = Confirm-RMSecurityGroup -CloudAttribute $CloudAttribute -SecurityGroup $UserParameter["SecurityGroup"] if (!$SecurityGroupIsValid) { $Errors += "Invalid SecurityGroup" } } if ($UserParameter.ContainsKey("AvailabilityOption") -and ![string]::IsNullOrWhiteSpace($UserParameter["AvailabilityOption"])) { if ("AvailabilityZone" -ieq $UserParameter["AvailabilityOption"] -and ` "" -ieq $VMSize.availability_zones) { $Errors += "AvailabilityZone is not available in the current resource group and location" } if ("AvailabilitySet" -ieq $UserParameter["AvailabilityOption"] -and $ResourceGroupIsValid -and ` (!$UserParameter.ContainsKey("CreateAvailabilitySet") -or !$UserParameter["CreateAvailabilitySet"]) -and ` $UserParameter.ContainsKey("AvailabilitySet") -and ![string]::IsNullOrWhiteSpace($UserParameter["AvailabilitySet"])) { $AvailabilitySets = Get-RMAvailabilitySet -CloudAttributes $CloudAttribute -ResourceGroup $UserParameter["ResourceGroup"] if ($AvailabilitySets.Count -lt 1) { $Errors += "No existing 'AvailabilitySet' in current resource group and location" } else { $AvailabilitySetIsValid = Confirm-RMAvailabilitySet -AvailabilitySet $AvailabilitySets -AvailabilitySetName if (!$AvailabilitySetIsValid) { $Errors += "Invalid AvailabilitySet" } } } } if ($UserParameter.ContainsKey("StorageAccount") -and ![string]::IsNullOrWhiteSpace($UserParameter["StorageAccount"])) { $StorageAccountIsValid = Confirm-RMStorageAccount -CloudAttribute $CloudAttribute -StorageAccount $UserParameter["StorageAccount"] if (!$StorageAccountIsValid) { $Errors += "Invalid StorageAccount" } } if ($UserParameter.ContainsKey("EncryptionSet") -and ![string]::IsNullOrWhiteSpace($UserParameter["EncryptionSet"])) { $EncryptionSetIsValid = Confirm-RMEncryptionSet -CloudAttribute $CloudAttribute -EncryptionSet $UserParameter["EncryptionSet"] if (!$EncryptionSetIsValid) { $Errors += "Invalid EncryptionSet" } } return $Errors } function Confirm-RMResourceGroupRegion { param ( [System.Object] $CloudAttributesSummary, [string] $ResourceGroupRegion ) $ResourceGroupRegionIsValid = $true if ($CloudAttributeSummary.properties.subscriptions.regions.label -notcontains $ResourceGroupRegion) { $ResourceGroupRegionIsValid = $false } return $ResourceGroupRegionIsValid } function Confirm-RMResourceGroup { param ( [System.Object] $CloudAttribute, [string] $ResourceGroup ) $ResourceGroupRegionIsValid = $true if ($CloudAttribute.properties.subscriptions.resource_groups.name -notcontains $ResourceGroup) { $ResourceGroupRegionIsValid = $false } return $ResourceGroupRegionIsValid } function Confirm-RMAvailabilitySet { param ( [string[]] $AvailabilitySet, [string] $AvailabilitySetName ) $AvailabilitySetIsValid = $true if ($AvailabilitySet -notcontains $AvailabilitySetName) { $AvailabilitySetIsValid = $false } return $AvailabilitySetIsValid } function Confirm-RMVMSize { param ( [System.Object] $CloudAttribute, [string] $VMSize ) $VMSizeIsValid = $true if ($CloudAttributes.properties.subscriptions.regions.vm_sizes.name -notcontains $VMSize) { $VMSizeIsValid = $false } return $VMSizeIsValid } function Confirm-RMVirtualNetwork { param ( [System.Object] $CloudAttribute, [string] $VirtualNetwork ) $VirtualNetworkIsValid = $true if ($CloudAttribute.properties.subscriptions.regions.networks.name -notcontains $VirtualNetwork) { $VirtualNetworkIsValid = $false } return $VirtualNetworkIsValid } function Confirm-RMDestinationNetworkName { param ( [System.Object] $CloudAttribute, [string] $VirtualNetwork, [string] $DestinationNetworkName ) $DestinationNetworkNameIsValid = $true $DestinationNetworkArray = Get-RMDestinationNetworkName -CloudAttributes $CloudAttribute ` -VirtualNetworkName $VirtualNetwork if ($DestinationNetworkArray.name -notcontains $DestinationNetworkName) { $DestinationNetworkNameIsValid = $false } return $DestinationNetworkNameIsValid } function Confirm-RMSecurityGroup { param( [System.Object] $CloudAttribute, [string] $SecurityGroup ) $SecurityGroupIsValid = $true if ($CloudAttribute.properties.subscriptions.regions.security_groups.name -notcontains $SecurityGroup) { $SecurityGroupIsValid = $false } return $SecurityGroupIsValid } function Confirm-RMStorageAccount { param( [System.Object] $CloudAttribute, [string] $StorageAccount ) $StorageAccountIsValid = $true if ($CloudAttributes.properties.subscriptions.regions.storage_accounts.name -notcontains $StorageAccount) { $StorageAccountIsValid = $false } return $StorageAccountIsValid } function Confirm-RMEncryptionSet { param ( [System.Object] $CloudAttribute, [string] $EncryptionSet ) $EncryptionSetIsValid = $true if ($CloudAttributes.properties.subscriptions.regions.disk_encryption_sets.name -notcontains $EncryptionSet) { $EncryptionSetIsValid = $false } return $EncryptionSetIsValid } function Confirm-RMVMBasedVolumeType { param ( [string[]] $SelectedDiskCount, [string[]] $VolumeType ) $VolumeTypeCnt = $VolumeType.Count $DisksCnt = $SelectedDiskCount.Count if ($VolumeTypeCnt -ne $DisksCnt) { $ErrorString += "The source has '$DisksCnt' disks and the number of volume types given by the parameter 'VolumeType' are '$VolumeTypeCnt'. The number of volume types given should be equal to the number of disks on the source." } return $ErrorString } function Read-VMSize { param( [System.Object] $CloudAttributes ) while ($true) { $VMSizeName = Read-RMString -UserMessage "Enter VM Size name, e.g. Standard_A7" -ParameterName "VM Size" ` -IsRequired $true $VMSize = Get-VMSizeByName -VMSizeName $VMSizeName -CloudAttributes $CloudAttributes if ($null -eq $VMSize) { Write-RMError -Message "VM size '$VMSizeName' does not exist" continue } return $VMSize } } function Get-RMDestinationNetworkName { param ( [System.Object] $CloudAttributes, [string] $VirtualNetworkName ) foreach ($VirtualNetwork in $CloudAttributes.properties.subscriptions.regions.networks) { if ($VirtualNetworkName -ieq $VirtualNetwork.name) { return $VirtualNetwork.subnets } } return $null } Export-ModuleMember -Function Start-RMAzureOSBasedInteractiveMigration, Start-RMAzureOSBasedNonInteractiveMigration, ` Start-RMInteractiveAzureVMBasedMigration, Start-RMNonInteractiveAzureVMBasedMigration |