Azure CSP Subscription Migration Guidance

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:

  1. 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:

  1. Check per Resource Group which Resources are eligible for the move. You can use:
    1. The outcome of the CSP Planner tool.
    2. 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.
  2. Draft a plan with the following phases:
    1. Prepare; This phase includes all the steps which are required to start the move to the Azure CSP subscription.
    2. Move; A per resource group based approach to move the resources to Azure CSP Migration. Define how and when the resources are moved.
    3. 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.

  1. 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.
  1. 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).
  1. 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.
  1. 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”
  1. 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”.
  1. 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.

  1. 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.

  1. 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.

    1. 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
  1. 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.