DSC icon indicating copy to clipboard operation
DSC copied to clipboard

Multi-string support

Open Gijsreyn opened this issue 6 months ago • 7 comments

Prerequisites

  • [X] Write a descriptive title.
  • [X] Make sure you are able to repro it on the latest version
  • [X] Search the existing issues.

Summary

Problem statement

This morning, I was rambling on my keyboard and looking at some examples to migrate PSDSC configuration documents to DSC. Experimenting with the PSDesiredStateConfiguration/Script resource was like opening a Pandora's box, with odd behaviors emerging out of the shadows especially when using multi-strings.

That brought me to do some investigation and see where things are going wrong.

Investigation

The initial start of my investigation, was using the following document:

# powershell.script.dsc.config.yaml
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
  - type: Microsoft.Windows/WindowsPowerShell
    name: Run script
    properties: 
      resources:
        - name: Run script
          type: PSDesiredStateConfiguration/Script
          properties: 
            Ensure: "Present"
            GetScript: |
              $testFile = C:\Temp\test.txt
              @{result = $(Get-Content $testFile)}
            TestScript: |
                Throw
            SetScript: |
                Throw

Running the script, gave me the following error message:

image

The strange thing while executing the document (dsc config get --path powershell.script.dsc.config.yaml), is that a piece is cut off:

image

Now, forget about the fact on YAML. Let's dive into the JSON part and see why the error was thrown. What I would have expected, is the following JSON being passed through to Invoke-DscResource:

// Example 1
{"GetScript":"$var = \"C:\\temp\\test.txt\"; @{result = $(Get-Content $var)}","SetScript":"throw","TestScript":"throw","type":"PSDesiredStateConfiguration/Script"}

Unfortunately, that does not happen, nor does the following JSONs are being passed through:

// Example 2
$res = @'
{"GetScript":["$var = \"C:\\temp\\test.txt\", "@{result = $(Get-Content $var)}"],"SetScript":"throw","TestScript":"throw","type":"PSDesiredStateConfiguration/Script"}
'@ 

// Example 3
$$string = @'
{
    "GetScript": [
        {
            "$var": "C:\\Temp\\test.txt"
        },
        {
            "@{result}": "Get-Content $var"
        }        
    ],
  "SetScript": "throw",
  "TestScript": "throw",
  "type": "PSDesiredStateConfiguration/Script"
}
'@

That third one sticks out like a sore thumb to me too.

Thoughts and ideas

That brought me even deeper to look at the adapter code and a train of thoughts on how to potentially look at this.

Firstly, passing in example 2, which looks more naturally to me, only reveals the real error message when you change the following line and add the -ErrorAction Stop parameter:

$invokeResult = Invoke-DscResource -Method $Operation -ModuleName $cachedDscResourceInfo.ModuleName -Name $cachedDscResourceInfo.Name -Property $property -ErrorAction Stop

The error message that is returned:

image

That still doesn't really say what is happening behind the scenes, so you've to dump out the objects.

Example 2 vs 1:

image

image

While example 1 is running smoothly, but example 2 is a breeze to type. It raises the question of why it doesn’t flow the same way when you input YAML through DSC's core engine.

Still, I was curious why the object was a mismatch and dove into the code. Looking at how the property hashtable is built, you can spot the difference and I applied the following:

# morph the INPUT object into a hashtable named "property" for the cmdlet Invoke-DscResource
$DesiredState.properties.psobject.properties | ForEach-Object -Begin { $property = @{} } -Process { 
    if ($_.Value.GetType().Name -eq 'Object[]')
    {
        $property[$_.Name] = $_.Value -as [System.String]
    }
    
    $property[$_.Name] = $_.Value 
}

If you want me to raise a PR for the fix and create Pester tests around it, just let me know.

Steps to reproduce

See problem statement

Expected behavior

Apply multi-strings.

Actual behavior

Multi-strings are not passed through YAML.

Error details

No response

Environment data

Name                           Value
----                           -----
PSVersion                      5.1.22621.3880
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.22621.3880
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Version

dsc 3.0.0-preview.8

Visuals

No response

Gijsreyn avatar Aug 08 '24 06:08 Gijsreyn