Skip to content

Commit 5d8d877

Browse files
authored
Merge pull request #1227 from Gijsreyn/gh-57/main/add-take-function
Add `take()` function
2 parents 51af9c6 + 56d9b66 commit 5d8d877

File tree

6 files changed

+518
-0
lines changed

6 files changed

+518
-0
lines changed

docs/reference/schemas/config/functions/overview.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ The following list of functions operate on arrays and collections:
589589
- [min()][min] - Return the smallest integer value from an array of integers.
590590
- [range()][range] - Create an array of integers within a specified range.
591591
- [skip()][skip] - Return an array or string with elements skipped from the beginning.
592+
- [take()][take] - Return an array or string with the specified number of elements from the start.
592593
- [tryGet()][tryGet] - Safely retrieve a value from an array by index or an object by key without throwing an error.
593594
- [tryIndexFromEnd()][tryIndexFromEnd] - Safely retrieve a value from an array by counting backward from the end.
594595
- [union()][union] - Return a single array or object with all unique elements from the parameters.
@@ -679,6 +680,7 @@ The following list of functions are for manipulating strings:
679680
- [length()][length] - Return the number of elements in an array, characters in a string, or top-level properties in an object.
680681
- [skip()][skip] - Return an array or string with elements skipped from the beginning.
681682
- [startsWith()][startsWith] - Check if a string starts with a specified prefix.
683+
- [take()][take] - Return an array or string with the specified number of elements from the start.
682684
- [string()][string] - Convert a value to its string representation.
683685
- [substring()][substring] - Extract a portion of a string starting at a specified position.
684686
- [toLower()][toLower] - Convert a string to lowercase.
@@ -765,6 +767,7 @@ The following list of functions create or convert values of a given type:
765767
[skip]: ./skip.md
766768
[startsWith]: ./startsWith.md
767769
[string]: ./string.md
770+
[take]: ./take.md
768771
[sub]: ./sub.md
769772
[substring]: ./substring.md
770773
[systemRoot]: ./systemRoot.md
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
---
2+
description: Reference for the 'take' DSC configuration document function
3+
ms.date: 11/01/2025
4+
ms.topic: reference
5+
title: take
6+
---
7+
8+
## Synopsis
9+
10+
Returns an array with the specified number of elements from the start of an
11+
array, or a string with the specified number of characters from the start of a
12+
string.
13+
14+
## Syntax
15+
16+
```Syntax
17+
take(originalValue, numberToTake)
18+
```
19+
20+
## Description
21+
22+
The `take()` function extracts a specified number of elements from the beginning
23+
of an array or characters from the beginning of a string. This is useful for
24+
limiting results, implementing pagination, or extracting prefixes from larger
25+
datasets.
26+
27+
- For arrays: returns a new array containing the first `n` elements
28+
- For strings: returns a new string containing the first `n` characters
29+
30+
Both parameters are required. The `originalValue` must be an array or a string.
31+
The `numberToTake` must be an integer. If the number is zero or negative, an
32+
empty array or empty string is returned. If the number is larger than the length
33+
of the array or string, all elements or characters are returned.
34+
35+
This function is particularly useful when you need to:
36+
37+
- Limit the number of items processed from a list
38+
- Extract a fixed-length prefix from identifiers or paths
39+
- Implement top-N selections without complex filtering
40+
- Create pagination or batch processing logic
41+
42+
## Examples
43+
44+
### Example 1 - Limit deployment to top priority servers
45+
46+
Deploy configuration changes to only the highest priority servers first, limiting
47+
risk during rollout. The `take()` function extracts the first N servers from
48+
your priority list. This example uses [`parameters()`][00] to reference the
49+
server list.
50+
51+
```yaml
52+
# take.example.1.dsc.config.yaml
53+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
54+
parameters:
55+
allServers:
56+
type: array
57+
defaultValue:
58+
- prod-web-01
59+
- prod-web-02
60+
- prod-web-03
61+
- prod-web-04
62+
- prod-web-05
63+
resources:
64+
- name: Priority Deployment
65+
type: Microsoft.DSC.Debug/Echo
66+
properties:
67+
output:
68+
allServers: "[parameters('allServers')]"
69+
deployToFirst: "[take(parameters('allServers'), 2)]"
70+
description: Deploy to first 2 servers in priority order
71+
```
72+
73+
```bash
74+
dsc config get --file take.example.1.dsc.config.yaml
75+
```
76+
77+
```yaml
78+
results:
79+
- name: Priority Deployment
80+
type: Microsoft.DSC.Debug/Echo
81+
result:
82+
actualState:
83+
output:
84+
allServers:
85+
- prod-web-01
86+
- prod-web-02
87+
- prod-web-03
88+
- prod-web-04
89+
- prod-web-05
90+
deployToFirst:
91+
- prod-web-01
92+
- prod-web-02
93+
description: Deploy to first 2 servers in priority order
94+
messages: []
95+
hadErrors: false
96+
```
97+
98+
The function returns only the first two servers from the list, allowing you to
99+
implement a staged rollout strategy.
100+
101+
### Example 2 - Extract environment prefix from resource names
102+
103+
When working with standardized naming conventions, extracting prefixes helps
104+
with categorization and routing logic. This example shows how to use `take()` to
105+
get environment codes from resource identifiers. This example uses
106+
[`createArray()`][01] to build the resource name list.
107+
108+
```yaml
109+
# take.example.2.dsc.config.yaml
110+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
111+
resources:
112+
- name: Resource Prefixes
113+
type: Microsoft.DSC.Debug/Echo
114+
properties:
115+
output:
116+
resources: "[createArray('prod-db-east-01', 'dev-api-west-02', 'test-cache-central')]"
117+
prodPrefix: "[take('prod-db-east-01', 4)]"
118+
devPrefix: "[take('dev-api-west-02', 3)]"
119+
testPrefix: "[take('test-cache-central', 4)]"
120+
```
121+
122+
```bash
123+
dsc config get --file take.example.2.dsc.config.yaml
124+
```
125+
126+
```yaml
127+
results:
128+
- name: Resource Prefixes
129+
type: Microsoft.DSC.Debug/Echo
130+
result:
131+
actualState:
132+
output:
133+
resources:
134+
- prod-db-east-01
135+
- dev-api-west-02
136+
- test-cache-central
137+
prodPrefix: prod
138+
devPrefix: dev
139+
testPrefix: test
140+
messages: []
141+
hadErrors: false
142+
```
143+
144+
The function extracts the environment prefix from each resource name, enabling
145+
environment-specific configuration logic.
146+
147+
### Example 3 - Implement batch processing with size limits
148+
149+
Processing items in controlled batches prevents resource exhaustion when dealing
150+
with large datasets. By using `take()`, you can limit the number of items
151+
processed in each run. This example uses [`parameters()`][00] to reference the
152+
pending jobs array and [`length()`][02] to show the total count.
153+
154+
```yaml
155+
# take.example.3.dsc.config.yaml
156+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
157+
parameters:
158+
pendingJobs:
159+
type: array
160+
defaultValue:
161+
- job-001
162+
- job-002
163+
- job-003
164+
- job-004
165+
- job-005
166+
- job-006
167+
- job-007
168+
- job-008
169+
resources:
170+
- name: Batch Processing
171+
type: Microsoft.DSC.Debug/Echo
172+
properties:
173+
output:
174+
totalPending: "[length(parameters('pendingJobs'))]"
175+
currentBatch: "[take(parameters('pendingJobs'), 3)]"
176+
batchSize: 3
177+
description: Process first 3 jobs from queue
178+
```
179+
180+
```bash
181+
dsc config get --file take.example.3.dsc.config.yaml
182+
```
183+
184+
```yaml
185+
results:
186+
- name: Batch Processing
187+
type: Microsoft.DSC.Debug/Echo
188+
result:
189+
actualState:
190+
output:
191+
totalPending: 8
192+
currentBatch:
193+
- job-001
194+
- job-002
195+
- job-003
196+
batchSize: 3
197+
description: Process first 3 jobs from queue
198+
messages: []
199+
hadErrors: false
200+
```
201+
202+
The function returns the first three jobs for processing, allowing you to
203+
implement controlled batch processing with predictable resource usage.
204+
205+
### Example 4 - Select top-N log entries for monitoring
206+
207+
Pagination-style access to log entries or event streams can be implemented by
208+
combining `take()` with [`skip()`][03]. This example shows how to get the most
209+
recent entries while demonstrating the complementary relationship between these
210+
functions. This example uses [`parameters()`][00] to reference the log entries
211+
array.
212+
213+
```yaml
214+
# take.example.4.dsc.config.yaml
215+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
216+
parameters:
217+
recentLogs:
218+
type: array
219+
defaultValue:
220+
- 2025-11-01 10:00:00 - System started
221+
- 2025-11-01 10:05:32 - User login: admin
222+
- 2025-11-01 10:07:15 - Config updated
223+
- 2025-11-01 10:12:48 - Service restarted
224+
- 2025-11-01 10:15:03 - Backup completed
225+
- 2025-11-01 10:20:17 - Health check passed
226+
- 2025-11-01 10:25:44 - Cache cleared
227+
resources:
228+
- name: Log Monitoring
229+
type: Microsoft.DSC.Debug/Echo
230+
properties:
231+
output:
232+
topThree: "[take(parameters('recentLogs'), 3)]"
233+
nextThree: "[take(skip(parameters('recentLogs'), 3), 3)]"
234+
description: Show first 3 and next 3 log entries
235+
```
236+
237+
```bash
238+
dsc config get --file take.example.4.dsc.config.yaml
239+
```
240+
241+
```yaml
242+
results:
243+
- name: Log Monitoring
244+
type: Microsoft.DSC.Debug/Echo
245+
result:
246+
actualState:
247+
output:
248+
topThree:
249+
- 2025-11-01 10:00:00 - System started
250+
- 2025-11-01 10:05:32 - User login: admin
251+
- 2025-11-01 10:07:15 - Config updated
252+
nextThree:
253+
- 2025-11-01 10:12:48 - Service restarted
254+
- 2025-11-01 10:15:03 - Backup completed
255+
- 2025-11-01 10:20:17 - Health check passed
256+
description: Show first 3 and next 3 log entries
257+
messages: []
258+
hadErrors: false
259+
```
260+
261+
By combining `take()` and `skip()`, you can implement pagination logic to
262+
process logs or events in manageable chunks.
263+
264+
## Parameters
265+
266+
### originalValue
267+
268+
The array or string to take elements from. Required.
269+
270+
```yaml
271+
Type: array | string
272+
Required: true
273+
Position: 1
274+
```
275+
276+
### numberToTake
277+
278+
The number of elements or characters to take from the start. Must be an integer.
279+
If this value is 0 or less, an empty array or string is returned. If it's larger
280+
than the length of the given array or string, all elements or characters are
281+
returned. Required.
282+
283+
```yaml
284+
Type: integer
285+
Required: true
286+
Position: 2
287+
```
288+
289+
## Output
290+
291+
Returns the same type as `originalValue`:
292+
293+
- If `originalValue` is an array, returns an array with up to `numberToTake`
294+
elements from the start
295+
- If `originalValue` is a string, returns a string with up to `numberToTake`
296+
characters from the start
297+
298+
```yaml
299+
Type: array | string
300+
```
301+
302+
## Errors
303+
304+
The function returns an error in the following cases:
305+
306+
- **Invalid original value type**: The first argument is not an array or string
307+
- **Invalid number type**: The second argument is not an integer
308+
309+
## Related functions
310+
311+
- [`skip()`][03] - Returns an array or string with elements skipped from the start
312+
- [`first()`][04] - Returns the first element of an array or first character of a string
313+
- [`last()`][05] - Returns the last element of an array or last character of a string
314+
- [`length()`][02] - Returns the number of elements in an array or characters in a string
315+
- [`createArray()`][01] - Creates an array from provided values
316+
- [`parameters()`][00] - Returns the value of a specified configuration parameter
317+
318+
<!-- Link reference definitions -->
319+
[00]: ./parameters.md
320+
[01]: ./createArray.md
321+
[02]: ./length.md
322+
[03]: ./skip.md
323+
[04]: ./first.md
324+
[05]: ./last.md

dsc/tests/dsc_functions.tests.ps1

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,37 @@ Describe 'tests for function expressions' {
599599
($out.results[0].result.actualState.output | Out-String) | Should -BeExactly ($expected | Out-String)
600600
}
601601

602+
It 'take function works for: <expression>' -TestCases @(
603+
@{ expression = "[take(createArray('a','b','c','d'), 2)]"; expected = @('a', 'b') }
604+
@{ expression = "[take('hello', 2)]"; expected = 'he' }
605+
@{ expression = "[take(createArray('a','b'), 0)]"; expected = @() }
606+
@{ expression = "[take('abc', 0)]"; expected = '' }
607+
@{ expression = "[take(createArray('a','b'), 5)]"; expected = @('a', 'b') }
608+
@{ expression = "[take('hi', 10)]"; expected = 'hi' }
609+
@{ expression = "[take('', 1)]"; expected = '' }
610+
@{ expression = "[take(createArray(), 2)]"; expected = @() }
611+
# Negative and zero counts return empty
612+
@{ expression = "[take(createArray('x','y','z'), -1)]"; expected = @() }
613+
@{ expression = "[take('hello', -2)]"; expected = '' }
614+
# Take all elements
615+
@{ expression = "[take(createArray('x','y','z'), 3)]"; expected = @('x', 'y', 'z') }
616+
@{ expression = "[take('test', 4)]"; expected = 'test' }
617+
) {
618+
param($expression, $expected)
619+
620+
$config_yaml = @"
621+
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
622+
resources:
623+
- name: Echo
624+
type: Microsoft.DSC.Debug/Echo
625+
properties:
626+
output: "$expression"
627+
"@
628+
$out = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log | ConvertFrom-Json
629+
$LASTEXITCODE | Should -Be 0 -Because (Get-Content $TestDrive/error.log -Raw)
630+
($out.results[0].result.actualState.output | Out-String) | Should -BeExactly ($expected | Out-String)
631+
}
632+
602633
It 'lastIndexOf function works for: <expression>' -TestCases @(
603634
@{ expression = "[lastIndexOf(createArray('a', 'b', 'a', 'c'), 'a')]"; expected = 2 }
604635
@{ expression = "[lastIndexOf(createArray(10, 20, 30, 20), 20)]"; expected = 3 }

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,12 @@ invoked = "sub function"
528528
description = "Returns the system root path"
529529
invoked = "systemRoot function"
530530

531+
[functions.take]
532+
description = "Returns an array with the specified number of elements from the start, or a string with the specified number of characters from the start"
533+
invoked = "take function"
534+
invalidNumberToTake = "Second argument must be an integer"
535+
invalidOriginalValue = "First argument must be an array or string"
536+
531537
[functions.toLower]
532538
description = "Converts the specified string to lower case"
533539

0 commit comments

Comments
 (0)