DSC icon indicating copy to clipboard operation
DSC copied to clipboard

Copy (loop) function array/object and conditionals

Open ThomasNieto opened this issue 2 months ago • 4 comments

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 avatar Oct 10 '25 16:10 ThomasNieto

@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.

SteveL-MSFT avatar Oct 10 '25 17:10 SteveL-MSFT

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 count property 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).

Gijsreyn avatar Oct 11 '25 03:10 Gijsreyn

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).

Gijsreyn avatar Oct 11 '25 03:10 Gijsreyn

The only thing missing is adding support for copy for properties which I'll do next.

SteveL-MSFT avatar Oct 11 '25 20:10 SteveL-MSFT