MigrationProfile/AzureMigrationProfile.psm1
Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath Util | Join-Path -ChildPath Util) Import-Module -Name @(Join-Path $PSScriptRoot .. | Join-Path -ChildPath CloudAccount | Join-Path -ChildPath CloudAccount) function New-RMAzureMigrationProfile { param( [Parameter(Mandatory)] [System.Object] $CloudAccount, [Parameter(Mandatory)] [System.Object] $CloudAttributes, [Parameter(Mandatory)] [System.Object] $Entitlement, [Parameter(Mandatory)] [System.Object] $Source, [Parameter(Mandatory)] [System.Object] $ScheduledAt, [Parameter(Mandatory)] [string] $TargetVMName, [Parameter(Mandatory)] [string] $TransferMethod, [Parameter(Mandatory)] [string] $ResourceGroup, [string] $ResourceGroupRegion, [Parameter(Mandatory)] [System.Object] $VMSize, [System.Object] $DiskTypeMappings, [string[]] $VolumeType, [Parameter(Mandatory)] [System.Object[]] $MountPoints, [Parameter(Mandatory)] [hashtable] $ResizeMountPoints, [hashtable] $ConvertFileSystem, [string] $MigrationExtension, [string] $MigrationExtensionId, [string] $MigrationExtensionOSM, [string] $MigrationExtensionIdOSM, [Parameter(Mandatory)] [string] $VirtualNetwork, [Parameter(Mandatory)] [string] $DestinationNetworkName, [Parameter(Mandatory)] [bool] $AssignPublicIP, [string] $StaticPrivateIP, [string] $SecurityGroup, [Parameter(Mandatory)] [bool] $DisableTargetDNSRegistration, [hashtable] $InstanceTags, [string] $AvailabilityZone, [string] $AvailabilitySet, [System.Object] $FaultDomainCount, [System.Object] $UpdateDomainCount, [Parameter(Mandatory)] [bool] $EnableBootDiagnostics, [string] $StorageAccount, [string] $EncryptionSet, [Parameter(Mandatory)] [bool] $EnableHybridUseBenefit, [Parameter(Mandatory)] [bool] $InPlaceUpgrade, [System.Object] $UpgradeOSVersion, [System.Object] $SQLServerUpgrade, [Parameter(Mandatory)] [bool] $ShutdownSource, [Parameter(Mandatory)] [bool] $ShutdownTarget, [Parameter(Mandatory)] [bool] $RemoveRMSAgentFromSource, [Parameter(Mandatory)] [bool] $RemoveRMSAgentFromTarget, [hashtable] $MigrationInstructions, [bool] $IgnoreValidationErrors, [string] $MTUSize, [string] $NetBIOSName, [system.Object] $KMSKey, [bool] $GeneralizeSystem, [hashtable] $OSHardening ) if ("" -ne $ResourceGroupRegion) { $ReturnedValue = Get-ResourceGroupRegionByUserInput -ResourceGroupRegion $ResourceGroupRegion -CloudAccount $CloudAccount if ($null -eq $ReturnedValue) { throw "Region '$ResourceGroupRegion' does not exist." } else { $ResourceGroupRegion = $ReturnedValue } } if ($null -ieq $ConvertFileSystem) { $ConvertFileSystem = @{} } $license_type = $null if ($EnableHybridUseBenefit) { $license_type = "Windows_Server" } $EncryptionSetId = $null if ("" -ne $EncryptionSet) { $EncryptionSetId = Get-DiskEncryptionSetIdByName -EncryptionSetName $EncryptionSet -CachedCloudAttributes $CloudAttributes } $MigrationExtensionIdArray = @() if (![string]::IsNullOrEmpty($MigrationExtensionId)) { $MigrationExtensionIdArray += $MigrationExtensionId } $MigrationExtensionArray = @() if (![string]::IsNullOrEmpty($MigrationExtension)) { $MigrationExtensionArray += $MigrationExtension } $MigrationExtensionIdOSMArray = @() if (![string]::IsNullOrEmpty($MigrationExtensionIdOSM)) { $MigrationExtensionIdOSMArray += $MigrationExtensionIdOSM } $MigrationExtensionOSMArray = @() if (![string]::IsNullOrEmpty($MigrationExtensionOSM)) { $MigrationExtensionOSMArray += $MigrationExtensionOSM } $MTUSizeObject = $null if (![string]::IsNullOrEmpty($MTUSize)) { $MTUSizeObject = $MTUSize } if ([string]::IsNullOrEmpty($VolumeType)) { # For the interactive case, take volume type of the first disk - this is what the UI is doing. $VolumeTypeString = $DiskTypeMappings[0]["type"] } else { $DiskTypeMappings = @() $ReturnedValue = Get-DiskTypeMappingBySource -Source $Source -VolumeType $VolumeType -IsInteractive $false 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 } $VolumeTypeString = $DiskTypeMappings[0]["type"] } $VirtualNetworkResourceGroup = $null $VirtualNetworkResourceGroup = Get-VirtualNetworkResourceGroup -CachedCloudAttributes $CloudAttributes -VirtualNetworkName $VirtualNetwork if ($null -eq $VirtualNetworkResourceGroup) { throw "Virtual network '$VirtualNetwork' does not exists, cannot start migration" } $SecurityGroupNode = $null if ("" -ne $SecurityGroup -and $null -ne $SecurityGroup) { $SecurityGroupNode = Get-SecurityGroup -SecurityGroupName $SecurityGroup -CachedCloudAttributes $CloudAttributes if ($null -eq $SecurityGroupNode) { throw "Security group '$SecurityGroup' does not exists, cannot start migration" } } if (!$VMSize.vmsizeSupported) { $Name = $VMSize.name throw "RiverMeadow does not support VM size '$Name', please use a different VM size and try again." } if ("" -ne $AvailabilityZone -and $VMSize.availability_zones -notcontains $AvailabilityZone) { $Name = $VMSize.name throw "The VM size '$Name' does not support the availability zone $AvailabilityZone" } $AvailabilitySetHash = @{} if ($null -eq $FaultDomainCount -or $null -eq $UpdateDomainCount) { $AvailabilitySetHash.Add("name", $AvailabilitySet) } else { $AvailabilitySetHash.Add("name", $AvailabilitySet) $AvailabilitySetHash.Add("fault_domain_count", $FaultDomainCount) $AvailabilitySetHash.Add("update_domain_count", $UpdateDomainCount) } if ([string]::IsNullOrEmpty($ScheduledAt)) { # To run "now", FE requires that the $ScheduledAt to be null $ScheduledAt = $null } $SQLServerUpgradeAsArray = @() if($null -ne $SQLServerUpgrade ) { $SQLServerUpgradeAsArray += $SQLServerUpgrade } $CurrentTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss" $MigrationProfile = @{ "name"= "powershell-" + $Source.host + "-" + $CurrentTime "tags"= @() "entitlement"=$Entitlement.id "cloud_account"=$CloudAccount.id "is_data_only"= $false "is_vdi"= $false "appliance_id"= $CloudAccount.appliance.id "schedule"= $ScheduledAt "schedule_delta"= 0 "transfer_mode"= "run-once" "sources"= @( @{ "source"= $Source.id "transfer_type"= $TransferMethod "target_config"= @{ "vm_details"= @{ "vm_name"= $TargetVMName "vapp_name"= $TargetVMName "tags"= $InstanceTags "resource_group"= $ResourceGroup "flavor"= @{ "flavor_type"= $VMSize.name "volume_type"= $VolumeTypeString } "kms_fqdn" = $KMSKey "enable_accelerated_networking"= $VMSize.enable_accelerated_networking "disk_type_mappings"= $DiskTypeMappings "license_type"= $license_type "availability_set"= $AvailabilitySetHash "availability_zone_id"= $AvailabilityZone "enable_boot_diagnostics"= $EnableBootDiagnostics "boot_diagnostics_storage_account"= $StorageAccount "disk_encryption_set_id"= $EncryptionSetId } "properties"= @{ "network"= @{ "interfaces"= @{ "eth0"= @{ "ip_type"= "dhcp" "mtu"= $MTUSizeObject "type"= "Ethernet" "network_name"= $DestinationNetworkName "vnet"= $VirtualNetwork "assign_public_ip"= $AssignPublicIP "ip_addr"= $StaticPrivateIP "resource_group"= $VirtualNetworkResourceGroup "security_group"= $SecurityGroupNode } } "automatic_dns_registration"= !$DisableTargetDNSRegistration } "hostname" = $NetBIOSName "selected_mounts"= $MountPoints "name"= $TargetVMName "mounts_new_size"= $ResizeMountPoints "convert_filesystems"= $ConvertFileSystem } "options"= @{ "region"= $CloudAttributes.properties.subscriptions[0].regions[0].name "resource_group_region"= $ResourceGroupRegion "subscription_id"= $CloudAttributes.properties.subscriptions[0].id "network"= @{ "name"= $VirtualNetwork "resource_group"= $VirtualNetworkResourceGroup } } } "os_type"= $Source.os_type "name"= $Source.hostname "os_hardening" = $OSHardening "harden_os" = if ($null -ieq $OSHardening) { $false } else { $true } "collection_type"= $null "generalize_system" = $GeneralizeSystem "drive_mapping" = @() "binary_asset_groups"= @( @{ "binary_assets" = $MigrationExtensionIdArray } @{ "binary_asset_names" = $MigrationExtensionArray } ) "binary_asset_groups_osm"= @( @{ "osm_assets" = $MigrationExtensionIdOSMArray } @{ "osm_asset_names" = $MigrationExtensionOSMArray } ) "product_upgrades" = $SQLServerUpgradeAsArray "shutdown_source"= $ShutdownSource "shutdown_target"= $ShutdownTarget "remove_source_agent" = $RemoveRMSAgentFromSource "remove_target_agent"= $RemoveRMSAgentFromTarget "in_place_upgrade"= $InPlaceUpgrade "upgrade_os_version"= $UpgradeOSVersion "migration_instructions"= $MigrationInstructions "data_transfer_port"= $null "ignore_validation_errors"= $IgnoreValidationErrors "preflight_warning"= $false } ) } # Giving max depth otherwise the cmdlet 'ConvertTo-Json' will truncate the JSON $MigrationProfileJson = $MigrationProfile |ConvertTo-Json -Depth 100 $RMLoginResult = Get-Variable -Name "RMContext-UserLogin" -ValueOnly $Uri = Get-Variable -Name "RMContext-ReactorURI" -ValueOnly $Headers = @{ Accept = "application/json" "X-Auth-Token" = $RMLoginResult.token } $Params = @{ Method = "Post" Uri = $Uri + "/migrationprofiles" Body = $MigrationProfileJson ContentType = "application/json" Headers = $Headers } Invoke-RMRestMethod -Params $Params } function New-RMAzureVMBasedMigrationProfile { param ( [System.Object] $CloudAccount, [System.Object] $CloudAttribute, [System.Object] $Entitlement, [System.Object] $Source, [System.Object] $ScheduledAt, [string] $TargetVMName, [string] $ResourceGroup, [string] $ResourceGroupRegion, [System.Object] $VMSize, [System.Object] $DiskTypeMapping, [string[]] $VolumeType, [System.Object[]] $SelectedDisk, [string] $VirtualNetwork, [string] $DestinationNetworkName, [bool] $AssignPublicIP, [string] $StaticPrivateIP, [string] $SecurityGroup, [hashtable] $InstanceTag, [string] $AvailabilityZone, [string] $AvailabilitySet, [System.Object] $FaultDomainCount, [System.Object] $UpdateDomainCount, [bool] $EnableBootDiagnostic, [string] $StorageAccount, [string] $EncryptionSet, [bool] $EnableHybridUseBenefit, [string] $MigrationExtension, [string] $MigrationExtensionId, [bool] $ShutdownSource, [bool] $ShutdownTarget, [bool] $FinalizeMigration, [hashtable] $MigrationInstruction, [bool] $IgnoreValidationError ) $AvailabilitySetHash = @{} if ($null -eq $FaultDomainCount -and $null -eq $UpdateDomainCount) { $AvailabilitySetHash.Add("name", $AvailabilitySet) } else { $AvailabilitySetHash.Add("name", $AvailabilitySet) $AvailabilitySetHash.Add("fault_domain_count", $FaultDomainCount) $AvailabilitySetHash.Add("update_domain_count", $UpdateDomainCount) } $VirtualNetworkResourceGroup = Get-VirtualNetworkResourceGroup -CachedCloudAttributes $CloudAttribute -VirtualNetworkName $VirtualNetwork $EncryptionSetId = $null if ("" -ne $EncryptionSet) { $EncryptionSetId = Get-DiskEncryptionSetIdByName -EncryptionSetName $EncryptionSet -CachedCloudAttributes $CloudAttribute } if ([string]::IsNullOrEmpty($ScheduledAt)) { # To run "now", FE requires that the $ScheduledAt to be null $ScheduledAt = $null } if ([string]::IsNullOrEmpty($VolumeType)) { # For the interactive case, take volume type of the first disk - this is what the UI is doing. $VolumeTypeString = $DiskTypeMapping[0]["type"] } else { $DiskTypeMapping = @() $ReturnedValue = Get-DiskTypeMappingBySource -Source $Source -VolumeType $VolumeType -IsInteractive $false -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 $DiskTypeMapping += $ReturnedValue } else { $DiskTypeMapping = $ReturnedValue } $VolumeTypeString = $DiskTypeMapping[0]["type"] } $SecurityGroupNode = $null if (![string]::IsNullOrWhiteSpace($SecurityGroup)) { $SecurityGroupNode = Get-SecurityGroup -SecurityGroupName $SecurityGroup -CachedCloudAttributes $CloudAttribute } $LicenseType = $null if($EnableHybridUseBenefit) { $LicenseType = "Windows_Server" } $MigrationExtensionIdArray = @() if (![string]::IsNullOrEmpty($MigrationExtensionId)) { $MigrationExtensionIdArray += $MigrationExtensionId } $MigrationExtensionArray = @() if (![string]::IsNullOrEmpty($MigrationExtension)) { $MigrationExtensionArray += $MigrationExtension } $CurrentTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss" $MigrationProfile = @{ "name"= "powershell-" + $Source.host + "-" + $CurrentTime "tags"= @() "entitlement" = $Entitlement.id "cloud_account" = $CloudAccount.id "is_data_only" = $false "is_vdi" = $false "appliance_id" = $CloudAccount.appliance.id "schedule" = $ScheduledAt "transfer_mode"= "run-once" "sources"= @( @{ "source" = $Source.id "target_config"= @{ "vm_details"= @{ "vm_name" = $TargetVMName "vapp_name" = $TargetVMName "tags" = $InstanceTag "resource_group"= $ResourceGroup "flavor"= @{ "flavor_type" = $VMSize.name "volume_type" = $VolumeTypeString } "enable_accelerated_networking" = $VMSize.enable_accelerated_networking "disk_type_mappings" = $DiskTypeMapping "availability_set" = $AvailabilitySetHash "availability_zone_id" = $AvailabilityZone "enable_boot_diagnostics" = $EnableBootDiagnostic "boot_diagnostics_storage_account" = if ([string]::IsNullOrWhiteSpace($StorageAccount)) {$null} else {$StorageAccount} "disk_encryption_set_id" = $EncryptionSetId "license_type" = $LicenseType } "properties" = @{ "network" = @{ "interfaces" = @{ "eth0" = @{ "ip_type" = "dhcp" "type" = "Ethernet" "network_name" = $DestinationNetworkName "vnet" = $VirtualNetwork "assign_public_ip" = $AssignPublicIP "ip_addr" = $StaticPrivateIP "resource_group" = $VirtualNetworkResourceGroup "security_group" = $SecurityGroupNode } } } "selected_mounts" = $SelectedDisk "name" = $TargetVMName "mounts_new_size" = @{} } "options" = @{ "region" = $CloudAttribute.properties.subscriptions[0].regions[0].name "resource_group_region" = $ResourceGroupRegion "subscription_id" = $CloudAttribute.properties.subscriptions[0].id "network" = @{ "name" = $VirtualNetwork "resource_group" = $VirtualNetworkResourceGroup } } } "os_type" = $Source.os_type "name" = $Source.host "collection_type" = "vm" "binary_asset_groups"= @( @{ "binary_assets" = $MigrationExtensionIdArray } @{ "binary_asset_names" = $MigrationExtensionArray } ) "shutdown_source" = $ShutdownSource "shutdown_target" = $ShutdownTarget "finalize_target" = $FinalizeMigration "in_place_upgrade" = $false "upgrade_os_version"= $null "migration_instructions" = $MigrationInstruction "ignore_validation_errors" = $IgnoreValidationError "preflight_warning" = $false } ) } return Invoke-RMMigrationProfilePost -MigrationProfile $MigrationProfile } function Get-VolumeType { param( [string] $VolumeType ) $VolumeTypes = @{ "Standard_SSD" = "StandardSSD_LRS" "Standard_HDD" = "Standard_LRS" "Premium_SSD" = "Premium_LRS" } return $VolumeTypes[$VolumeType] } function Get-DiskEncryptionSetIdByName { param( [string] $EncryptionSetName, [System.Object] $CachedCloudAttributes ) $DiskEncryptionSets = $CachedCloudAttributes.properties.subscriptions[0].regions[0].disk_encryption_sets foreach ($DiskEncryptionSet in $DiskEncryptionSets) { if ($DiskEncryptionSet.name -ieq $EncryptionSetName) { return $DiskEncryptionSet.id } } return $null } function Get-DiskTypeMappingBySource { param( [System.Object] $Source, [System.Object] $VMSize, [string[]] $VolumeType, [bool] $IsInteractive, [bool] $IsVM ) $DiskTypeMappings = @() if ($IsVM) { $SortedDisks = $Source.attributes.storage.vm_disks } else { $SortedDisks = $Source.attributes.storage.disks.psobject.Properties.Value | Sort-Object -Property device } $Index = 0 $DiskIndex = 0 foreach ($Disk in $SortedDisks) { if ($IsInteractive) { $Size = $Disk.size_kb/(1024*1024) $Size = [math]::round($Size, 2) $Type = "" if ($VMSize.premium_disk_support) { $Type = Read-RMString -UserMessage "Enter the volume type for disk with size $Size GiB" ` -Options "Standard_SSD", "Standard_HDD", "Premium_SSD" -ParameterName "Volume type" ` -DefaultValue "Standard_SSD" -IsRequired $false } else { $Type = Read-RMString -UserMessage "Enter the volume type for disk with size $Size GiB" ` -Options "Standard_SSD", "Standard_HDD" -ParameterName "Volume type" ` -DefaultValue "Standard_SSD" -IsRequired $false } $Type = Get-VolumeType -VolumeType $Type } else { if ($VolumeType.Count -gt 1) { $Type = Get-VolumeType -VolumeType $VolumeType[$Index] $Index++ } else { $Type = Get-VolumeType -VolumeType $VolumeType[0] } } if ($IsVM) { $DiskMapping = @{ "source_disk_identifier" = "$DiskIndex" "type" = $Type } $DiskIndex ++ } else { $DiskMapping = @{ "source_disk_identifier" = $Disk.device "type" = $Type } } $DiskTypeMappings += $DiskMapping } return $DiskTypeMappings } function Get-VirtualNetworkResourceGroup { param( [System.Object] $CachedCloudAttributes, [string] $VirtualNetworkName ) foreach($Network in $CachedCloudAttributes.properties.subscriptions[0].regions[0].networks) { if ($Network.name -ieq $VirtualNetworkName) { return $Network.resource_group } } return $null } function Get-SecurityGroup { param( [string] $SecurityGroupName, [System.Object] $CachedCloudAttributes ) if ("" -eq $SecurityGroup) { return $null } foreach($SecurityGroup in $CachedCloudAttributes.properties.subscriptions[0].regions[0].security_groups) { if ($SecurityGroup.name -eq $SecurityGroupName) { $Result = @{ "name" = $SecurityGroupName "resource_group" = $SecurityGroup.resource_group } return $Result } } return $null } function Get-VMSizeByName { param( [string] $VMSizeName, [System.Object] $CloudAttributes ) foreach($VMSize in $CloudAttributes.properties.subscriptions[0].regions[0].vm_sizes) { if ($VMSize.name -ieq $VMSizeName) { return $VMSize } } return $null } function Get-ResourceGroupRegionByUserInput { param( [string] $ResourceGroupRegion, [System.Object] $CloudAccount ) $CloudAttributesSummary = Get-CloudAttributesSummary -CloudAccount $CloudAccount foreach ($Subscription in $CloudAttributesSummary.properties.subscriptions) { if (-not($Subscription.id -eq $CloudAccount.appliance.cloud_properties.subscription_id)) { continue } foreach ($Region in $Subscription.regions) { if ($Region.name -eq $ResourceGroupRegion -or $Region.label -eq $ResourceGroupRegion) { return $Region.name } } } return $null } Export-ModuleMember -Function New-RMAzureMigrationProfile, New-RMAzureVMBasedMigrationProfile, Get-VMSizeByName, Get-DiskTypeMappingBySource |