Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 64 additions & 4 deletions helpers/GenerateResourcesAndImage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ Function GenerateResourcesAndImage {
The type of image to generate. Valid values are: Windows2022, Windows2025, Windows2025_vs2026, Ubuntu2204, Ubuntu2404.
.PARAMETER ManagedImageName
The name of the managed image to create. The default is "Runner-Image-{{ImageType}}".
.PARAMETER ComputeGalleryName
The name of the existing compute gallery to use. If specified, the image definition and version will be created in this gallery instead of creating a managed image.
The compute gallery must already exist in the resource group specified by the ResourceGroupName parameter.
.PARAMETER ComputeGalleryImageName
The name of the compute gallery image definition to create within the specified compute gallery. This is required if ComputeGalleryName is specified.
.PARAMETER ComputeGalleryImageVersion
The name of the compute gallery image version to create within the specified compute gallery image definition. This is required if ComputeGalleryName is specified.
.PARAMETER AzureLocation
The Azure location where the Azure resources will be created. For example: "East US"
.PARAMETER ImageGenerationRepositoryRoot
Expand Down Expand Up @@ -130,6 +137,12 @@ Function GenerateResourcesAndImage {
[ImageType] $ImageType,
[Parameter(Mandatory = $False)]
[string] $ManagedImageName = "Runner-Image-$($ImageType)",
[Parameter(Mandatory = $False)]
[string] $ComputeGalleryName,
[Parameter(Mandatory = $False)]
[string] $ComputeGalleryImageName,
[Parameter(Mandatory = $False)]
[string] $ComputeGalleryImageVersion,
[Parameter(Mandatory = $True)]
[string] $AzureLocation,
[Parameter(Mandatory = $False)]
Expand Down Expand Up @@ -161,6 +174,17 @@ Function GenerateResourcesAndImage {
throw "'packer' binary is not found on PATH."
}

# Validate Compute Gallery parameters
if ($ComputeGalleryName -and -not $ComputeGalleryImageName) {
throw "ComputeGalleryImageName parameter is required when ComputeGalleryName is specified."
}
if ($ComputeGalleryName -and -not $ComputeGalleryImageVersion) {
throw "ComputeGalleryImageVersion parameter is required when ComputeGalleryName is specified."
}
if ($ComputeGalleryImageVersion -and -not ($ComputeGalleryImageVersion -match '^\d+\.\d+\.\d+$')) {
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If ComputeGalleryImageName/ComputeGalleryImageVersion are provided without ComputeGalleryName, they are silently ignored and a managed image is produced. Add validation to reject "partial" compute gallery inputs (e.g., if either of the image name/version params are set, require ComputeGalleryName too) to prevent unexpected output artifacts.

Suggested change
if ($ComputeGalleryImageVersion -and -not ($ComputeGalleryImageVersion -match '^\d+\.\d+\.\d+$')) {
if ($ComputeGalleryImageName -and -not $ComputeGalleryName) {
throw "ComputeGalleryName parameter is required when ComputeGalleryImageName is specified."
}
if ($ComputeGalleryImageVersion -and -not $ComputeGalleryName) {
throw "ComputeGalleryName parameter is required when ComputeGalleryImageVersion is specified."
}
if ($ComputeGalleryName -and $ComputeGalleryImageVersion -and -not ($ComputeGalleryImageVersion -match '^\d+\.\d+\.\d+$')) {

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If wanting to do complete validation rather than silently ignore, we could do a more comprehensive check of all scenarios using an array of the 3 inputs, select non-empty and then length -eq 0 or length -eq 3.

Not sure if this is worthwhile as it looks pretty messy, but may give extra validation for people mis-inputting the parameters.

throw "ComputeGalleryImageVersion parameter must be in the format Major.Minor.Patch, for example: 1.0.0."
}

# Get template path
$PackerTemplate = Get-PackerTemplate -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType
Write-Debug "Template path: $($PackerTemplate.Path)."
Expand Down Expand Up @@ -204,6 +228,25 @@ Function GenerateResourcesAndImage {
}
Write-Debug "Tags JSON: $TagsJson."

# Prepare artifact arguments
if ($ComputeGalleryName) {
Write-Host "Compute gallery '$ComputeGalleryName' will be used to store the resulting image."
$artifactArgs = @(
"-var=gallery_name=$($ComputeGalleryName)",
"-var=gallery_image_name=$($ComputeGalleryImageName)",
"-var=gallery_image_version=$($ComputeGalleryImageVersion)",
"-var=gallery_resource_group_name=$($ResourceGroupName)"
)
}
else {
Write-Host "A managed image with name '$ManagedImageName' will be created to store the resulting image."
$artifactArgs = @(
"-var=managed_image_name=$($ManagedImageName)",
"-var=managed_image_resource_group_name=$($ResourceGroupName)"
)
}


$InstallPassword = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()

Write-Host "Downloading packer plugins..."
Expand All @@ -222,8 +265,7 @@ Function GenerateResourcesAndImage {
"-var=tenant_id=fake" `
"-var=location=$($AzureLocation)" `
"-var=image_os=$($PackerTemplate.ImageOS)" `
"-var=managed_image_name=$($ManagedImageName)" `
"-var=managed_image_resource_group_name=$($ResourceGroupName)" `
@artifactArgs `
"-var=install_password=$($InstallPassword)" `
"-var=allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" `
"-var=azure_tags=$($TagsJson)" `
Expand Down Expand Up @@ -257,6 +299,25 @@ Function GenerateResourcesAndImage {
throw "Resource group '$ResourceGroupName' does not exist."
}

# Check compute gallery and image definition existence
if ($ComputeGalleryName) {
$ComputeGalleryExists = az sig show --resource-group $ResourceGroupName --gallery-name $ComputeGalleryName --query "id" --output tsv 2>$null;
if ($ComputeGalleryExists) {
Write-Verbose "Compute gallery '$ComputeGalleryName' already exists in resource group '$ResourceGroupName'."
}
else {
throw "Compute gallery '$ComputeGalleryName' does not exist in resource group '$ResourceGroupName'."
}

$ImageDefinitionExists = az sig image-definition show --resource-group $ResourceGroupName --gallery-name $ComputeGalleryName --name $ComputeGalleryImageName --query "id" --output tsv 2>$null;
if ($ImageDefinitionExists) {
Write-Verbose "Compute gallery image definition '$ComputeGalleryImageName' already exists in compute gallery '$ComputeGalleryName'."
}
else {
throw "Compute gallery image definition '$ComputeGalleryImageName' does not exist in compute gallery '$ComputeGalleryName'."
}
}

# Create service principal
if ([string]::IsNullOrEmpty($AzureClientId)) {
Write-Host "Creating service principal for packer..."
Expand Down Expand Up @@ -292,8 +353,7 @@ Function GenerateResourcesAndImage {
-var "tenant_id=$($TenantId)" `
-var "location=$($AzureLocation)" `
-var "image_os=$($PackerTemplate.ImageOS)" `
-var "managed_image_name=$($ManagedImageName)" `
-var "managed_image_resource_group_name=$($ResourceGroupName)" `
@artifactArgs `
-var "install_password=$($InstallPassword)" `
-var "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" `
-var "azure_tags=$($TagsJson)" `
Expand Down