Skip to content

Passing object properties to Hashtable of class-based PowerShell resource #709

Closed

Description

@JohnMcPMS

Prerequisites

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

Summary

When passing an object type property to a resource that is using the Microsoft.DSC/PowerShell adapter, the object is not converted to a Hashtable correctly.

This currently only affects the resource commands, as config complains about custom resources before attempting to execute them (Not implemented: Custom resource not supported). Not sure if that is a bug (resource should also block) or simply a TODO.

Steps to reproduce

  1. With this file:
# config.yaml

Action: Partial
Settings:
  experimentalFeatures:
    dsc3: true
  1. Install the Microsoft.WinGet.DSC module from PSGallery. This is the target resource class.
[DSCResource()]
class WinGetUserSettings
{
    # We need a key. Do not set.
    [DscProperty(Key)]
    [string]$SID

    # A hash table with the desired settings.
    [DscProperty(Mandatory)]
    [Hashtable]$Settings

    [DscProperty()]
    [WinGetAction]$Action = [WinGetAction]::Full
  1. Run the command:
> dsc.exe resource test -r Microsoft.WinGet.DSC/WinGetUserSettings -f config.yml

Expected behavior

Resource invocation successful

Actual behavior

2025-03-17T18:13:16.530836Z ERROR PID 8308: Exception: Exception setting "Settings": "Cannot convert value "@{experimentalFeatures=}" to type "System.Collections.Hashtable". Error: "Cannot convert the "@{experimentalFeatures=}" value of type "System.Management.Automation.PSCustomObject" to type "System.Collections.Hashtable".""

Error details

Environment data

Name                           Value
----                           -----
PSVersion                      7.5.0
PSEdition                      Core
GitCommitId                    7.5.0
OS                             Microsoft Windows 10.0.23828
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Version

3.0.0

Visuals

No response

Activity

  1. Gijsreyn commented on Mar 18, 2025

    @Gijsreyn
    Collaborator

    Hi JohnMcPMS. I think you found something interesting. I was trying to reproduce the config part, and what you probably did in the first place, was something like this:

    $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
    resources:
    - name: UserSettings
      type: Microsoft.WinGet.DSC/WinGetUserSettings
      properties:
        Action: 'Partial'
        Settings:
          experimentalFeatures:
            dsc3: true

    This gives the error you reported, but it should have been:

    $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
    resources:
    - name: Use class PowerShell resources
      type: Microsoft.DSC/PowerShell
      properties:
        resources:
        - name: PowerShell 7 Preview
          type: Microsoft.WinGet.DSC/WinGetUserSettings
          properties:
            Action: Partial
            Settings:
              experimentalFeatures:
                dsc3: true

    This gives the same error message as the dsc resource command. Anyway, back to the interesting part. I was looking were the issue is going wrong, and it's on the lines responsible for converting the following in the psDscAdapter.psm1:

    if ($DesiredState.properties) {
        # set each property of $dscResourceInstance to the value of the property in the $desiredState INPUT object
        $DesiredState.properties.psobject.properties | ForEach-Object -Process {
            $dscResourceInstance.$($_.Name) = $_.Value
        }
    }

    The $DesiredState is of class dscResourceObject, which sets the properties default to psobject. You opened something interesting, because the properties in this case aren't compared against the actual class constructed with $dscResourceInstance = $resource::New().
    That's why you see the exception happening. To demonstrate the issue (and a workaround) a little bit more clearly, I simple added the following lines to convert the PSCustomObject to a hashtable:

    if ($DesiredState.properties) {
      # set each property of $dscResourceInstance to the value of the property in the $desiredState INPUT object
      $DesiredState.properties.psobject.properties | ForEach-Object -Process {
          if ($_.Value.GetType().Name -eq 'PSCustomObject') {
              $hashTable = @{}
              $_.Value.psobject.properties | ForEach-Object { $hashTable[$_.Name] = $_.Value } 
    
              $dscResourceInstance.$($_.Name) = $hashTable
          }
          else 
          {
              Write-DscTrace -Message "Setting property: $($_.Name) to $($_.Value.TypeNameOfValue)"
              $dscResourceInstance.$($_.Name) = $_.Value    
          }
      }
    }

    Then the result ends in what you're looking for:

    Image

    It however asks the fundamental question I guess: how does dsc.exe parse the specific object types towards adapted resources?

    Steve Lee (@SteveL-MSFT) or Mikey Lombardi (He/Him) (@michaeltlombardi) , what are your thoughts on?

  2. JohnMcPMS commented on Mar 18, 2025

    @JohnMcPMS
    CollaboratorAuthor

    It was my understanding that the config commands would be more efficient if you explicitly wrapped all of your adapted resources, but that it was not necessary. It seems strange to me that it would be required via config, but one cannot even supply --adapter to the resource usage commands.

  3. SteveL-MSFT commented on Mar 19, 2025

    @SteveL-MSFT
    Member

    JohnMcPMS the issue you are referring to is this #693 which I'm working on

  4. SteveL-MSFT commented on Mar 19, 2025

    @SteveL-MSFT
    Member

    Gijs Reijn (@Gijsreyn) I think you are on the right track for a fix, can you create a PR with added test?

  5. SteveL-MSFT commented on Mar 20, 2025

    @SteveL-MSFT
    Member

    This should be fixed by #713

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions