Last month I spend some time on migrating an Azure PAYG subscription to an Azure CSP subscription. It seems like moving around some resources between resource groups is not that complex but I ran into some issues during the move which made me write down this post.
Before we start with the actual migration you should first draft a plan based on the different type of resources in you Azure subscription. I have used the following approach:
Scan
In this step we collect all the information of the current subscription. You can use the following tools and steps to get the information:
- Use the Azure CSP Migration Assessment tool. This will give you a good overview of which resources can be migrated, which require some extra action and which cannot be moved. The output is something similar to this:
Premium Storage | Data Services | SQL Database | UNKNOWN | Use Azure Resource Move |
Premium Storage | Data Services | SQL Database | UNKNOWN | Use Azure Resource Move |
Premium Storage | Data Services | SQL Database | UNKNOWN | Use Azure Resource Move |
Compute Hours | Virtual Machines | Standard_B2 VM | UNKNOWN | Use Azure Resource Move |
Standard Managed Disk/S4 (Units) | Storage | Locally Redundant | MODIFY | Does not support Resource Move, requires redeploy |
Standard Managed Disk/S10 (Units) | Storage | Locally Redundant | MODIFY | Does not support Resource Move, requires redeploy |
Registry Unit | Container Registry | Standard | UNKNOWN | Does not support Resource Move, requires redeploy |
Professional | Visual Studio | BLOCKED | Leave behind until resource is available on CSP | |
Protected Instances | Recovery Services | Backup | MODIFY | Does not support Resource Move, requires redeploy |
Standard Compute Unit | Data Services | Azure Database for MySQL | UNKNOWN | Use Azure Resource Move |
Registry Unit | Container Registry | Standard | UNKNOWN | Does not support Resource Move, requires redeploy |
Etc. |
Also, the tool will give you an indication of the cost per resource in the new CSP subscription model.
Plan
Now use the collected data to plan the CSP migration. In my scenario I have used an per resource group approach. This comes down to the following steps:
- Check per Resource Group which Resources are eligible for the move. You can use:
- The outcome of the CSP Planner tool.
- Use the following list to check if the resources are eligible for the move and available the destination region.
Note: marketplace resources are available in the CSP model by using the BYOL type. PAYG marketplace resources are not available in CSP. Also, to move BYOL marketplace resources (for example Barracuda NGF) requires you to remove the VM, move the disk and other VM related resources, and rebuild the VM in the new subscription.
- Draft a plan with the following phases:
- Prepare; This phase includes all the steps which are required to start the move to the Azure CSP subscription.
- Move; A per resource group based approach to move the resources to Azure CSP Migration. Define how and when the resources are moved.
- Post activities; All the post activities which are required after the CSP move has been completed. Like for instance resources which cannot be moved need be redeployed or migrated.
At the end of this phase you should have a complete overview on what resources will be moved and what approach you will be using.
Prepare
The preparation phase comes down to preparing the destination CSP subscription and preparing the resources for the move.
- Classic (ASM) resources. Azure Classic Resources cannot be moved to the CSP subscription because it is ARM based only; This means, these ASM type of resources need to be migrated to ARM. You can use the following link for some ASM to ARM migration guidance.
- Create the new CSP subscription and make sure it is assigned to the same Azure Active Directory tenant; Create a new Azure Subscription and make sure it is linked to the same Azure Active Directory tenant like the existing subscription(s).
- Set the same Azure subscription permissions; Now make sure the same access permissions are set on the new subscription like on the existing subscription. You can check the permissions by opening the Subscirption tab in the Azure portal and click on Access Control (IAM). Note: Also check the permissions set on the individual Resource Groups.
- Register Azure Resources Providers in the new subscription. Before you start moving resources into the new subscription you must make sure that the Azure Resource Provider type for all resources are available. You can check this by using the following cmdlet:
1 | Get-AzureRmResourceProvider -ListAvailable | Select-Object ProviderNamespace, RegistrationState |
This will provide you a list will registered and non-registered resource providers. In case you want to register an resource provider you can use the following cmdlet:
1 | Register-AzureRmResourceProvider -ProviderNamespace “name provider” |
- Check the Quota limits in the new subscription and adjust them when needed. To avoid any errors during the migration you must make sure the quota of the new subscriptions meets the same limits like the source subscription. You are able to find the quota at the subscription tab and click on “Usage + Quato”.
- Managed disks to unmanaged.
At the moment of writing you cannot move managed disks between resource groups. Also, this is one of the most common prepare activities I have encountered. This is why I have created some basic script to change disks from managed to unmanaged. To make use of the script you need to create a new storage account on which the unmanaged disks can be stored.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | Script: migrate-managed2unmanaged Version: 0.1 Author: Jurgen van den Broek Description: This script can be used to change a managed disk to unmanaged for specific Azure Virtual Machine. The script creates a new storage account for the unmanaged disks. In the first part of the script the current VM configuration is exported and put into a deallocated state. Next the managed disk is copied to the newly created storage account. Next, the VM is removed and build up by using the unmanaged disk. Use the availability set name parameter if the VM is part of a High Available set and using managed disks. This required because the managed disk availability set configuration is different compared to unmanaged disks. Param ( # Param subscription is the name of the Azure subscription. $Subscription, # Param resourceGroup is the name of the Resource Group containing the Virtual Machines. $Resourcegroup, # Param virtualMachine is the name of the VM which requires a disk change. $VirtualMachine, # Param storageAccountName is the name of the Storage Account on which the unmanaged disks will be stored. $StorageAccountName ) Begin { #Creating Parameters based on questions. #$Subscription = Read-Host "Enter the name of the Azure Subscription" $Subscription = "subscription name" #$Resourcegroup = Read-Host "Enter the name of Azure Resource Group which contains the VMs" $Resourcegroup = "resource group name" #$VirtualMachine = Read-Host "Enter the name of the Azure Virtual Machine you want to switch disk types" $VirtualMachineName = "vm name" #$availabilitysetname = Read-Host "Enter then name of the new Availabity Set" $AvailabilitySetName = $null #$rgstorageaccountname = "temp-storage" $StorageAccountName = $Resourcegroup.ToLower() + "store" $StorageAccountName = $StorageAccountName.replace('-','') #Login-AzureRmAccount Select-AzureRmSubscription -SubscriptionName $Subscription } Process { try { #Create Azure Storage Account for unmanaged disk #The if statement checks if the storage allready exists. If not it will create a new one. $x = Get-AzureRmStorageAccount -ResourceGroupName $Resourcegroup -Name $StorageAccountName -ErrorAction SilentlyContinue if ($x.StorageAccountName -eq $StorageAccountName) { Write-Host "The Storage Acccount with the name $StorageAccountName does allready exist and will be used" -ForegroundColor Yellow $StorageAccountKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $Resourcegroup -Name $storageAccountName ) | Select-Object -Property "Value" -First 1 $context = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey.Value } else { Write-Host "Creating Azure Storage Account with the name $StorageAccountName" -ForegroundColor Green $storageAccount = New-AzureRmStorageAccount -ResourceGroupName $Resourcegroup -Name $StorageAccountName -SkuName Standard_LRS -Kind Storage -Location "West Europe" $StorageAccountKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $Resourcegroup -Name $storageAccountName ) | Select-Object -Property "Value" -First 1 $context = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey.Value New-AzureStorageContainer -Name mig -Permission Container -Context $context Write-Host "The Azure Storage Account with the name $StorageAccountName has been created." -ForegroundColor Green } $vm = Get-AzureRmVM -ResourceGroupName $Resourcegroup -Name $VirtualMachineName #$vm | Export-Csv -Path "path" -NoClobber -Force if ($vm.Name -eq $VirtualMachineName) { $osDisklist = $vm.StorageProfile.OsDisk | Where-Object {$_.ManagedDisk -ne $null} | Select-Object Name $dataDisklist = $vm.StorageProfile.DataDisks | Where-Object {$_.ManagedDisk -ne $null} | Select-Object Name $message = 'something' $question = 'You are about to start the migration and stop the Virtual machine. Are you sure you want to proceed?' $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription] $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes')) $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No')) $decision = $Host.UI.PromptForChoice($message, $question, $choices, 1) if ($decision -eq 0) { Write-Host 'The migration is started' $decision = "True" } else { Write-Host 'The migration is cancelled' $decision = "False" } if ($decision -eq "True") { $vm | Stop-AzureRmVM -Force if ($dataDisklist -ne $null) { $osDisk = $osDisklist.name $dataDisk = $dataDisklist.Name $osDiskvhd = $osDisklist.name + ".vhd" $dataDiskvhd = $dataDisklist.Name + ".vhd" $sas = Grant-AzureRmDiskAccess -ResourceGroupName $storageaccountname -DiskName $osDisk -Access Read -DurationInSecond 3600 $sas = Grant-AzureRmDiskAccess -ResourceGroupName $StorageAccountName -DiskName $dataDisk -Access Read -DurationInSecond 3600 $blobcopyresultOs = Start-AzureStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestinationContainer "mig" -DestinationBlob $osdiskvhd -DestinationContext $context $blobcopyresultData = Start-AzureStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestinationContainer "mig" -DestinationBlob $datadiskvhd -DestinationContext $context $statusos = $blobcopyresultOs | Get-AzureStorageBlobCopyState $statusos $statusdata = $blobcopyresultdata | Get-AzureStorageBlobCopyState $statusdata While($statusos.Status -eq "Pending"){ Start-Sleep 30 $statusos = $blobcopyresultOs | Get-AzureStorageBlobCopyState $statusos } While($statusdata.Status -eq "Pending"){ Start-Sleep 30 $statusdata = $blobcopyresultdata | Get-AzureStorageBlobCopyState $statusdata } } else { $osDisk = $osDisklist.name $osDiskvhd = $osDisklist.name + ".vhd" $sas = Grant-AzureRmDiskAccess -ResourceGroupName $Resourcegroup -DiskName $osDisk -Access Read -DurationInSecond 3600 $blobcopyresultOs = Start-AzureStorageBlobCopy -AbsoluteUri $sas -DestinationContainer "mig" -DestinationBlob $osdiskvhd -DestinationContext $context -Force $statusos = $blobcopyresultOs | Get-AzureStorageBlobCopyState $statusos While($statusos.Status -eq "Pending"){ Start-Sleep 30 $statusos = $blobcopyresultOs | Get-AzureStorageBlobCopyState $statusos } } } else { } if ($AvailabilitySetName -ne $null) { $originalavailabilityset = $AvailabilitySetName $newavailabilitysetname = $originalavailabilityset + "as" $as = Get-AzureRmAvailabilitySet -ResourceGroupName $Resourcegroup -Name $newavailabilitysetname -ErrorAction SilentlyContinue if ($as -ne $null) { $newavailabilityset = new-AzureRmAvailabilitySet -ResourceGroupName $Resourcegroup -Name $newavailabilitysetname -Location "West Europe" } else { $newavailabilityset = Get-AzureRmAvailabilitySet -ResourceGroupName $Resourcegroup -Name $newavailabilitysetname -ErrorAction SilentlyContinue Write-host "Availabilityset does allready exist" } } else { Write-host "New availability set not required since this is a single VM deployment" } $message = 'something' $question = 'You are about to finisch the migration and recreate the Virtual machine. Are you sure you want to proceed?' $choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription] $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes')) $choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No')) $decision = $Host.UI.PromptForChoice($message, $question, $choices, 1) if ($decision -eq 0) { Write-Host 'The migration is started' $decision = "True" } else { Write-Host 'The migration is cancelled' $decision = "False" } if ($decision -eq "True") { Remove-AzureRmVM -ResourceGroupName $resourceGroup -Name $VirtualMachineName # Create a new VM with the same name and size $newVm = New-AzureRmVMConfig -VMName $Vm.Name -VMSize $Vm.HardwareProfile.VmSize #-AvailabilitySetId $as.Id (enable this when using a availability set) $newVm = Set-AzureRmVMOSDisk -VM $newvm -VhdUri (Get-AzureStorageBlob -Context $context -Blob $osDiskvhd -Container "mig").ICloudBlob.uri.AbsoluteUri -CreateOption Attach -Name $osDisk -Linux # change Linux to Windows when creating a Windows VM. if ($dataDisklist -ne $null) { $newVm = Set-AzureRmVMDataDisk -VM $newvm -VhdUri (Get-AzureStorageBlob -Context $context -Blob $dataDiskvhd -Container "mig").ICloudBlob.uri.AbsoluteUri -CreateOption Attach -Name $dataDisk } foreach($nic in $Vm.NetworkProfile.NetworkInterfaces) { Add-AzureRmVMNetworkInterface -VM $newVm -Id $nic.Id } New-AzureRmVM -ResourceGroupName $resourceGroup -Location "West Europe" -VM $newVm } else { } } else { } } catch { Write-Host "The script has encounterd an error" -ForegroundColor Red } } |
Common issue: Copy actions gets stuck while copying managed disk to a storage account
During the migration of managed to unmanaged disks, I have encountered a problem which seems to be related to the managed disk backend API. While copying the managed disks to a storage account it got stuck at a certain %. Some of the activities got stuck at 0 bytes copied and some of them in the middle of a copy action (x bytes). To troubleshoot this, I have tried to increase the token timeout of the SAS token but without any luck. When I tried to download the same disk, which failed to copy to a storage account, via the portal (locally) it was downloaded successfully. This made me come up with the workaround to create a VM in Azure and download the disk locally on this VM. Unfortunately the download of the disk failed with a similar behavior like the copy action to storage account. In the end I have managed to work around this issue.
Solution (workaround)
Create a VM in Azure with enough disk space for the managed disk you want to download locally. Next download and install the network throttling tool TMeter and configure it as described in the following post. Make sure to set the throttle to 15mbp/s. (in my experience this seems to be the cap)
In the end this helped me to download the disks on the VM and upload the disks by using the full upload bandwidth using the following script:
1 | AzCopy /Source:C:\Users\jurge\Downloads /Dest:https://”name storage”.blob.core.windows.net/mig /DestKey:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx /Pattern:”name disk”.vhd /BlobType:page |
I used the last part of the managed – unmanaged disk script to recreate the VM based on the upload disk.
- Resource type which are not eligible for the move. Define a migration plan for the resources which are eligible for a resource group move. Some common blockers I have encountered:
- Azure websites including TLS certificates. See the common resource group issues in the section below.
- Azure MySQL / Postgres database. This requires a manual database migration.
- Azure SQL database with Long Term Backup enabled. This requires a manual database migration to save the Long Term Backups being already made.
- Sendgrid service. This requires a migration to new service because Sendgrid is not available in the CSP model.
- Recovery Vault. This requires a manual recreation of the Azure Backup Vault in the new subscription.
Also, this might be a good time to discuss and define a new target model for resource groups, policies and RBAC. This can be either part of the preparation or post activities.
Move
For the actual move of the resources to CSP subscription I have used another Powershell script which is based on per Resource Group move approach.
- Export all configurations + resources id’s of the current resource groups and resources.
The following script will collect all the resource id’s per resource group and export these into csv files. Also, json files are generated including all properties of each individual resource in a resource group.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #$resourcegroups = Get-AzureRMResourceGroup | Where-Object { $_.ResourceGroupName –like } $resourceIds = @() $moveSeparateResources = @() $nonMovableTypes = @('microsoft.insights/components','Microsoft.Compute/virtualMachines/extensions','Microsoft.RecoveryServices/vaults', 'Microsoft.DBforMySQL/servers', 'Microsoft.Compute/disks') # These are the types that cannot be moved $typeToMoveSeparate = @() # These are the types that must be moved separately $rglist = @() foreach ($group in $resourcegroups) { $rgname = $group.resourcegroupname $rglist += $rgname } Out-File -InputObject $rglist -FilePath C:\resourcegroups.csv #export configuration + resource ids for move foreach ($group in $resourcegroups) { $rgname = $group.resourcegroupname $resourceids = @() $resourcegroupresources = Find-AzureRmResource -ResourceGroupNameEquals $rgname foreach ($r in $resourcegroupresources) { if ($nonMovableTypes.Contains($r.ResourceType)) { continue } if ($typeToMoveSeparate.Contains($r.ResourceType)) { $moveSeparateResources = $moveSeparateResources + $r; } else { $resourceIds = $resourceIds + $r.ResourceId; } } Out-File -InputObject $resourceids -FilePath C:\$rgname"ResourceIDs".csv -Force Export-AzureRmResourceGroup -ResourceGroupName $rgname -Path C:\$rgname.json -Force } |
The exported files will be helpful during the move and it can also be considered as a backup.
- Move all dependent resources into a single resource group.
Now we move all dependent resources into a single resource group so we are able to move them all at the same time. The most common scenario which requires this, is a VNET including VM’s and related resources like storage accounts, availability sets, load balancers and public IP’s. Use the following script to move the resources based on the exported csv files:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ###Import / Move Resources $destResourceGroup = "xxxx" # Name of the resource group your moving resources to $subscriptionId = "xxxx-xxxx-xxxx-xxxx-xxxx" $rgcsv = "path the resource group id's file" $csv = Import-Csv -Path $rgcsv -Header "resourceids" $groupResources = @() foreach ($id in $csv) { $groupResources = $groupResources + $id.resourceids } Move-AzureRmResource -DestinationSubscriptionId $subscriptionId -DestinationResourceGroupName $destResourceGroup -ResourceId $groupResources |
- Move the resources.
Now move the resources which you have moved into a single resource group based on the script above. Just make sure to replace the subscriptionId and resource group name with the values in the CSP subscription.
You might encounter some errors when you try to move the resources to the other resource group in the CSP subscription. Some of the errors I have encountered are listed below.
Common errors
VNET timeout error
This error was generated during the move of multiple VM’s and its related resources (including the VNET) to the other subscription. It took me a while to figure out what was happing, but it seems not related to VNET at all.
{\"target\":\"Microsoft.Network/virtualNetworks\",\"message\":\"{\\\"error\\\":{\\\"code\\\":\\\"ResourceMoveTimedOut \\\",\\\"message\\\":\\\"Move resources for provider 'Microsoft.Network' did not finish within allowed time '00:15:00'.\\\"}}\"}, <em>Solution</em> |
Some of the VM sizes in the source subscription (D series) were not available in CSP. After changing these VM’s to Dv2 series size, the move completed successfully.
Dependent resources
You might get this error when you initiated a move and some of the depended resources are in another resource group.
{"code":"ResourceMoveProviderValidationFailed","message":"Resource move validation failed. Please see details. Diagnostic information: timestamp '20180117T221529Z', subscription id 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', tracking id 'xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxxx', request correlation id 'xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx'.", "details":[{"target":"Microsoft.Compute/virtualMachines","message":"{\"error\":{\"details\":[{\"code\":\ "MissingMoveDependentResources\",\"target\":\"/subscriptions/xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/ mycatalstrg/providers/Microsoft.Storage/storageAccounts/mycatalyst\",\"message\":\ "The move resources request does not contain all the dependent resources. Please check error details for missing resource ids.\ "}],\"code\":\"MissingMoveDependentResources\",\"message\":\"T he move resources request does not contain all the dependent resources. Please check error details for missing resource ids.\ "}}"},{"target":"Microsoft.Network/virtualNetworks","message":"{\"error\":{\"code\":\"MissingMoveDependentResource s\",\" |
Solution
To successfully complete the move you need move all the depended resources into one resource group and initiate the move again.
Storage account in multiple regions
I have encountered this error when trying to move two storage accounts. One of the storage accounts relies in West Europe and the other in North Europe.
We are having another issue for moving a Storage Account: Move-AzureRmResource : {'error':{'code':'ResourceMoveProvid erValidationFailed','message':'Resource move validation failed. Please see details. Diagnostic information: timestamp '2018 0413T093143Z', subscription id 'eed2e64f-4182-44f1-8426-93ce4283e739', tracking id 'b4ea2b4d-dc28-4fcc-8932-5cc9627 89134', request correlation id '511ecde4-2dc4-4bb6-a01a-344a85b21115'.','details':[{'target':'Microsoft.Storage/storageAcco unts','message':'{\\'error\\':{\\'code\\':\\'MoveResourcesStorageAccountsNotFound\\',\\'message\\':\\'Move resources s pecified storage account(s) System.Collections.Generic.List`1[System.String] are not found with sourceSubscription <em>'xxxxx xxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxxx', sourceResourceGroup xxxxxx, targetSubscription </em><em>'xxxxxxxxx-xxxxx-xxxx-xxxx-xxx xxxxxxxxxxx', targetResourceGroup xxxxxx\\'}}'},{'target':'Microsoft.Storage/storageAccounts','message':'{\\'error\\':{\ \'code\\':\\'MoveResourcesStorageAccountsNotFound\\',\\'message\\':\\'Move resources specified storage account(s) S ystem.Collections.Generic.List`1[System.String] are not found with sourceSubscription </em><em>'xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxx xxxxxxxxx', sourceResourceGroup xxxx, targetSubscription </em><em>'xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxxx', targetResource Group xxxxx.\\'}}'}]}} At line:9 char:17 + ... Move-AzureRmResource -DestinationResourceGroupName $destR ... + ~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Move-Azur eRmResource], ErrorResponseMessageException + FullyQualifiedErrorId : Conflict,Microsoft.Azure.Commands.Resourc eManager.Cmdlets.Implementation.MoveAzureResourceCommand </em> |
Solution
Move the storage accounts one by one and the move will complete successfully.
Move multiple SQL Azure database servers
This error occurs when you try move multiple Azure SQL database servers (PaaS) at a time.
"properties": { "statusCode": "Conflict","statusMessage": "{\"error\":{\"code\":\"ResourceMoveProviderValidationFailed \",\"message\":\"Resource move validation failed. Please see details. Diagnostic information: timestamp '20180413T120 131Z', subscription id <em>'xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxxx'</em>, tracking id '6ea7efd8-adfb-48f6-91ed-ebe9555b80ad' , request correlation id 'c7636917-a42e-465c-83df-1d3c501d0b7d'.\",\"details\":[{\"target\":\"Microsoft.Sql/servers\",\" message\":\"{\\\"error\\\":{\\\"code\\\":\\\"SubscriptionDoesNotHaveServer\\\",\\\"message\\\":\\\"Subscription <em>'x xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxxx'</em> does not have the server 'xxxxxxxx'.\\\"}}\"},{\"target\":\"Microsoft.Sql/serv ers\",\"message\":\"{\\\"error\\\":{\\\"code\\\":\\\"SubscriptionDoesNotHaveServer\\\",\\\"message\\\":\\\"Subscri ption <em>'xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxxx'</em> does not have the server 'xxxxxx'.\\\"}}\"}]}}", "serviceRequestId": null}, |
Solution
Move the SQL database servers and the linked databases one by one and the move will complete successfully.
Move Webapp with certificates
The following error is generated when you try to move app service plans including WebApps which have a TLS certificate configured on it.
"submissionTimestamp": "2018-04-13T12:33:21.1029946Z", "subscriptionId": "eed2e64f-4182-44f1-8426-93ce4283e739", "properties": { "statusCode": "BadRequest", "statusMessage": "{\"error\":{\"code\":\"ResourceNotFound\",\"message\":\ "Resources with identifiers 'Microsoft.Web/certificates/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, Microsoft.Web/certificates/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' were not found . The tracking Id is '09e8c89a-eb8f-4736-b246-d96157585a2a'.\"}}", "serviceRequestId": null }, |
Solution
To move a WebApp which has a TLS certificate configured, you need to remove the TLS certificate from the site. Move the resources to the other subscription. And upload and configure the TLS certificate back on the site.
Final steps..
The final step, when you have completed the move of all the resources into the new CSP subscription, is to divide the resources over the different resource group in the new subscription. For this I have used the same script as shown above for the resource move. For the resources I wanted to move I have adjusted the different resource ID’s in the csv files by replacing:
/subscriptions<strong>/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/ resourcegroupname</strong>/providers/Microsoft.KeyVault/vaults/kv-diskencryption |
With the new subscription ID and the name of resource group in which the resources have moved into.
I’d hope this post will be helpful for anyone who is moving resources between subscriptions or in particular to a CSP subscription model.