Azure Azure Compute Azure PowerShell Microsoft Excel

How to List and Export Available Azure VM Images by Generation and Region with an Azure PowerShell script


In this blog post, you’ll learn how to use an Azure PowerShell script to list and export available Azure VM images by generation and region to a CSV file for easy review.

As many of you know, Azure VM images form the foundation of every virtual machine deployment. Without validating the correct generation (Gen1 or Gen2) and regional availability, you may encounter deployment errors or unsupported configuration scenarios, especially in enterprise environments operating across multiple Azure regions.

That’s why I’ll show you how to automate this process using an Azure PowerShell script that programmatically retrieves and exports available Azure VM image SKUs by generation and region for a selected set of common OS publishers. This approach saves time and provides a reliable way to validate image availability before deploying virtual machines


Table of Contents


Prerequisites

  • At least version 14.6.0 of the Azure Az PowerShell module is required.


Executing actions and utilizing the Azure PowerShell script

To automate the listing and export of available Azure VM image SKUs by generation (Gen1 or Gen2) and region for common OS publishers, the Azure PowerShell script I’ve created performs the following actions:

  • Remove the breaking change warning messages.
  • Create C:\Temp folder if not exists.
  • List available Azure VM image SKUs by generation and region and export to CSV.
  • Open the CSV file if it was created.

To use the script, start by either copying and saving it as List-and-Export-available-Azure-VM-Images-by-Generation-and-Region.ps1 or downloading it directly from GitHub. You can then run the script using Windows Terminal, Visual Studio Code, or Windows PowerShell. Alternatively, it can be executed directly from Azure Cloud Shell.


Azure PowerShell script

If you are not using Azure Cloud Shell to run the script, remember to sign in using the Connect-AzAccount cmdlet to authenticate with your Azure account.


You can then run the script with the required parameters to initiate the process.

.\List-and-Export-available-Azure-VM-Images-by-Generation-and-Region "<specify region>" -Generation "<specify generation Gen1 or Gen2>"

<#
.SYNOPSIS

A script used to list and export available Azure VM image SKUs by generation (Gen1 or Gen2) and region.

.DESCRIPTION

A script used to list and export available Azure VM image SKUs by generation (Gen1 or Gen2) and region. 
The script will do all of the following:

Remove the breaking change warning messages.
Create C:\Temp folder if not exists.
List available Azure VM image SKUs by generation and region and export to CSV.
Open the CSV file if it was created.

.NOTES

Filename:       List-and-Export-available-Azure-VM-Images-by-Generation-and-Region.ps1
Created:        22/12/2025
Last modified:  22/12/2025
Author:         Wim Matthyssen
Version:        1.0
PowerShell:     Azure PowerShell and Azure Cloud Shell
Requires:       PowerShell Az (v14.6.0)
Action:         Change variables were needed to fit your needs.
Disclaimer:     This script is provided "As Is" with no warranties.

.EXAMPLE

Connect-AzAccount
.\List-and-Export-available-Azure-VM-Images-by-Generation-and-Region "<specify region>" -Generation "<specify generation Gen1 or Gen2>"

Example: .\List-and-Export-available-Azure-VM-Images-by-Generation-and-Region -Region "westeurope" -Generation "Gen2"

.LINK

https://wmatthyssen.com/2025/12/22/how-to-list-and-export-available-azure-vm-images-by-generation-and-region-with-an-azure-powershell-script/
#>

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Parameters

param(
    [string]$Region = "westeurope",
    [ValidateSet("Gen2","Gen1")]
    [string]$Generation = "Gen2"
)

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Variables

$region = $Region
$tempFolderName = "Temp"
$tempFolder = "C:\" + $tempFolderName +"\"
$itemType = "Directory"

# Limit to common OS publishers so the query completes in reasonable time
$publishersOfInterest = @(
    "MicrosoftWindowsServer"  # Windows Server
    #"MicrosoftWindowsDesktop",  # Windows client
    #"Canonical",                # Ubuntu
    #"RedHat",                   # RHEL
    #"SUSE",                     # SLES
    #"Oracle",                   # Oracle Linux
    #"OpenLogic"                 # CentOS
)

Set-PSBreakpoint -Variable currenttime -Mode Read -Action {$global:currenttime = Get-Date -Format "dddd MM/dd/yyyy HH:mm"} | Out-Null 
$foregroundColor1 = "Green"
$foregroundColor2 = "Yellow"
$foregroundColor3 = "Red"
$writeEmptyLine = "`n"
$writeSeperatorSpaces = " - "

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Remove the breaking change warning messages

Set-Item -Path Env:\SuppressAzurePowerShellBreakingChangeWarnings -Value $true | Out-Null
Update-AzConfig -DisplayBreakingChangeWarning $false | Out-Null
$warningPreference = "SilentlyContinue"

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script started

Write-Host ($writeEmptyLine + "# Script started. Scanning $Generation SKUs in region $region for common OS publishers. " +
"Without errors, it can take up to 2 minutes to complete" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Create C:\Temp folder if not exists

If(!(test-path $tempFolder))
{
New-Item -Path "C:\" -Name $tempFolderName -ItemType $itemType -Force | Out-Null
}

Write-Host ($writeEmptyLine + "# $tempFolderName folder available" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor2 $writeEmptyLine

## ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## List available Azure VM image SKUs by generation and region and export to CSV

# For Gen1 SKUs *without* this pattern are treated as Gen1.
$gen2Pattern = '(?i)(^|-)(g2|gen2)($|-)'

$result = foreach ($publisher in $publishersOfInterest) {
    $offers = Get-AzVMImageOffer -Location $region -PublisherName $publisher -ErrorAction SilentlyContinue
    if (-not $offers) { continue }

    foreach ($offer in $offers) {
        $skus = Get-AzVMImageSku -Location $region -PublisherName $publisher -Offer $offer.Offer -ErrorAction SilentlyContinue
        if (-not $skus) { continue }

        foreach ($sku in $skus) {
            $skuName = $sku.Skus
            if (-not $skuName) { continue }

            $isGen2Like = $skuName -match $gen2Pattern

            # Select by requested generation
            if (($Generation -eq "Gen2" -and $isGen2Like) -or
                ($Generation -eq "Gen1" -and -not $isGen2Like)) {
                [PSCustomObject]@{
                    Publisher = $publisher
                    Offer     = $offer.Offer
                    Sku       = $skuName
                }
            }
        }
    }
}

if (-not $result) {
    Write-Host ($writeEmptyLine + "# No $Generation SKUs found in region $region for the selected publishers." + $writeSeperatorSpaces + $currentTime)`
    -foregroundcolor $foregroundColor3 $writeEmptyLine 
} else {
    $result |
    Sort-Object Publisher, Offer, Sku |
    Export-Csv -Path ($tempFolder + "AzureVmImages-$Generation-$region.csv") -NoTypeInformation -Encoding UTF8
    Write-Host ($writeEmptyLine + "# CSV file created: $tempFolder" + "AzureVmImages-$Generation-$region.csv" + $writeSeperatorSpaces + $currentTime)`
    -foregroundcolor $foregroundColor2 $writeEmptyLine
}

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Open the CSV file if it was created

$csvPath = ($tempFolder + "AzureVmImages-$Generation-$region.csv")

if (Test-Path $csvPath) {
    Write-Host ($writeEmptyLine + "# Opening CSV file: $csvPath" + $writeSeperatorSpaces + $currentTime)`
    -ForegroundColor $foregroundColor2 $writeEmptyLine

    Invoke-Item $csvPath   # open CSV with default app (Excel)
}

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

## Write script completed

Write-Host ($writeEmptyLine + "# Script completed" + $writeSeperatorSpaces + $currentTime)`
-foregroundcolor $foregroundColor1 $writeEmptyLine 

## ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------




Adjusting the CSV layout for improved readability in Excel

In the opened CSV. file, you may see a warning message stating “POSSIBLE DATA LOSS Some features might be lost if you save this workbook in the comma-delimited (.csv) format. To preserve these features, save it in an Excel file format.”


First, click the X to dismiss the warning.


Then select the column containing all the data, navigate to the Data tab in the Excel ribbon, and click Text to Columns.


In the wizard that appears, select Delimited and click Next.


On the next screen, select Comma as the delimiter and click Next.


Finally, click Finish to apply the changes. The data will now be displayed in clearly defined columns, making it easier to read and analyze.



Conclusion

I hope the Azure PowerShell script shared in this blog post helps simplify the discovery and usage of Azure VM images by generation and region across your subscriptions.

If you have any questions or suggestions about this blog post or script, feel free to reach out to me on X (@wmatthyssen) or leave a comment. I’ll be happy to help.



Unknown's avatar

Wim is an Azure Technical Advisor and Trainer with over fifteen years of Microsoft technology experience. As a Microsoft Certified Trainer (MCT), his strength is assisting companies in the transformation of their businesses to the Cloud by implementing the latest features, services, and solutions. Currently, his main focus is on the Microsoft Hybrid Cloud Platform, and especially on Microsoft Azure and the Azure hybrid services.   Wim is also a Microsoft MVP in the Azure category and a founding board member of the MC2MC user group. As a passionate community member, he regularly writes blogs and speaks about his daily experiences with Azure and other Microsoft technologies.