Validating Azure resource move beforehand with a script
tl;dr Came here just for the script? You can find it here: https://dev.azure.com/cloud1public/_git/Blog%20Source
Every now and then there is a need to move Azure resources around. Splitting one subscription to many, joining multiple subscriptions into one. Cloud Adoption Framework for Azure and its landing zones being one of the reasons.
Many of the Microsoft Azure resources can be moved between resource groups and subscriptions if they are within same Azure tenant. Azure Portal has a button for moving the resources which also performs a validation before the actual operation. Right now, there is no option for running just the validation from the UI without also moving the resources. Finding out about any issues only when already in the middle of moving the resources might bring the task to halt and jeopardize any planned transfer schedule, especially in critical environments.
Microsoft offers a checklist for moving Azure resources: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/move-resource-group-and-subscription.
The checklist contains items like:
- A specific resource may be moved only if some other resources are moved at the same time. For example, managed disks for a virtual machine must be moved together.
- The target subscription must have a registration for the resource type to be moved
The documentation referred within the checklist lists whether specific resource types support the move operation: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/move-support-resources
Microsoft Checklist lists the account moving the resources requiring the following permissions:
- Microsoft.Resources/subscriptions/resourceGroups/moveResources/action on the source resource group.
- Microsoft.Resources/subscriptions/resourceGroups/write on the destination resource group.
From among the built-in roles only Contributor and Owner roles have the required permissions.
Checking all the items in the Checklist manually can be a tedious task, especially if the number of resources to move is large.
API to the rescue
Luckily, there is an API just for validating the resource move operation. The API is described at https://docs.microsoft.com/en-us/rest/api/resources/resources/validatemoveresources.
The validation is a long running process, so the API works in two phases.
- Submitting the validation request and getting the parameters for the second part.
- Checking if the validation has finished and reporting the results when available.
The API has multiple versions, some dating back to 2014 and has a mandatory version parameter. Finding the most recent version proved to be difficult but one way for listing the valid options is to deliberately submit an incorrect version string, forcing the API to reveal all the supported versions:
Other notes about the API
The API requires the account making the request to have membership in the Contributor role on the source resource group. The permissions in the destination resource group seem not to be evaluated.
Also, the API may output multiple errors of various severity levels for an individual resource. For example, the validation result might warn about missing registration and that the resource cannot be moved.
Searching the Internet for PowerShell scripts using the forementioned API returns only few results, all of which seem to have some room for improvement (at least at the time of writing this article). Calling the API from PowerShell was quite easy but reporting the results cleanly required a little bit of work. Handling various exceptions and edge cases made the script a bit longer.
The whole PowerShell script can be found from our Azure DevOps repository: https://dev.azure.com/cloud1public/_git/Blog%20Source
The information the script needs to call the validation API:
- Source Azure Subscription ID
- Source Azure Resource group name
- Destination Azure Subscription ID (can be left out if it’s the same than source)
- Destination Azure Resource group name
Script will validate the move operation for all the resources in the specified resource group with two notable exceptions:
- the resources which have a parent resource; the validation API would fail for every child resource with a ResourceNotTopLevel error, so these are automatically excluded by checking if <resource>.ParentResource property has a value
- all resources of the Resource Types listed in an array called $excludedResourceTypes
$excludedResourceTypes array is meant to exclude resources from validation. The script will output a list of all excluded top level resources before starting the validation. In some cases, the validation will first report errors for some resources and skip reporting other errors. Only after the original errors are fixed / resources excluded, will the validation report other errors.
Hope you will find the script useful!