Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 267 additions & 0 deletions docs/reference/schemas/config/functions/substring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
---
description: Reference for the 'substring' DSC configuration document function
ms.date: 09/27/2025
ms.topic: reference
title: substring
---

# substring

## Synopsis

Returns a substring that starts at the specified character position and contains
the specified number of characters.

## Syntax

```Syntax
substring(<stringToParse>, <startIndex>)
substring(<stringToParse>, <startIndex>, <length>)
```

## Description

The `substring()` function extracts a portion of a string based on the specified
starting position and optional length. The function uses zero-based indexing,
meaning the first character is at position 0. This is useful for parsing
identifiers, extracting prefixes or suffixes, manipulating configuration values,
or formatting display strings.

Key behaviors:

- **Zero-based indexing**: The first character is at index 0
- **Optional length**: If length is omitted, returns the remainder of the string
from the start position
- **Boundary validation**: Prevents access beyond string boundaries with clear
error messages

## Examples

### Example 1 - Extract environment from resource name

This example demonstrates extracting environment information from standardized
resource names for conditional configuration. It uses the [`parameters()`][08]
function to retrieve the resource name.

```yaml
# substring.example.1.dsc.config.yaml
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
resourceName:
type: string
defaultValue: svc-api-prod-east
resources:
- name: Extract environment
type: Microsoft.DSC.Debug/Echo
properties:
output:
environment: "[substring(parameters('resourceName'), 8, 4)]"
```

```bash
dsc config get --file substring.example.1.dsc.config.yaml
```

```yaml
results:
- name: Extract environment
type: Microsoft.DSC.Debug/Echo
result:
actualState:
output:
environment: prod
messages: []
hadErrors: false
```

### Example 2 - Extract region from resource identifier

This example shows extracting a region code from a standardized resource
identifier without specifying length, using [`parameters()`][08] to retrieve
the identifier.

```yaml
# substring.example.2.dsc.config.yaml
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
resourceId:
type: string
defaultValue: app-web-eastus2-001
resources:
- name: Extract region
type: Microsoft.DSC.Debug/Echo
properties:
output:
region: "[substring(parameters('resourceId'), 8)]"
```

```bash
dsc config get --file substring.example.2.dsc.config.yaml
```

```yaml
results:
- name: Extract region
type: Microsoft.DSC.Debug/Echo
result:
actualState:
output:
region: eastus2-001
messages: []
hadErrors: false
```

### Example 3 - Parse version components

This example demonstrates parsing semantic version strings to extract major,
minor, and patch components. It uses [`parameters()`][08] to retrieve the
version string.

```yaml
# substring.example.3.dsc.config.yaml
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
version:
type: string
defaultValue: "3.2.1"
resources:
- name: Parse version
type: Microsoft.DSC.Debug/Echo
properties:
output:
major: "[substring(parameters('version'), 0, 1)]"
minor: "[substring(parameters('version'), 2, 1)]"
patch: "[substring(parameters('version'), 4, 1)]"
```

```bash
dsc config get --file substring.example.3.dsc.config.yaml
```

```yaml
results:
- name: Parse version
type: Microsoft.DSC.Debug/Echo
result:
actualState:
output:
major: "3"
minor: "2"
patch: "1"
messages: []
hadErrors: false
```

### Example 4 - Unicode and emoji support

This example shows that `substring()` correctly handles Unicode characters and
emojis. It uses [`parameters()`][08] to retrieve the message string.

```yaml
# substring.example.4.dsc.config.yaml
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
message:
type: string
defaultValue: "Hello 🌍 World!"
resources:
- name: Unicode substring
type: Microsoft.DSC.Debug/Echo
properties:
output:
greeting: "[substring(parameters('message'), 0, 5)]"
emoji: "[substring(parameters('message'), 6, 1)]"
remainder: "[substring(parameters('message'), 8)]"
```

```bash
dsc config get --file substring.example.4.dsc.config.yaml
```

```yaml
results:
- name: Unicode substring
type: Microsoft.DSC.Debug/Echo
result:
actualState:
output:
greeting: Hello
emoji: 🌍
remainder: " World!"
messages: []
hadErrors: false
```

## Parameters

### stringToParse

The original string from which the substring is extracted.

```yaml
Type: string
Required: true
Position: 1
```

### startIndex

The zero-based starting character position for the substring. Must be a
non-negative integer and cannot exceed the length of the string.

```yaml
Type: int
Required: true
Position: 2
```

### length

The number of characters for the substring. Must be a non-negative integer. The
start index plus length cannot exceed the length of the string. If omitted, the
remainder of the string from the start position is returned.

```yaml
Type: int
Required: false
Position: 3
```

## Output

The `substring()` function returns a string containing the extracted portion of
the original string.

```yaml
Type: string
```

## Exceptions

The `substring()` function raises errors for the following conditions:

- **Invalid start index**: When `startIndex` is negative
- **Start index out of bounds**: When `startIndex` exceeds the string length
- **Invalid length**: When `length` is negative
- **Length out of bounds**: When `startIndex + length` exceeds the string
length

## Related functions

- [`string()`][00] - Converts values to strings
- [`concat()`][01] - Concatenates strings together
- [`indexOf()`][02] - Finds the index of a substring in a string
- [`lastIndexOf()`][03] - Finds the last index of a substring in a string
- [`length()`][04] - Returns the length of a string or array
- [`startsWith()`][05] - Checks if a string starts with a prefix
- [`endsWith()`][06] - Checks if a string ends with a suffix

<!-- Link reference definitions -->
[00]: ./string.md
[01]: ./concat.md
[02]: ./indexOf.md
[03]: ./lastIndexOf.md
[04]: ./length.md
[05]: ./startsWith.md
[06]: ./endsWith.md
[08]: ./parameters.md
50 changes: 50 additions & 0 deletions dsc/tests/dsc_functions.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,56 @@ Describe 'tests for function expressions' {
type: Microsoft.DSC.Debug/Echo
properties:
output: "$expression"
"@
$out = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log
$LASTEXITCODE | Should -Not -Be 0
$errorContent = Get-Content $TestDrive/error.log -Raw
$errorContent | Should -Match ([regex]::Escape($expectedError))
}

It 'substring function works for: <expression>' -TestCases @(
@{ expression = "[substring('hello world', 6, 5)]"; expected = 'world' }
@{ expression = "[substring('hello', 0, 2)]"; expected = 'he' }
@{ expression = "[substring('hello', 1, 3)]"; expected = 'ell' }
@{ expression = "[substring('hello', 2)]"; expected = 'llo' }
@{ expression = "[substring('hello', 0)]"; expected = 'hello' }
@{ expression = "[substring('hello', 5)]"; expected = '' }
@{ expression = "[substring('hello', 1, 1)]"; expected = 'e' }
@{ expression = "[substring('hello', 5, 0)]"; expected = '' }
@{ expression = "[substring('', 0)]"; expected = '' }
@{ expression = "[substring('', 0, 0)]"; expected = '' }
@{ expression = "[substring('héllo', 1, 2)]"; expected = 'él' }
) {
param($expression, $expected)

$escapedExpression = $expression -replace "'", "''"
$config_yaml = @"
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
- name: Echo
type: Microsoft.DSC.Debug/Echo
properties:
output: '$escapedExpression'
"@
$out = $config_yaml | dsc config get -f - | ConvertFrom-Json
$out.results[0].result.actualState.output | Should -Be $expected
}

It 'substring function error handling: <expression>' -TestCases @(
@{ expression = "[substring('hello', -1, 2)]"; expectedError = 'Start index cannot be negative' }
@{ expression = "[substring('hello', 1, -1)]"; expectedError = 'Length cannot be negative' }
@{ expression = "[substring('hello', 10, 1)]"; expectedError = 'Start index is beyond the end of the string' }
@{ expression = "[substring('hello', 2, 10)]"; expectedError = 'Length extends beyond the end of the string' }
) {
param($expression, $expectedError)

$config_yaml = @"
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
- name: Echo
type: Microsoft.DSC.Debug/Echo
properties:
output: `"$expression`"
"@
$out = dsc -l trace config get -i $config_yaml 2>$TestDrive/error.log
$LASTEXITCODE | Should -Not -Be 0
Expand Down
10 changes: 10 additions & 0 deletions dsc_lib/locales/en-us.toml
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,16 @@ invalidOriginalValue = "First argument must be an array or string"
[functions.string]
description = "Converts a value to a string"

[functions.substring]
description = "Returns a substring that starts at the specified character position and contains the specified number of characters"
invoked = "substring function"
startIndexNegative = "Start index cannot be negative"
startIndexTooLarge = "Start index is beyond the end of the string"
startIndexValueTooLarge = "Start index value too large"
lengthNegative = "Length cannot be negative"
lengthTooLarge = "Length extends beyond the end of the string"
lengthValueTooLarge = "Length value too large"

[functions.sub]
description = "Subtracts the second number from the first"
invoked = "sub function"
Expand Down
2 changes: 2 additions & 0 deletions dsc_lib/src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub mod skip;
pub mod starts_with;
pub mod string;
pub mod sub;
pub mod substring;
pub mod system_root;
pub mod r#true;
pub mod union;
Expand Down Expand Up @@ -177,6 +178,7 @@ impl FunctionDispatcher {
Box::new(starts_with::StartsWith{}),
Box::new(string::StringFn{}),
Box::new(sub::Sub{}),
Box::new(substring::Substring{}),
Box::new(system_root::SystemRoot{}),
Box::new(r#true::True{}),
Box::new(utc_now::UtcNow{}),
Expand Down
Loading
Loading