From 0af816f1e3075c372239ecf9b8c67349ade2f2cc Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Tue, 7 Apr 2026 15:15:27 +0200 Subject: [PATCH 01/13] Added support for existing resource groups --- images.CI/linux-and-win/build-image.ps1 | 91 +++++++++++++++++-------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/images.CI/linux-and-win/build-image.ps1 b/images.CI/linux-and-win/build-image.ps1 index fa4dac9191..5b81316320 100644 --- a/images.CI/linux-and-win/build-image.ps1 +++ b/images.CI/linux-and-win/build-image.ps1 @@ -1,12 +1,14 @@ +[CmdletBinding(DefaultParameterSetName = 'TempResourceGroup')] param( [String] [Parameter (Mandatory=$true)] $TemplatePath, [String] [Parameter (Mandatory=$true)] $BuildTemplateName, [String] [Parameter (Mandatory=$true)] $ClientId, [String] [Parameter (Mandatory=$false)] $ClientSecret, - [String] [Parameter (Mandatory=$true)] $Location, + [String] [Parameter (Mandatory=$true, ParameterSetName = 'TempResourceGroup')] $Location, [String] [Parameter (Mandatory=$true)] $ImageName, [String] [Parameter (Mandatory=$true)] $ImageResourceGroupName, - [String] [Parameter (Mandatory=$true)] $TempResourceGroupName, + [String] [Parameter (Mandatory=$true, ParameterSetName = 'TempResourceGroup')] $TempResourceGroupName, + [String] [Parameter (Mandatory=$true, ParameterSetName = 'ExistingResourceGroup')] $ExistingResourceGroupName, [String] [Parameter (Mandatory=$true)] $SubscriptionId, [String] [Parameter (Mandatory=$true)] $TenantId, [String] [Parameter (Mandatory=$true)] $ImageOS, # e.g. "ubuntu22", "ubuntu24" or "win22", "win25" @@ -50,28 +52,63 @@ Write-Host "Validate packer template" packer validate -syntax-only -only "$buildName*" $TemplatePath Write-Host "Build $buildName VM" -packer build -only "$buildName*" ` - -var "client_id=$ClientId" ` - -var "client_secret=$ClientSecret" ` - -var "install_password=$InstallPassword" ` - -var "location=$Location" ` - -var "image_os=$ImageOS" ` - -var "managed_image_name=$ImageName" ` - -var "managed_image_resource_group_name=$ImageResourceGroupName" ` - -var "subscription_id=$SubscriptionId" ` - -var "temp_resource_group_name=$TempResourceGroupName" ` - -var "tenant_id=$TenantId" ` - -var "virtual_network_name=$VirtualNetworkName" ` - -var "virtual_network_resource_group_name=$VirtualNetworkRG" ` - -var "virtual_network_subnet_name=$VirtualNetworkSubnet" ` - -var "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" ` - -var "use_azure_cli_auth=$UseAzureCliAuth" ` - -var "azure_tags=$azure_tags" ` - -color=false ` - $TemplatePath ` - | Where-Object { - #Filter sensitive data from Packer logs - $currentString = $_ - $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } - $sensitiveString -eq $null - } + +switch ($PSCmdlet.ParameterSetName) { + 'TempResourceGroup' { + Write-Host "Use temporary resource group $TempResourceGroupName" + packer build -only "$buildName*" ` + -var "client_id=$ClientId" ` + -var "client_secret=$ClientSecret" ` + -var "install_password=$InstallPassword" ` + -var "location=$Location" ` + -var "image_os=$ImageOS" ` + -var "managed_image_name=$ImageName" ` + -var "managed_image_resource_group_name=$ImageResourceGroupName" ` + -var "subscription_id=$SubscriptionId" ` + -var "temp_resource_group_name=$TempResourceGroupName" ` + -var "tenant_id=$TenantId" ` + -var "virtual_network_name=$VirtualNetworkName" ` + -var "virtual_network_resource_group_name=$VirtualNetworkRG" ` + -var "virtual_network_subnet_name=$VirtualNetworkSubnet" ` + -var "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" ` + -var "use_azure_cli_auth=$UseAzureCliAuth" ` + -var "azure_tags=$azure_tags" ` + -color=false ` + $TemplatePath ` + | Where-Object { + #Filter sensitive data from Packer logs + $currentString = $_ + $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } + $sensitiveString -eq $null + } + break + } + 'ExistingResourceGroup' { + Write-Host "Use existing resource group $ExistingResourceGroupName" + packer build -only "$buildName*" ` + -var "client_id=$ClientId" ` + -var "client_secret=$ClientSecret" ` + -var "install_password=$InstallPassword" ` + -var "image_os=$ImageOS" ` + -var "managed_image_name=$ImageName" ` + -var "managed_image_resource_group_name=$ImageResourceGroupName" ` + -var "subscription_id=$SubscriptionId" ` + -var "build_resource_group_name=$ExistingResourceGroupName" ` + -var "tenant_id=$TenantId" ` + -var "virtual_network_name=$VirtualNetworkName" ` + -var "virtual_network_resource_group_name=$VirtualNetworkRG" ` + -var "virtual_network_subnet_name=$VirtualNetworkSubnet" ` + -var "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" ` + -var "use_azure_cli_auth=$UseAzureCliAuth" ` + -var "azure_tags=$azure_tags" ` + -color=false ` + $TemplatePath ` + | Where-Object { + #Filter sensitive data from Packer logs + $currentString = $_ + $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } + $sensitiveString -eq $null + } + break + } +} From 6a8fbe9cb8afa6093682c4073cb143a32655bb02 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Thu, 9 Apr 2026 17:19:25 +0200 Subject: [PATCH 02/13] Added pester tests --- .github/workflows/powershell-tests.yml | 8 +- .../linux-and-win/tests/build-image.Tests.ps1 | 96 +++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 images.CI/linux-and-win/tests/build-image.Tests.ps1 diff --git a/.github/workflows/powershell-tests.yml b/.github/workflows/powershell-tests.yml index 88b7a88eda..2030c220db 100644 --- a/.github/workflows/powershell-tests.yml +++ b/.github/workflows/powershell-tests.yml @@ -7,6 +7,7 @@ on: branches: [ main ] paths: - 'helpers/software-report-base/**' + - 'images.CI/linux-and-win/**' jobs: powershell-tests: @@ -22,4 +23,9 @@ jobs: run: | $ErrorActionPreference = "Stop" Invoke-Pester -Output Detailed "helpers/software-report-base/tests" - \ No newline at end of file + + - name: Run linux-and-win scripts tests + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + Invoke-Pester -Output Detailed "images.CI/linux-and-win/tests" diff --git a/images.CI/linux-and-win/tests/build-image.Tests.ps1 b/images.CI/linux-and-win/tests/build-image.Tests.ps1 new file mode 100644 index 0000000000..997cae52a2 --- /dev/null +++ b/images.CI/linux-and-win/tests/build-image.Tests.ps1 @@ -0,0 +1,96 @@ +Describe "build-image.ps1 parameter sets" { + BeforeAll { + $scriptPath = (Resolve-Path (Join-Path $PSScriptRoot "..\build-image.ps1")).Path + $command = Get-Command -Name $scriptPath + } + + It "defines exactly two parameter sets" { + $command.ParameterSets | Should -HaveCount 2 + } + + It "requires temp resource group parameters in TempResourceGroup set" { + $tempSet = $command.ParameterSets | Where-Object Name -eq "TempResourceGroup" + $tempSet | Should -Not -BeNullOrEmpty + + ($tempSet.Parameters | Where-Object Name -eq "Location") | Should -Not -BeNullOrEmpty + ($tempSet.Parameters | Where-Object Name -eq "Location").IsMandatory | Should -BeTrue + + ($tempSet.Parameters | Where-Object Name -eq "TempResourceGroupName") | Should -Not -BeNullOrEmpty + ($tempSet.Parameters | Where-Object Name -eq "TempResourceGroupName").IsMandatory | Should -BeTrue + + $tempSet.Parameters.Name | Should -Not -Contain "ExistingResourceGroupName" + } + + It "requires existing resource group parameter in ExistingResourceGroup set" { + $existingSet = $command.ParameterSets | Where-Object Name -eq "ExistingResourceGroup" + $existingSet | Should -Not -BeNullOrEmpty + + ($existingSet.Parameters | Where-Object Name -eq "ExistingResourceGroupName") | Should -Not -BeNullOrEmpty + ($existingSet.Parameters | Where-Object Name -eq "ExistingResourceGroupName").IsMandatory | Should -BeTrue + + $existingSet.Parameters.Name | Should -Not -Contain "Location" + $existingSet.Parameters.Name | Should -Not -Contain "TempResourceGroupName" + } +} + +Describe "build-image.ps1 switch" { + BeforeAll { + $scriptPath = (Resolve-Path (Join-Path $PSScriptRoot "..\build-image.ps1")).Path + $global:packerInvocations = @() + + function global:packer { + param( + [Parameter(ValueFromRemainingArguments = $true)] + [string[]] $Arguments + ) + + $global:packerInvocations += ,$Arguments + "mocked packer output" + } + + Mock -CommandName Write-Host + } + + AfterAll { + Remove-Item function:\global:packer -ErrorAction SilentlyContinue + } + + Context "TempResourceGroup" { + It "calls packer build with temp resource group parameters" { + + & $scriptPath -TemplatePath ".\" ` + -BuildTemplateName "template.TestBuild" ` + -TempResourceGroupName "TestTempRG" ` + -ClientId "TestClientId" ` + -Location "TestLocation" ` + -ImageName "TestImage" ` + -ImageResourceGroupName "TestImageRG" ` + -SubscriptionId "TestSubId" ` + -TenantId "TestTenantId" ` + -ImageOS "TestOS" | Out-Null + + Should -Invoke -CommandName Write-Host -Times 1 -Exactly -ParameterFilter { + $Object -eq "Use temporary resource group TestTempRG" + } + } + } + + Context "ExistingResourceGroup" { + It "calls packer build with existing resource group parameters" { + + & $scriptPath -TemplatePath ".\" ` + -BuildTemplateName "template.TestBuild" ` + -ExistingResourceGroupName "TestExistingRG" ` + -ClientId "TestClientId" ` + -ImageName "TestImage" ` + -ImageResourceGroupName "TestImageRG" ` + -SubscriptionId "TestSubId" ` + -TenantId "TestTenantId" ` + -ImageOS "TestOS" | Out-Null + + Should -Invoke -CommandName Write-Host -Times 1 -Exactly -ParameterFilter { + $Object -eq "Use existing resource group TestExistingRG" + } + } + } +} From c1e91fb53dbea60b882834f6fffdde79b6f266fa Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Mon, 13 Apr 2026 08:57:46 +0200 Subject: [PATCH 03/13] Removed whitespaces --- .github/workflows/powershell-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/powershell-tests.yml b/.github/workflows/powershell-tests.yml index 2030c220db..7d33170ea0 100644 --- a/.github/workflows/powershell-tests.yml +++ b/.github/workflows/powershell-tests.yml @@ -23,7 +23,7 @@ jobs: run: | $ErrorActionPreference = "Stop" Invoke-Pester -Output Detailed "helpers/software-report-base/tests" - + - name: Run linux-and-win scripts tests shell: pwsh run: | From 03f8644baef7b1e775f50920ecfd181ceae8d1ba Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Mon, 13 Apr 2026 11:04:37 +0200 Subject: [PATCH 04/13] Refactor to remove duplication in passing variables to packer --- images.CI/linux-and-win/build-image.ps1 | 82 ++++++++++--------------- 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/images.CI/linux-and-win/build-image.ps1 b/images.CI/linux-and-win/build-image.ps1 index 5b81316320..4d8fac9946 100644 --- a/images.CI/linux-and-win/build-image.ps1 +++ b/images.CI/linux-and-win/build-image.ps1 @@ -51,64 +51,46 @@ packer plugins install github.com/hashicorp/azure $pluginVersion Write-Host "Validate packer template" packer validate -syntax-only -only "$buildName*" $TemplatePath -Write-Host "Build $buildName VM" +$packerVariableFlag = "-var" +$packerVariables = "$packerVariableFlag", "client_id=$ClientId", ` + "$packerVariableFlag", "client_secret=$ClientSecret", ` + "$packerVariableFlag", "install_password=$InstallPassword", ` + "$packerVariableFlag", "image_os=$ImageOS", ` + "$packerVariableFlag", "managed_image_name=$ImageName", ` + "$packerVariableFlag", "managed_image_resource_group_name=$ImageResourceGroupName", ` + "$packerVariableFlag", "subscription_id=$SubscriptionId", ` + "$packerVariableFlag", "tenant_id=$TenantId", ` + "$packerVariableFlag", "virtual_network_name=$VirtualNetworkName", ` + "$packerVariableFlag", "virtual_network_resource_group_name=$VirtualNetworkRG", ` + "$packerVariableFlag", "virtual_network_subnet_name=$VirtualNetworkSubnet", ` + "$packerVariableFlag", "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)", ` + "$packerVariableFlag", "use_azure_cli_auth=$UseAzureCliAuth", ` + "$packerVariableFlag", "azure_tags=$azure_tags" ` switch ($PSCmdlet.ParameterSetName) { 'TempResourceGroup' { Write-Host "Use temporary resource group $TempResourceGroupName" - packer build -only "$buildName*" ` - -var "client_id=$ClientId" ` - -var "client_secret=$ClientSecret" ` - -var "install_password=$InstallPassword" ` - -var "location=$Location" ` - -var "image_os=$ImageOS" ` - -var "managed_image_name=$ImageName" ` - -var "managed_image_resource_group_name=$ImageResourceGroupName" ` - -var "subscription_id=$SubscriptionId" ` - -var "temp_resource_group_name=$TempResourceGroupName" ` - -var "tenant_id=$TenantId" ` - -var "virtual_network_name=$VirtualNetworkName" ` - -var "virtual_network_resource_group_name=$VirtualNetworkRG" ` - -var "virtual_network_subnet_name=$VirtualNetworkSubnet" ` - -var "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" ` - -var "use_azure_cli_auth=$UseAzureCliAuth" ` - -var "azure_tags=$azure_tags" ` - -color=false ` - $TemplatePath ` - | Where-Object { - #Filter sensitive data from Packer logs - $currentString = $_ - $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } - $sensitiveString -eq $null - } + $packerVariables += "$packerVariableFlag", "temp_resource_group_name=$TempResourceGroupName", ` + "$packerVariableFlag", "location=$Location" + break } 'ExistingResourceGroup' { Write-Host "Use existing resource group $ExistingResourceGroupName" - packer build -only "$buildName*" ` - -var "client_id=$ClientId" ` - -var "client_secret=$ClientSecret" ` - -var "install_password=$InstallPassword" ` - -var "image_os=$ImageOS" ` - -var "managed_image_name=$ImageName" ` - -var "managed_image_resource_group_name=$ImageResourceGroupName" ` - -var "subscription_id=$SubscriptionId" ` - -var "build_resource_group_name=$ExistingResourceGroupName" ` - -var "tenant_id=$TenantId" ` - -var "virtual_network_name=$VirtualNetworkName" ` - -var "virtual_network_resource_group_name=$VirtualNetworkRG" ` - -var "virtual_network_subnet_name=$VirtualNetworkSubnet" ` - -var "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)" ` - -var "use_azure_cli_auth=$UseAzureCliAuth" ` - -var "azure_tags=$azure_tags" ` - -color=false ` - $TemplatePath ` - | Where-Object { - #Filter sensitive data from Packer logs - $currentString = $_ - $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } - $sensitiveString -eq $null - } + $packerVariables += "$packerVariableFlag", "existing_resource_group_name=$ExistingResourceGroupName" + break } } + +Write-Host "Build $buildName VM" +packer build -only "$buildName*" ` + @packerVariables ` + -color=false ` + $TemplatePath ` + | Where-Object { + #Filter sensitive data from Packer logs + $currentString = $_ + $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } + $sensitiveString -eq $null + } From fd762816dde1af44e9598d10344abf903a16c1d3 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Mon, 13 Apr 2026 12:02:23 +0200 Subject: [PATCH 05/13] Fixed packer variable for build_resource_group_name --- images.CI/linux-and-win/build-image.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images.CI/linux-and-win/build-image.ps1 b/images.CI/linux-and-win/build-image.ps1 index 4d8fac9946..f6fbd0074f 100644 --- a/images.CI/linux-and-win/build-image.ps1 +++ b/images.CI/linux-and-win/build-image.ps1 @@ -77,7 +77,7 @@ switch ($PSCmdlet.ParameterSetName) { } 'ExistingResourceGroup' { Write-Host "Use existing resource group $ExistingResourceGroupName" - $packerVariables += "$packerVariableFlag", "existing_resource_group_name=$ExistingResourceGroupName" + $packerVariables += "$packerVariableFlag", "build_resource_group_name=$ExistingResourceGroupName" break } From 4061d3b64d476782e34732de598a07e021353778 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Mon, 13 Apr 2026 12:15:23 +0200 Subject: [PATCH 06/13] Updated documentation packer variables --- docs/create-image-and-azure-resources.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/create-image-and-azure-resources.md b/docs/create-image-and-azure-resources.md index ce84d62c6c..99bbc7e5d7 100644 --- a/docs/create-image-and-azure-resources.md +++ b/docs/create-image-and-azure-resources.md @@ -235,7 +235,6 @@ The following variables are required to be passed to the Packer process: | `client_id` | `ARM_CLIENT_ID` | The Active Directory service principal associated with your builder. | `client_secret` | `ARM_CLIENT_SECRET` | The password or secret for your service principal; may be omitted if `client_cert_path` is set. | `client_cert_path` | `ARM_CLIENT_CERT_PATH` | The location of a PEM file containing a certificate and private key for the service principal; may be omitted if `client_secret` is set. -| `location` | `ARM_RESOURCE_LOCATION` | The Azure datacenter in which your VM will be built. | `managed_image_resource_group_name` | `ARM_RESOURCE_GROUP` | The resource group under which the final artifact will be stored. ### Optional variables @@ -246,7 +245,8 @@ The following variables are optional: - `build_resource_group_name` - specify an existing resource group to run the build in; by default, a temporary resource group will be created and destroyed as part of the build; if you do not have permission to do so, use `build_resource_group_name` to specify an existing resource group to run the build in; - `object_id` - the object ID for the AAD SP; will be derived from the oAuth token if empty; - `tenant_id` - the Active Directory tenant identifier with which your `client_id` and `subscription_id` are associated; if not specified, `tenant_id` will be looked up using `subscription_id`; -- `temp_resource_group_name` - the name assigned to the temporary resource group created during the build; if this value is not set, a random value will be assigned; this resource group is deleted at the end of the build; +- `location` | `ARM_RESOURCE_LOCATION` | The Azure datacenter in which your VM will be built; required if the build is in a temporary resource group; not allowed to be used in combination with `build_resource_group_name` +- `temp_resource_group_name` - the name assigned to the temporary resource group created during the build; if this value is not set, a random value will be assigned; this resource group is deleted at the end of the build; not allowed to be used in combination with `build_resource_group_name` - `private_virtual_network_with_public_ip` - this value allows you to set a `virtual_network_name` and obtain a public IP; if this value is not set and `virtual_network_name` is defined, Packer is only allowed to be executed from a host on the same subnet / virtual network; - `virtual_network_name` - use a pre-existing virtual network for the VM; this option enables private communication with the VM, no public IP address is used or provisioned (unless you set `private_virtual_network_with_public_ip`); - `virtual_network_resource_group_name` - if `virtual_network_name` is set, this value may also be set; if `virtual_network_name` is set, and this value is not set, the builder attempts to determine the resource group containing the virtual network; if the resource group cannot be found, or it cannot be disambiguated, this value should be set; From c4428f47729408c25cf0dd665332304a49c09814 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Tue, 14 Apr 2026 13:27:13 +0200 Subject: [PATCH 07/13] added function to add -var flag --- images.CI/linux-and-win/build-image.ps1 | 57 ++++++++++++++++--------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/images.CI/linux-and-win/build-image.ps1 b/images.CI/linux-and-win/build-image.ps1 index f6fbd0074f..91091b0000 100644 --- a/images.CI/linux-and-win/build-image.ps1 +++ b/images.CI/linux-and-win/build-image.ps1 @@ -42,6 +42,20 @@ $SensitiveData = @( $azure_tags = $Tags | ConvertTo-Json -Compress +function Add-PackerVariableFlag { + param( + [String[]]$packerVariables + ) + + $result = @() + + foreach ($packerVariable in $packerVariables) { + $result += "-var", $packerVariable + } + + return $result +} + Write-Host "Show Packer Version" packer --version @@ -51,33 +65,38 @@ packer plugins install github.com/hashicorp/azure $pluginVersion Write-Host "Validate packer template" packer validate -syntax-only -only "$buildName*" $TemplatePath -$packerVariableFlag = "-var" -$packerVariables = "$packerVariableFlag", "client_id=$ClientId", ` - "$packerVariableFlag", "client_secret=$ClientSecret", ` - "$packerVariableFlag", "install_password=$InstallPassword", ` - "$packerVariableFlag", "image_os=$ImageOS", ` - "$packerVariableFlag", "managed_image_name=$ImageName", ` - "$packerVariableFlag", "managed_image_resource_group_name=$ImageResourceGroupName", ` - "$packerVariableFlag", "subscription_id=$SubscriptionId", ` - "$packerVariableFlag", "tenant_id=$TenantId", ` - "$packerVariableFlag", "virtual_network_name=$VirtualNetworkName", ` - "$packerVariableFlag", "virtual_network_resource_group_name=$VirtualNetworkRG", ` - "$packerVariableFlag", "virtual_network_subnet_name=$VirtualNetworkSubnet", ` - "$packerVariableFlag", "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)", ` - "$packerVariableFlag", "use_azure_cli_auth=$UseAzureCliAuth", ` - "$packerVariableFlag", "azure_tags=$azure_tags" ` +$packerVariablesList = Add-PackerVariableFlag -packerVariables @( + "client_id=$ClientId", + "client_secret=$ClientSecret", + "install_password=$InstallPassword", + "image_os=$ImageOS", + "managed_image_name=$ImageName", + "managed_image_resource_group_name=$ImageResourceGroupName", + "subscription_id=$SubscriptionId", + "tenant_id=$TenantId", + "virtual_network_name=$VirtualNetworkName", + "virtual_network_resource_group_name=$VirtualNetworkRG", + "virtual_network_subnet_name=$VirtualNetworkSubnet", + "allowed_inbound_ip_addresses=$($AllowedInboundIpAddresses)", + "use_azure_cli_auth=$UseAzureCliAuth", + "azure_tags=$azure_tags" + ) switch ($PSCmdlet.ParameterSetName) { 'TempResourceGroup' { Write-Host "Use temporary resource group $TempResourceGroupName" - $packerVariables += "$packerVariableFlag", "temp_resource_group_name=$TempResourceGroupName", ` - "$packerVariableFlag", "location=$Location" + $packerVariablesList += Add-PackerVariableFlag -packerVariables @( + "temp_resource_group_name=$TempResourceGroupName", + "location=$Location" + ) break } 'ExistingResourceGroup' { Write-Host "Use existing resource group $ExistingResourceGroupName" - $packerVariables += "$packerVariableFlag", "build_resource_group_name=$ExistingResourceGroupName" + $packerVariablesList += Add-PackerVariableFlag -packerVariables @( + "build_resource_group_name=$ExistingResourceGroupName" + ) break } @@ -85,7 +104,7 @@ switch ($PSCmdlet.ParameterSetName) { Write-Host "Build $buildName VM" packer build -only "$buildName*" ` - @packerVariables ` + @packerVariablesList ` -color=false ` $TemplatePath ` | Where-Object { From 478aa59ddb56f881490b61a9a961726979391012 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Tue, 14 Apr 2026 13:56:47 +0200 Subject: [PATCH 08/13] Added packer argument checks in current pester switch tests --- .../linux-and-win/tests/build-image.Tests.ps1 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/images.CI/linux-and-win/tests/build-image.Tests.ps1 b/images.CI/linux-and-win/tests/build-image.Tests.ps1 index 997cae52a2..59c9cb1f13 100644 --- a/images.CI/linux-and-win/tests/build-image.Tests.ps1 +++ b/images.CI/linux-and-win/tests/build-image.Tests.ps1 @@ -36,9 +36,9 @@ Describe "build-image.ps1 parameter sets" { Describe "build-image.ps1 switch" { BeforeAll { $scriptPath = (Resolve-Path (Join-Path $PSScriptRoot "..\build-image.ps1")).Path - $global:packerInvocations = @() - function global:packer { + Mock -CommandName Write-Host + Mock -CommandName packer -MockWith { param( [Parameter(ValueFromRemainingArguments = $true)] [string[]] $Arguments @@ -47,8 +47,6 @@ Describe "build-image.ps1 switch" { $global:packerInvocations += ,$Arguments "mocked packer output" } - - Mock -CommandName Write-Host } AfterAll { @@ -72,6 +70,12 @@ Describe "build-image.ps1 switch" { Should -Invoke -CommandName Write-Host -Times 1 -Exactly -ParameterFilter { $Object -eq "Use temporary resource group TestTempRG" } + + Should -Invoke -CommandName packer -Times 1 -Exactly -ParameterFilter { + $Arguments -contains "temp_resource_group_name=TestTempRG" -and + $Arguments -contains "location=TestLocation" -and + $Arguments -contains "-var" + } } } @@ -91,6 +95,11 @@ Describe "build-image.ps1 switch" { Should -Invoke -CommandName Write-Host -Times 1 -Exactly -ParameterFilter { $Object -eq "Use existing resource group TestExistingRG" } + + Should -Invoke -CommandName packer -Times 1 -Exactly -ParameterFilter { + $Arguments -contains "build_resource_group_name=TestExistingRG" -and + $Arguments -contains "-var" + } } } } From b5a23a673a2196529e4ae85b0543e42cc1aa6191 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Wed, 15 Apr 2026 12:46:27 +0200 Subject: [PATCH 09/13] removed unused afterall --- .../linux-and-win/tests/build-image.Tests.ps1 | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/images.CI/linux-and-win/tests/build-image.Tests.ps1 b/images.CI/linux-and-win/tests/build-image.Tests.ps1 index 59c9cb1f13..1b8bd02cd0 100644 --- a/images.CI/linux-and-win/tests/build-image.Tests.ps1 +++ b/images.CI/linux-and-win/tests/build-image.Tests.ps1 @@ -38,21 +38,19 @@ Describe "build-image.ps1 switch" { $scriptPath = (Resolve-Path (Join-Path $PSScriptRoot "..\build-image.ps1")).Path Mock -CommandName Write-Host + + $global:packerInvocations = @() Mock -CommandName packer -MockWith { param( [Parameter(ValueFromRemainingArguments = $true)] - [string[]] $Arguments + [string[]] $arguments ) - $global:packerInvocations += ,$Arguments + $global:packerInvocations += ,$arguments "mocked packer output" } } - AfterAll { - Remove-Item function:\global:packer -ErrorAction SilentlyContinue - } - Context "TempResourceGroup" { It "calls packer build with temp resource group parameters" { @@ -72,9 +70,9 @@ Describe "build-image.ps1 switch" { } Should -Invoke -CommandName packer -Times 1 -Exactly -ParameterFilter { - $Arguments -contains "temp_resource_group_name=TestTempRG" -and - $Arguments -contains "location=TestLocation" -and - $Arguments -contains "-var" + $arguments -contains "temp_resource_group_name=TestTempRG" -and + $arguments -contains "location=TestLocation" -and + $arguments -contains "-var" } } } @@ -97,8 +95,8 @@ Describe "build-image.ps1 switch" { } Should -Invoke -CommandName packer -Times 1 -Exactly -ParameterFilter { - $Arguments -contains "build_resource_group_name=TestExistingRG" -and - $Arguments -contains "-var" + $arguments -contains "build_resource_group_name=TestExistingRG" -and + $arguments -contains "-var" } } } From f690ac92e34601a6245c04272e8be688d4718154 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Wed, 15 Apr 2026 13:14:31 +0200 Subject: [PATCH 10/13] Fix indentation --- images.CI/linux-and-win/build-image.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/images.CI/linux-and-win/build-image.ps1 b/images.CI/linux-and-win/build-image.ps1 index 91091b0000..8a5fe684d4 100644 --- a/images.CI/linux-and-win/build-image.ps1 +++ b/images.CI/linux-and-win/build-image.ps1 @@ -107,9 +107,9 @@ packer build -only "$buildName*" ` @packerVariablesList ` -color=false ` $TemplatePath ` - | Where-Object { - #Filter sensitive data from Packer logs - $currentString = $_ - $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } - $sensitiveString -eq $null - } + | Where-Object { + #Filter sensitive data from Packer logs + $currentString = $_ + $sensitiveString = $SensitiveData | Where-Object { $currentString -match $_ } + $sensitiveString -eq $null + } From b7d76e31dd7b70c44431db63367235c4ffcde2df Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Wed, 15 Apr 2026 13:17:35 +0200 Subject: [PATCH 11/13] Updated doc --- docs/create-image-and-azure-resources.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/create-image-and-azure-resources.md b/docs/create-image-and-azure-resources.md index 99bbc7e5d7..abac550160 100644 --- a/docs/create-image-and-azure-resources.md +++ b/docs/create-image-and-azure-resources.md @@ -242,11 +242,11 @@ The following variables are required to be passed to the Packer process: The following variables are optional: - `managed_image_name` - the name of the managed image to create. If not specified, "Runner-Image-{{ImageType}}" will be used; -- `build_resource_group_name` - specify an existing resource group to run the build in; by default, a temporary resource group will be created and destroyed as part of the build; if you do not have permission to do so, use `build_resource_group_name` to specify an existing resource group to run the build in; +- `build_resource_group_name` - specify an existing resource group to run the build in; by default, a temporary resource group will be created and destroyed as part of the build; if you do not have permission to do so, use `build_resource_group_name` to specify an existing resource group to run the build in; not allowed to be used in combination with `location` and `temp_resource_group_name`; - `object_id` - the object ID for the AAD SP; will be derived from the oAuth token if empty; - `tenant_id` - the Active Directory tenant identifier with which your `client_id` and `subscription_id` are associated; if not specified, `tenant_id` will be looked up using `subscription_id`; -- `location` | `ARM_RESOURCE_LOCATION` | The Azure datacenter in which your VM will be built; required if the build is in a temporary resource group; not allowed to be used in combination with `build_resource_group_name` -- `temp_resource_group_name` - the name assigned to the temporary resource group created during the build; if this value is not set, a random value will be assigned; this resource group is deleted at the end of the build; not allowed to be used in combination with `build_resource_group_name` +- `location` | `ARM_RESOURCE_LOCATION` | The Azure datacenter in which your VM will be built; required if the build is in a temporary resource group; not allowed to be used in combination with `build_resource_group_name`; +- `temp_resource_group_name` - the name assigned to the temporary resource group created during the build; if this value is not set, a random value will be assigned; this resource group is deleted at the end of the build; not allowed to be used in combination with `build_resource_group_name`; - `private_virtual_network_with_public_ip` - this value allows you to set a `virtual_network_name` and obtain a public IP; if this value is not set and `virtual_network_name` is defined, Packer is only allowed to be executed from a host on the same subnet / virtual network; - `virtual_network_name` - use a pre-existing virtual network for the VM; this option enables private communication with the VM, no public IP address is used or provisioned (unless you set `private_virtual_network_with_public_ip`); - `virtual_network_resource_group_name` - if `virtual_network_name` is set, this value may also be set; if `virtual_network_name` is set, and this value is not set, the builder attempts to determine the resource group containing the virtual network; if the resource group cannot be found, or it cannot be disambiguated, this value should be set; From 3e45df19499f15dce486f11fd524b00b78e7b377 Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Wed, 15 Apr 2026 13:19:22 +0200 Subject: [PATCH 12/13] Fixed doc typo --- docs/create-image-and-azure-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/create-image-and-azure-resources.md b/docs/create-image-and-azure-resources.md index abac550160..00f055d2dd 100644 --- a/docs/create-image-and-azure-resources.md +++ b/docs/create-image-and-azure-resources.md @@ -242,7 +242,7 @@ The following variables are required to be passed to the Packer process: The following variables are optional: - `managed_image_name` - the name of the managed image to create. If not specified, "Runner-Image-{{ImageType}}" will be used; -- `build_resource_group_name` - specify an existing resource group to run the build in; by default, a temporary resource group will be created and destroyed as part of the build; if you do not have permission to do so, use `build_resource_group_name` to specify an existing resource group to run the build in; not allowed to be used in combination with `location` and `temp_resource_group_name`; +- `build_resource_group_name` - specify an existing resource group to run the build in; by default, a temporary resource group will be created and destroyed as part of the build; if you do not have permission to do so, use `build_resource_group_name` to specify an existing resource group to run the build in; not allowed to be used in combination with `location` or `temp_resource_group_name`; - `object_id` - the object ID for the AAD SP; will be derived from the oAuth token if empty; - `tenant_id` - the Active Directory tenant identifier with which your `client_id` and `subscription_id` are associated; if not specified, `tenant_id` will be looked up using `subscription_id`; - `location` | `ARM_RESOURCE_LOCATION` | The Azure datacenter in which your VM will be built; required if the build is in a temporary resource group; not allowed to be used in combination with `build_resource_group_name`; From 9cdddc2fd61272f41ed25d6921a76cf35658844f Mon Sep 17 00:00:00 2001 From: Eduard Kuijpers Date: Wed, 15 Apr 2026 15:30:57 +0200 Subject: [PATCH 13/13] Fixed doc optional variables list --- docs/create-image-and-azure-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/create-image-and-azure-resources.md b/docs/create-image-and-azure-resources.md index 00f055d2dd..eca389ab6a 100644 --- a/docs/create-image-and-azure-resources.md +++ b/docs/create-image-and-azure-resources.md @@ -245,7 +245,7 @@ The following variables are optional: - `build_resource_group_name` - specify an existing resource group to run the build in; by default, a temporary resource group will be created and destroyed as part of the build; if you do not have permission to do so, use `build_resource_group_name` to specify an existing resource group to run the build in; not allowed to be used in combination with `location` or `temp_resource_group_name`; - `object_id` - the object ID for the AAD SP; will be derived from the oAuth token if empty; - `tenant_id` - the Active Directory tenant identifier with which your `client_id` and `subscription_id` are associated; if not specified, `tenant_id` will be looked up using `subscription_id`; -- `location` | `ARM_RESOURCE_LOCATION` | The Azure datacenter in which your VM will be built; required if the build is in a temporary resource group; not allowed to be used in combination with `build_resource_group_name`; +- `location` (env var `ARM_RESOURCE_LOCATION`) - The Azure datacenter in which your VM will be built; required if the build is in a temporary resource group; not allowed to be used in combination with `build_resource_group_name`; - `temp_resource_group_name` - the name assigned to the temporary resource group created during the build; if this value is not set, a random value will be assigned; this resource group is deleted at the end of the build; not allowed to be used in combination with `build_resource_group_name`; - `private_virtual_network_with_public_ip` - this value allows you to set a `virtual_network_name` and obtain a public IP; if this value is not set and `virtual_network_name` is defined, Packer is only allowed to be executed from a host on the same subnet / virtual network; - `virtual_network_name` - use a pre-existing virtual network for the VM; this option enables private communication with the VM, no public IP address is used or provisioned (unless you set `private_virtual_network_with_public_ip`);