Adopting Gen1 VMs into Azure Local (yes, the vintage ones)
If you are moving a Hyper-V Gen1 VM, something truly vintage like an Azure Stack Hub VM, or any other workload that refuses to accept that Gen2 exists, good news. You can still adopt it into Azure Local.
Azure Local strongly prefers Gen2 VMs. Secure Boot. vTPM. Modern things. Reality, however, contains Gen1 VMs that still matter. This article covers how to bring them along without rebuilding them or pretending they do not exist.
The overall adoption flow is almost identical to the Gen2 process covered earlier, with a few deliberate deviations where Gen1 demands special handling.
If you have not read the baseline article yet, start here
That one covers the core flow and the Azure CLI plumbing we will reuse here.
What follows is strictly the Gen1-specific delta.
High-level process
Same movie. Slightly different Act II and a less happy ending.
- Download and prepare the disks
- Create vNICs for each VM
- Create placeholder disks for each VHD or VHDX
- Swap placeholder disks with the real disks on the Azure Local CSV
- Create the Arc VM using ARM and Azure CLI
Steps 0 and 1 are unchanged. Use the same Azure CLI commands from the previous article.
The first real divergence appears when you create the placeholder OS disk.
Step 2. Create a Gen1 placeholder OS disk
Azure CLI does not expose all the knobs required for Gen1 disks, so we drop down to the REST API. This is where we explicitly tell Azure Local that this disk belongs to a Gen1 VM and uses VHD (which matters if you are into vintage Azure Stack Hub workloads).
Important detail. This must run in the same subscription and resource group that backs your Azure Local environment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Gen1 VHD placeholder disk
$uri = "https://management.azure.com/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.AzureStackHCI/virtualHardDisks/<vhdname>?api-version=2023-09-01-preview"
$payload = '{
"extendedLocation": {
"name": "/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.ExtendedLocation/customLocations/<s-cluster-customlocation>",
"type": "CustomLocation"
},
"location": "<location>",
"properties": {
"diskSizeGB": 127,
"dynamic": true,
"hyperVGeneration": "V1",
"diskFileFormat": "vhd",
"containerId": "/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.AzureStackHCI/storageContainers/<UserStorage1-xxx>"
}
}'
Note
You will need two values later, so write them down now:
- The disk name
<vhdname>- The storage container ID
UserStorageX-...
The storage container is the path where the disk physically lives on the cluster. You will reference it again when creating the VM.
Step 3. Swap placeholder disks
Nothing new here.
This is the same process as the Gen2 adoption flow. Replace the placeholder VHD with the real VHD you copied onto the cluster shared volume, then move on.
If this sounds hand-wavy, it is because it is already covered in detail in the Gen2 article.
We do not need to relive it together.
Step 4. Create the Arc VM (Gen1 edition)
Before doing this, make sure you have access to Hyper-V Manager on the Azure Local hosts. Gen1 VMs still rely on IDE controllers and legacy firmware assumptions. You may need Hyper-V Manager to sanity-check things like:
- IDE CD-ROM presence
- Boot order
- Whether the VM actually boots instead of staring back at you in silence
All of these changes require the VM to be stopped and started, so expect a few power cycles.
Here is the VM creation script. It looks almost identical to the Gen2 version, with two important differences:
- Secure Boot must be disabled
- vTPM must be disabled
Because Gen1.
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
$resourceGroup = "RGname"
$customLocation = "/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.ExtendedLocation/customLocations/<s-cluster-customlocation>"
$location = "AzLocalRegion"
$size = "Default"
$storagePathId = "/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.AzureStackHCI/storageContainers/<UserStorage1-xxxx>"
$vmName = "VMname"
$osDiskName = "/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.AzureStackHCI/virtualHardDisks/<diskname>"
$osType = "windows"
$nic1 = "/subscriptions/<subID>/resourceGroups/<RGname>/providers/Microsoft.AzureStackHCI/networkInterfaces/<nicName-created-before>"
$enableAgent = "false"
$enableVmConfigAgent = "false"
$enableVtpm = "false"
$enableSecureBoot = "false"
az stack-hci-vm create `
--resource-group $resourceGroup `
--custom-location $customLocation `
--location $location `
--size $size `
--storage-path-id $storagePathId `
--name $vmName `
--os-disk-name $osDiskName `
--os-type $osType `
--enable-agent $enableAgent `
--enable-vm-config-agent $enableVmConfigAgent `
--enable-vtpm $enableVtpm `
--enable-secure-boot $enableSecureBoot `
--nics $nic1
At this point, you should have a functional Gen1 VM running on Azure Local.
If it boots, take a moment to appreciate what just happened. You moved a legacy workload into a modern control plane without rebuilding it.
Enable guest management
The VM exists, but it is not fully manageable yet. You still need guest management, which means agents.
Microsoft documents the full flow here:
https://learn.microsoft.com/en-us/azure/azure-local/manage/manage-arc-virtual-machines?tabs=windows#enable-guest-management
Start enabling the Guest Management first (after shutting down the VM) so it mounts the agent iso and all that. Then add the bits below, and at the end you should have a fully managed AzLocal VM.
The short version looks like this.
1. Enable the VM configuration agent
1
2
3
4
az stack-hci-vm update \
--name "vmname" \
--resource-group "rg" \
--enable-vm-config-agent true
Note
Because this is a Gen1 VM, you must:
- Shut down the VM from the Azure Portal
- Run the command
- Start the VM again from the Azure Portal
Yes, this is intentional.
2. Log into the VM and install the guest agent
Make sure networking works first. No network, no agent, no joy.
Validate requirements here:
https://learn.microsoft.com/azure/azure-arc/servers/network-requirements?tabs=azure-cloud
Install the agent using the documented steps. This part is thankfully boring.
3. Enable the agent
1
2
3
4
az stack-hci-vm update \
--name "vmname" \
--resource-group "rg" \
--enable-agent true
You may need one more shutdown and startup cycle to make everything happy.
Gen1 VMs like ceremony.
Final thoughts
That is it.
You now have a Gen1 VM, built for a different era, running on Azure Local, managed through Azure Arc, and controlled using modern tooling.
Is Gen1 ideal? No.
Does it still exist in real environments? Absolutely.
Can Azure Local handle it? Yes, with a bit of respectful accommodation.
If you already went through the Gen2 adoption process, this should feel familiar. If not, start there and come back here for the Gen1 twist.
And yes, that other article is excellent.
We are not repeating it.
