Search code examples
azureazure-devopsazure-powershell

Using AZ CLI in PowerShell to move all resources in an Azure Resource Group


I am looking to make an Azure DevOps Pipeline to move resources at the resource group level, to another subscription with an empty resource group. However, I'm running into an issue with Move-AzResource where it can't move all resources since some resources like storage accounts and VMs have a dependency on other resources. I know that the easy way to this is to just use the Azure Portal, but I was wondering if there was a way to programmable move resources instead. Any advice would help!

PowerShell Script:

# Connect to your Azure account
Connect-AzAccount -Tenant 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' -Subscription 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'

# Define resource group names
$sourceRG = "move-this"
$targetRG = "move-to-this"

# Specify the target subscription ID
$destinationSubscription = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" # Replace with your actual target subscription ID

# Get resources from the source resource group
$resources = Get-AzResource -ResourceGroupName $sourceRG

# Move each resource to the target resource group
foreach ($resource in $resources) {
    Move-AzResource -DestinationResourceGroupName $targetRG -DestinationSubscriptionId $destinationSubscription -ResourceId $resource.ResourceId -Force
}

Error:

Line |
   9 |      Move-AzResource -DestinationResourceGroupName $targetRG -Destinat …
     |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | ResourceMoveValidationFailed : The resource batch move request has '1' validation errors. Diagnostic information: timestamp '20240511T202422Z', tracking   
     | Id '791c0f0a-aa19-4929-86b0-fab99adb6ec9', request correlation Id '4502f145-7358-4076-b6ac-33987628efcf'. CorrelationId:
     | 6693eb66-f052-48da-bbb1-ab6676610a26

Tried to use Move-AzResource to move all of the resources in a resource group to a different resource group in another subscription. However, I'm getting validation errors due to the nature of the resources in that resource group.


Solution

  • I found that just moving each individual resource rather than the entire resource group was the answer. Using this script, I can list the resources I want to move in a parameter and move each resource individually through a for loop.

    move.ps1:

    $locationId                 = $env:locationID
    $destinationId              = $env:destinationID
    $destinationRg              = $env:destinationRG
    $resourceList               = $env:resourceList -replace '\s', '' # Remove any whitespace
    
    Write-Host "locationId: $locationId"
    Write-Host "destinationId: $destinationId"
    
    # Define an array of server names
    $resources                  = $resourceList -split ','
    
    # Specify the target resource group and destination subscription
    $locationSubscription       = $locationId
    $destinationSubscription    = $destinationId
    $targetRG                   = $destinationRg
    
    Set-AzContext -Subscription $locationSubscription
    # Loop through each server name and move the resource
    foreach ($resource in $resources) {
        $Resource               = Get-AzResource -ResourceName $resource
        if ($Resource -ne $null) {
            # Attempt to move the resource
            try {
                Move-AzResource -DestinationResourceGroupName $targetRG -ResourceId $Resource.ResourceId -DestinationSubscriptionId $destinationSubscription -Force
                Write-Host "Moved $($Resource.Name) to $targetRG in subscription $destinationSubscription" -ForegroundColor Green
            } catch {
                # Handle the error
                Write-Host "Error moving $resource $($_.Exception.Message)" -ForegroundColor Red
            }
        } else {
            Write-Host "Resource $resource not found in $locationSubscription!" -ForegroundColor Red
        }
    }
    

    move-reosurces.yml:

    trigger:
    - main
    
    parameters:
    - name: locationID
      type: string
      displayName: 'Where is the resource located?'
      default: '<origin-subscription-id>'
    
    - name: destinationID
      type: string
      displayName: 'Where is the resource going?'
      default: '<destination-subscription-id>'
    
    - name: destinationRG
      type: string
      displayName: 'Where are we putting the resource?'
      default: '<destination-resource-group>'
    
    - name: resourcesToMove
      type: string
      displayName: "What resources are we moving?"
      default: '(Separate the resources with a comma! Ex: resource1, resource2, resource3)'
    
    steps:
    - task: AzurePowerShell@5
      inputs:
        displayName: 'Move Resources'
        azureSubscription: '<service-principal-goes-here>'
        ScriptType: 'FilePath'
        ScriptPath: '$(Build.SourcesDirectory)/script/move.ps1'
        azurePowerShellVersion: 'LatestVersion'
      env:
        locationID: ${{parameters.locationID}}
        destinationID: ${{parameters.destinationID}}
        destinationRG: ${{parameters.destinationRG}}
        resourceList: ${{parameters.resourcesToMove}}
    

    This script will do the job.