Copy (loop) function array/object and conditionals
Summary of the new feature / enhancement
In BICEP users can loop through a collection or object (dictionary). The loop condition would also be very useful.
These kind of loops are a very common pattern to loop through a collection or object (dictionary) in order to set the same value.
Proposed technical implementation details (optional)
No response
@ThomasNieto can you show an example of what the Bicep looks like and the resulting JSON template? The doc link only shows the Bicep side.
Just chipping in my two cents here. If this is what you meant Thomas:
targetScope = 'desiredStateConfiguration'
// Parameter object containing registry values to manage
param registryValues object = {
items: [
{
name: 'ExampleString'
keyPath: 'HKCU\\DscExamples'
valueName: 'StringValue'
valueData: {
String: 'Hello from DSC'
}
}
{
name: 'ExampleDWord'
keyPath: 'HKCU\\DscExamples'
valueName: 'DWordValue'
valueData: {
DWord: 42
}
}
{
name: 'ExampleExpandString'
keyPath: 'HKCU\\DscExamples\\Config'
valueName: 'PathValue'
valueData: {
ExpandString: '%USERPROFILE%\\Documents'
}
}
{
name: 'ExampleMultiString'
keyPath: 'HKCU\\DscExamples\\Config'
valueName: 'ListValue'
valueData: {
MultiString: [
'Item1'
'Item2'
'Item3'
]
}
}
]
}
// Loop over the registry values and create a resource for each
resource registryConfigs 'Microsoft.Windows/Registry@2025-08-27' = [for item in registryValues.items: {
name: item.name
properties: {
keyPath: item.keyPath
valueName: item.valueName
valueData: item.valueData
_exist: true
}
}]
It converts it to JSON like this:
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/config/document.json",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.38.3.11034",
"templateHash": "9985521513055688686"
}
},
"parameters": {
"registryValues": {
"type": "object",
"defaultValue": {
"items": [
{
"name": "ExampleString",
"keyPath": "HKCU\\DscExamples",
"valueName": "StringValue",
"valueData": {
"String": "Hello from DSC"
}
},
{
"name": "ExampleDWord",
"keyPath": "HKCU\\DscExamples",
"valueName": "DWordValue",
"valueData": {
"DWord": 42
}
},
{
"name": "ExampleExpandString",
"keyPath": "HKCU\\DscExamples\\Config",
"valueName": "PathValue",
"valueData": {
"ExpandString": "%USERPROFILE%\\Documents"
}
},
{
"name": "ExampleMultiString",
"keyPath": "HKCU\\DscExamples\\Config",
"valueName": "ListValue",
"valueData": {
"MultiString": [
"Item1",
"Item2",
"Item3"
]
}
}
]
}
}
},
"resources": [
{
"copy": {
"name": "registryConfigs",
"count": "[length(parameters('registryValues').items)]"
},
"type": "Microsoft.Windows/Registry",
"apiVersion": "2025-08-27",
"name": "[parameters('registryValues').items[copyIndex()].name]",
"properties": {
"keyPath": "[parameters('registryValues').items[copyIndex()].keyPath]",
"valueName": "[parameters('registryValues').items[copyIndex()].valueName]",
"valueData": "[parameters('registryValues').items[copyIndex()].valueData]",
"_exist": true
}
}
]
}
Now, there's already a standing issue seen from Steve's comment on #1118. If you remove the apiVersion, it reveals two other issues:
- The
countproperty expects an integer value, even though I would say that it should evaluate the expression and that should return the integer. - The second issue is when it reaches the
copyIndex()call on properties, it doesn't work (Parser: The 'copyIndex()' function can only be used when processing a 'Copy' loop).
One more different example when talking with Thomas:
// Bicep configuration to manage multiple registry values using a loop
// This demonstrates using parameters with the Microsoft.Windows/Registry resource
targetScope = 'desiredStateConfiguration'
// Parameter object containing registry values to manage
param registryValues object = {
stringValue: {
name: 'ExampleString'
keyPath: 'HKCU\\DscExamples'
valueName: 'StringValue'
valueData: {
String: 'Hello from DSC'
}
}
dwordValue: {
name: 'ExampleDWord'
keyPath: 'HKCU\\DscExamples'
valueName: 'DWordValue'
valueData: {
DWord: 42
}
}
expandStringValue: {
name: 'ExampleExpandString'
keyPath: 'HKCU\\DscExamples\\Config'
valueName: 'PathValue'
valueData: {
ExpandString: '%USERPROFILE%\\Documents'
}
}
multiStringValue: {
name: 'ExampleMultiString'
keyPath: 'HKCU\\DscExamples\\Config'
valueName: 'ListValue'
valueData: {
MultiString: [
'Item1'
'Item2'
'Item3'
]
}
}
}
// Loop over the registry values using items() and create a resource for each
resource registryConfigs 'Microsoft.Windows/Registry@2025-08-27' = [for reg in items(registryValues): {
name: reg.value.name
properties: {
keyPath: reg.value.keyPath
valueName: reg.value.valueName
valueData: reg.value.valueData
_exist: true
}
}]
This is where we require the items() function (seen on the list at #57).
The only thing missing is adding support for copy for properties which I'll do next.