Efficient Azure Virtual Network Cloning: Copying Single and Multiple VNets using PowerShell

Creating a copy of an existing Virtual Network in a location of your choosing can be useful for a wide range of reasons, in my case, I want to copy a live configuration so that I can safely demonstrate the value of utilising the Virtual Network Manager solution.

In an ideal situation, there would be no need to clone an Azure Virtual Network as you would redeploy using whatever templating solution you use. Still, often this isn’t possible for a whole range of reasons, in which case we need a practical way to clone Virtual Networks, which isn’t functionality that the Azure Portal offers.

This is where a scripting solution can take some of the burden, I’ll present 2 solutions below, one which will take a given Virtual Network in any existing Subscription and then copy it to the new Subscription and Resource Group, and the other which will copy all Virtual Networks in a given Subscription to the target location.

There are some significant limitations to this approach however, the scripts below are designed to effectively copy the overall VNet config and any Subnets, it will not copy elements such as any Bastion config, DDoS Protection, Firewalls etc as this was outside of the scope of what I needed to copy.

The Scripts

The scripts below were originally based on a script by Anderson Patricio, I have significantly modified them both to expand the functionality however they’re both still somewhat limited in scope and would require additional work to make them production-ready in any real capacity.

Copy a Single VNet

This script will take any Virtual Network within the provided tenant, subscription and with the provided name and copy it to a target Subscription which can be different from the source.

# Original Source - https://github.com/andersonpatricio/scripts/blob/master/VNETClone.ps1

$tenantId = "###INSERT TENANT ID###"
$sourceSubscriptionName = "###INSERT SOURCE SUBSCRIPTION NAME###"
$sourceVirtualNetworkName = "original-Vnet-name"
$newVirtualNetworkSuffix = "clone"

$targetSubscriptionName = "###INSERT TARGET SUBSCRIPTION NAME###"
$targetResourceGroupName = "test-policy"

Function CloneVNET {
    param(
        [Parameter(Mandatory=$True)]
        [string]$sourceSubscriptionName,

        [Parameter(Mandatory=$True)]
        [string]$VnetName,

        [Parameter(Mandatory=$True)]
        [string]$targetSubscriptionName,

        [Parameter(Mandatory=$True)]
        [string]$targetResourceGroupName,

        [Parameter(Mandatory=$False)]
        [string]$newVirtualNetworkSuffix
    )

    # Get the existing Virtual Network
    $sourceVnet = Get-AzVirtualNetwork -Name $VnetName

    # Switch context to the new Subscription if required
    $currentSub = Get-AzContext
    if($currentSub.Subscription.Name -ne $targetSubscriptionName) {
        Get-AzSubscription -SubscriptionName $targetSubscriptionName -WarningAction SilentlyContinue -TenantId $tenantId | Set-AzContext -WarningAction SilentlyContinue
    }

    # Create the new Virtual Network
    $newVnetName = $sourceVnet.name + "_" + $newVirtualNetworkSuffix
    $newVNET = New-AzVirtualNetwork -ResourceGroupName $targetResourceGroupName -Location $sourceVnet.Location -Name $newVnetName -AddressPrefix $sourceVnet.AddressSpace.AddressPrefixes -Force
    if ($newVNET.ProvisioningState -ne "Succeeded"){
        Write-Error "Failed to provision new VNet"
        return;
    }

    # Create the Subnets in the new Virtual Network
    $Subnets = $sourceVnet.Subnets
    foreach ($subnet in $subnets){
        Add-AzVirtualNetworkSubnetConfig -Name $subnet.name -AddressPrefix $subnet.AddressPrefix -VirtualNetwork $newVNET
    }
    $newVNET | Set-AZVirtualNetwork

    # Switch context back to the source Subscription if required
    $currentSub = Get-AzContext
    if($currentSub.Subscription.Name -ne $sourceSubscriptionName) {
        Get-AzSubscription -SubscriptionName $sourceSubscriptionName -WarningAction SilentlyContinue -TenantId $tenantId | Set-AzContext -WarningAction SilentlyContinue
    }

    return $newVnetName
}

# Authenticate to Azure
Connect-AZAccount -TenantId $tenantId

# Set context to the correct source Subscription
Get-AzSubscription -SubscriptionName $sourceSubscriptionName | Set-AzContext

CloneVNET -sourceSubscriptionName $sourceSubscriptionName `
        -VnetName $sourceVirtualNetworkName `
        -targetSubscriptionName $targetSubscriptionName `
        -targetResourceGroupName $targetResourceGroupName `
        -newVirtualNetworkSuffix $newVirtualNetworkSuffix

Copy all VNets

This script will copy all Virtual Networks found in a Subscription to the designated Subscription and Resource Group. If you’d like to copy it all like for like and to reproduce the Resource Groups too, it will require some further modification.

# Original Source - https://github.com/andersonpatricio/scripts/blob/master/VNETClone.ps1

$tenantId = "###INSERT TENANT ID###"
$sourceSubscriptionName = "###INSERT SOURCE SUBSCRIPTION NAME###"

$targetSubscriptionName = "###INSERT TARGET SUBSCRIPTION NAME###"
$targetResourceGroupName = "VNET-test"

Function CloneAllVnets {
    param(
        [Parameter(Mandatory=$True)]
        [string]$sourceSubscriptionName,

        [Parameter(Mandatory=$True)]
        [string]$targetSubscriptionName,

        [Parameter(Mandatory=$True)]
        [string]$targetResourceGroupName
    )

    # Get the existing Virtual Network
    $sourceVnets = Get-AzVirtualNetwork

    # Switch context to the new Subscription if required
    $currentSub = Get-AzContext
    if($currentSub.Subscription.Name -ne $targetSubscriptionName) {
        Get-AzSubscription -SubscriptionName $targetSubscriptionName -WarningAction SilentlyContinue -TenantId $tenantId | Set-AzContext -WarningAction SilentlyContinue
    }

    $sourceVnets | ForEach-Object {
        # Create the new Virtual Network
        $newVNET = New-AzVirtualNetwork -ResourceGroupName $targetResourceGroupName -Location $_.Location -Name $_.Name -AddressPrefix $_.AddressSpace.AddressPrefixes -Force
        if ($newVNET.ProvisioningState -ne "Succeeded"){
            Write-Error "Failed to provision new VNet"
            return;
        }

        # Create the Subnets in the new Virtual Network
        $Subnets = $_.Subnets
        foreach ($subnet in $subnets){
            Add-AzVirtualNetworkSubnetConfig -Name $subnet.name -AddressPrefix $subnet.AddressPrefix -VirtualNetwork $newVNET
        }
        $newVNET | Set-AZVirtualNetwork
    }

    # Switch context back to the source Subscription if required
    $currentSub = Get-AzContext
    if($currentSub.Subscription.Name -ne $sourceSubscriptionName) {
        Get-AzSubscription -SubscriptionName $sourceSubscriptionName -WarningAction SilentlyContinue -TenantId $tenantId | Set-AzContext -WarningAction SilentlyContinue
    }

    return $newVnetName
}

# Authenticate to Azure
Connect-AZAccount -TenantId $tenantId

# Set context to the correct source Subscription
Get-AzSubscription -SubscriptionName $sourceSubscriptionName | Set-AzContext

CloneAllVnets -sourceSubscriptionName $sourceSubscriptionName `
        -targetSubscriptionName $targetSubscriptionName `
        -targetResourceGroupName $targetResourceGroupName

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.