Skip to content

Commit 6d62538

Browse files
authored
Merge pull request #1258 from Gijsreyn/gh-57/main/add-objectkey-function
Add `objectKeys()` function
2 parents 3092a0c + 131fb26 commit 6d62538

File tree

5 files changed

+479
-0
lines changed

5 files changed

+479
-0
lines changed
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
---
2+
description: Reference for the 'objectKeys' DSC configuration document function
3+
ms.date: 11/14/2025
4+
ms.topic: reference
5+
title: objectKeys
6+
---
7+
8+
## Synopsis
9+
10+
Returns an array containing all the keys from an object.
11+
12+
## Syntax
13+
14+
```Syntax
15+
objectKeys(<inputObject>)
16+
```
17+
18+
## Description
19+
20+
The `objectKeys()` function extracts all property names from an object and returns them as
21+
an array of strings. This function is useful for:
22+
23+
- Iterating over object properties when you only need the keys
24+
- Counting the number of properties in an object
25+
- Checking if specific keys exist in an object
26+
- Converting object keys for further processing
27+
28+
The function only returns the top-level keys of the object. For nested objects, only the
29+
outer keys are included in the result.
30+
31+
This function is similar to [`items()`][00], which returns both keys and values, while
32+
`objectKeys()` returns only the keys.
33+
34+
## Examples
35+
36+
### Example 1 - Extract keys from simple object
37+
38+
The following example extracts all keys from a simple object.
39+
40+
```yaml
41+
# objectKeys.example.1.dsc.config.yaml
42+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
43+
resources:
44+
- name: Echo
45+
type: Microsoft.DSC.Debug/Echo
46+
properties:
47+
output: "[objectKeys(createObject('firstName', 'John', 'lastName', 'Doe', 'age', 30))]"
48+
```
49+
50+
```bash
51+
dsc config get --file objectKeys.example.1.dsc.config.yaml
52+
```
53+
54+
```yaml
55+
results:
56+
- name: Echo
57+
type: Microsoft.DSC.Debug/Echo
58+
result:
59+
actualState:
60+
output:
61+
- firstName
62+
- lastName
63+
- age
64+
messages: []
65+
hadErrors: false
66+
```
67+
68+
### Example 2 - Count object properties
69+
70+
The following example uses `objectKeys()` with [`length()`][01] to count the number of
71+
properties in an object.
72+
73+
```yaml
74+
# objectKeys.example.2.dsc.config.yaml
75+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
76+
resources:
77+
- name: Echo
78+
type: Microsoft.DSC.Debug/Echo
79+
properties:
80+
output: "[length(objectKeys(createObject('a', 1, 'b', 2, 'c', 3)))]"
81+
```
82+
83+
```bash
84+
dsc config get --file objectKeys.example.2.dsc.config.yaml
85+
```
86+
87+
```yaml
88+
results:
89+
- name: Echo
90+
type: Microsoft.DSC.Debug/Echo
91+
result:
92+
actualState:
93+
output: 3
94+
messages: []
95+
hadErrors: false
96+
```
97+
98+
### Example 3 - Check if key exists
99+
100+
The following example uses `objectKeys()` with [`contains()`][02] to check if a specific
101+
key exists in an object.
102+
103+
```yaml
104+
# objectKeys.example.3.dsc.config.yaml
105+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
106+
parameters:
107+
config:
108+
type: object
109+
defaultValue:
110+
enabled: true
111+
timeout: 30
112+
resources:
113+
- name: Echo
114+
type: Microsoft.DSC.Debug/Echo
115+
properties:
116+
output:
117+
hasEnabled: "[contains(objectKeys(parameters('config')), 'enabled')]"
118+
hasDebug: "[contains(objectKeys(parameters('config')), 'debug')]"
119+
```
120+
121+
```bash
122+
dsc config get --file objectKeys.example.3.dsc.config.yaml
123+
```
124+
125+
```yaml
126+
results:
127+
- name: Echo
128+
type: Microsoft.DSC.Debug/Echo
129+
result:
130+
actualState:
131+
output:
132+
hasEnabled: true
133+
hasDebug: false
134+
messages: []
135+
hadErrors: false
136+
```
137+
138+
### Example 4 - Iterate over keys with copy loop
139+
140+
The following example uses `objectKeys()` to iterate over object properties using the
141+
[`copy`][03] feature.
142+
143+
```yaml
144+
# objectKeys.example.4.dsc.config.yaml
145+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
146+
parameters:
147+
settings:
148+
type: object
149+
defaultValue:
150+
debug: false
151+
logLevel: info
152+
maxRetries: 3
153+
resources:
154+
- name: "[format('Setting-{0}', copyIndex())]"
155+
copy:
156+
name: settingsLoop
157+
count: "[length(objectKeys(parameters('settings')))]"
158+
type: Microsoft.DSC.Debug/Echo
159+
properties:
160+
output: "[objectKeys(parameters('settings'))[copyIndex()]]"
161+
```
162+
163+
```bash
164+
dsc config get --file objectKeys.example.4.dsc.config.yaml
165+
```
166+
167+
```yaml
168+
results:
169+
- name: Setting-0
170+
type: Microsoft.DSC.Debug/Echo
171+
result:
172+
actualState:
173+
output: debug
174+
- name: Setting-1
175+
type: Microsoft.DSC.Debug/Echo
176+
result:
177+
actualState:
178+
output: logLevel
179+
- name: Setting-2
180+
type: Microsoft.DSC.Debug/Echo
181+
result:
182+
actualState:
183+
output: maxRetries
184+
messages: []
185+
hadErrors: false
186+
```
187+
188+
### Example 5 - Top-level keys only
189+
190+
The following example demonstrates that `objectKeys()` only returns top-level keys, even
191+
when the object contains nested objects.
192+
193+
```yaml
194+
# objectKeys.example.5.dsc.config.yaml
195+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
196+
resources:
197+
- name: Echo
198+
type: Microsoft.DSC.Debug/Echo
199+
properties:
200+
output: "[objectKeys(createObject('user', createObject('name', 'John', 'age', 30), 'role', 'admin'))]"
201+
```
202+
203+
```bash
204+
dsc config get --file objectKeys.example.5.dsc.config.yaml
205+
```
206+
207+
```yaml
208+
results:
209+
- name: Echo
210+
type: Microsoft.DSC.Debug/Echo
211+
result:
212+
actualState:
213+
output:
214+
- user
215+
- role
216+
messages: []
217+
hadErrors: false
218+
```
219+
220+
### Example 6 - Empty object
221+
222+
The following example shows that `objectKeys()` returns an empty array for an empty object.
223+
224+
```yaml
225+
# objectKeys.example.6.dsc.config.yaml
226+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
227+
resources:
228+
- name: Echo
229+
type: Microsoft.DSC.Debug/Echo
230+
properties:
231+
output:
232+
keys: "[objectKeys(createObject())]"
233+
isEmpty: "[equals(length(objectKeys(createObject())), 0)]"
234+
```
235+
236+
```bash
237+
dsc config get --file objectKeys.example.6.dsc.config.yaml
238+
```
239+
240+
```yaml
241+
results:
242+
- name: Echo
243+
type: Microsoft.DSC.Debug/Echo
244+
result:
245+
actualState:
246+
output:
247+
keys: []
248+
isEmpty: true
249+
messages: []
250+
hadErrors: false
251+
```
252+
253+
## Parameters
254+
255+
### inputObject
256+
257+
The object from which to extract the keys.
258+
259+
```yaml
260+
Type: object
261+
Required: true
262+
Position: 1
263+
```
264+
265+
## Output
266+
267+
Returns an array of strings, where each string is a property name (key) from the input
268+
object. The array contains only the top-level keys.
269+
270+
```yaml
271+
Type: array
272+
```
273+
274+
## Error conditions
275+
276+
The function will return an error in the following cases:
277+
278+
- **Not an object**: The input is not an object (e.g., string, number, array, null)
279+
280+
## Notes
281+
282+
- The function only returns top-level keys; nested object keys are not included
283+
- For empty objects, the function returns an empty array
284+
- The order of keys in the returned array follows JSON object property ordering
285+
- Key names are always returned as strings
286+
- To get both keys and values, use [`items()`][00] instead
287+
288+
## Related functions
289+
290+
- [`items()`][00] - Converts an object to an array of key-value pairs
291+
- [`createObject()`][04] - Creates an object from key-value pairs
292+
- [`length()`][01] - Returns the number of elements in an array
293+
- [`contains()`][02] - Checks if an array contains a specific value
294+
295+
<!-- Link reference definitions -->
296+
[00]: ./items.md
297+
[01]: ./length.md
298+
[02]: ./contains.md
299+
[03]: ../document/copy.md
300+
[04]: ./createObject.md

dsc/tests/dsc_functions.tests.ps1

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,46 @@ Describe 'tests for function expressions' {
958958
$out.results[0].result.actualState.output | Should -Be $expected
959959
}
960960

961+
It 'objectKeys function returns array of keys: <expression>' -TestCases @(
962+
@{ expression = "[length(objectKeys(createObject('a', 1, 'b', 2, 'c', 3)))]"; expected = 3 }
963+
@{ expression = "[length(objectKeys(createObject()))]"; expected = 0 }
964+
@{ expression = "[objectKeys(createObject('name', 'John'))[0]]"; expected = 'name' }
965+
@{ expression = "[length(objectKeys(createObject('x', 1, 'y', 2)))]"; expected = 2 }
966+
) {
967+
param($expression, $expected)
968+
969+
$escapedExpression = $expression -replace "'", "''"
970+
$config_yaml = @"
971+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
972+
resources:
973+
- name: Echo
974+
type: Microsoft.DSC.Debug/Echo
975+
properties:
976+
output: '$escapedExpression'
977+
"@
978+
$out = $config_yaml | dsc config get -f - | ConvertFrom-Json
979+
$out.results[0].result.actualState.output | Should -Be $expected
980+
}
981+
982+
It 'objectKeys function works with nested objects: <expression>' -TestCases @(
983+
@{ expression = "[objectKeys(createObject('person', createObject('name', 'John')))[0]]"; expected = 'person' }
984+
@{ expression = "[length(objectKeys(createObject('a', createArray(1,2,3), 'b', 'text')))]"; expected = 2 }
985+
) {
986+
param($expression, $expected)
987+
988+
$escapedExpression = $expression -replace "'", "''"
989+
$config_yaml = @"
990+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
991+
resources:
992+
- name: Echo
993+
type: Microsoft.DSC.Debug/Echo
994+
properties:
995+
output: '$escapedExpression'
996+
"@
997+
$out = $config_yaml | dsc config get -f - | ConvertFrom-Json
998+
$out.results[0].result.actualState.output | Should -Be $expected
999+
}
1000+
9611001
It 'tryGet() function works for: <expression>' -TestCases @(
9621002
@{ expression = "[tryGet(createObject('a', 1, 'b', 2), 'a')]"; expected = 1 }
9631003
@{ expression = "[tryGet(createObject('a', 1, 'b', 2), 'c')]"; expected = $null }

lib/dsc-lib/locales/en-us.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ invoked = "not function"
448448
description = "Returns a null value"
449449
invoked = "null function"
450450

451+
[functions.objectKeys]
452+
description = "Returns the keys from an object, where an object is a collection of key-value pairs"
453+
451454
[functions.or]
452455
description = "Evaluates if any arguments are true"
453456
invoked = "or function"

lib/dsc-lib/src/functions/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub mod mod_function;
5555
pub mod mul;
5656
pub mod not;
5757
pub mod null;
58+
pub mod object_keys;
5859
pub mod or;
5960
pub mod parameters;
6061
pub mod parse_cidr;
@@ -189,6 +190,7 @@ impl FunctionDispatcher {
189190
Box::new(mul::Mul{}),
190191
Box::new(not::Not{}),
191192
Box::new(null::Null{}),
193+
Box::new(object_keys::ObjectKeys{}),
192194
Box::new(or::Or{}),
193195
Box::new(parameters::Parameters{}),
194196
Box::new(parse_cidr::ParseCidr{}),

0 commit comments

Comments
 (0)