PSDSC Resource data in `Set` and `Test` break naive expectations
Prerequisites
- [X] Write a descriptive title.
- [X] Make sure you are able to repro it on the latest version
- [X] Search the existing issues.
Steps to reproduce
-
Create the files for a new PowerShell module
mkdir ./dsc-repro/psdsc.repro touch ./dsc-repro/psdsc.repro/psdsc.repro.psd1 touch ./dsc-repro/psdsc.repro/psdsc.repro.psm1 -
Define the module manifest:
@{ RootModule = 'psdsc.repro.psm1' ModuleVersion = '0.0.1' GUID = '361fff1b-423a-423f-9e05-39f5ab94a437' Author = 'Bug Reproducer' CompanyName = 'Unknown' Copyright = '(c) Bug Reproducer. All rights reserved.' FunctionsToExport = '*' CmdletsToExport = '*' VariablesToExport = '*' AliasesToExport = '*' DscResourcesToExport = @( 'ReproResultData' ) PrivateData = @{ PSData = @{} } } -
Define the root module script:
[DscResource()] class ReproResultData { [DscProperty(Key)] [string] $KeyProperty [DscProperty()] [string] $ValueProperty [ReproResultData] Get() { $Current = [ReproResultData]::new() $Current.KeyProperty = $this.KeyProperty $Current.ValueProperty = "Default" return $Current } [bool] Test() { return $true } [void] Set() { } } -
Add the folder containing the repro module to the
PSModulePath:$env:PSModulePath += [System.IO.Path]::PathSeparator + "$PWD/dsc-repro" -
Confirm you can get the
ReproResultDatadsc resource and see its properties:$Resource = Get-DscResource -Module psdsc.reproImplementationDetail : ClassBased ResourceType : ReproResultData Name : ReproResultData FriendlyName : Module : psdsc.repro ModuleName : psdsc.repro Version : 0.0.1 Path : C:\code\dsc-repro\psdsc.repro\psdsc.repro.psd1 ParentPath : C:\code\dsc-repro\psdsc.repro ImplementedAs : PowerShell CompanyName : Unknown Properties : {KeyProperty, DependsOn, EnumProperty, PsDscRunAsCredential}$Resource | Select-Object -ExpandProperty Properties | Format-TableName PropertyType IsMandatory Values ---- ------------ ----------- ------ KeyProperty [string] True {} DependsOn [string[]] False {} PsDscRunAsCredential [PSCredential] False {} ValueProperty [string] False {}dsc --format yaml resource list psdsc.repro/ReproResultData# Formatted for easier reading type : psdsc.repro/ReproResultData version : 0.0.1 path : C:\code\dsc-repro\psdsc.repro\psdsc.repro.psd1 description : null directory : C:\code\dsc-repro\psdsc.repro implementedAs : ClassBased author : '' properties : [ KeyProperty, DependsOn, PsDscRunAsCredential, ValueProperty ] requires : DSC/PowerShellGroup manifest : null -
Invoke the resource with
Invoke-DscResource$PSInvokeParams = @{ Module = 'psdsc.repro' Name = 'ReproResultData' Property = @{ KeyProperty = 'Repro Example (PSDSC)' ValueProperty = 'Desired' } } 'Get', 'Test', 'Set' | ForEach-Object { Invoke-DscResource -Method $_ @PSInvokeParams | Format-List }KeyProperty : Repro Example (PSDSC) ValueProperty : Default --- InDesiredState : False --- RebootRequired : False -
Invoke the resource with
dsc resource:foreach ($Method in @('get', 'test', 'set')) { $InputJson = @{ KeyProperty = 'Repro Example (DSCv3)' ValueProperty = 'Desired' } | ConvertTo-Json $Arguments = @( $Method '-r', 'psdsc.repro/ReproResultData' '-i', $InputJson ) dsc resource @Arguments }actualState: KeyProperty: Repro Example (DSCv3) ValueProperty: Default --- desiredState: KeyProperty: Repro Example (DSCv3) ValueProperty: Desired type: psdsc.repro/ReproResultData actualState: InDesiredState: false inDesiredState: false differingProperties: - KeyProperty - ValueProperty - type --- beforeState: KeyProperty: Repro Example (DSCv3) ValueProperty: Default afterState: RebootRequired: false changedProperties: - RebootRequired
Expected behavior
$PSInvokeParams = @{
Module = 'psdsc.repro'
Name = 'ReproResultData'
Property = @{
KeyProperty = 'Repro Example (PSDSC)'
ValueProperty = 'Desired'
}
}
'Get', 'Test', 'Set' | ForEach-Object {
Invoke-DscResource -Method $_ @PSInvokeParams | Format-List
}
KeyProperty : Repro Example (PSDSC)
ValueProperty : Default
---
InDesiredState : False
---
RebootRequired : False
foreach ($Method in @('get', 'test', 'set')) {
$InputJson = @{
KeyProperty = 'Repro Example (DSCv3)'
ValueProperty = 'Desired'
} | ConvertTo-Json
$Arguments = @(
$Method
'-r', 'psdsc.repro/ReproResultData'
'-i', $InputJson
)
dsc resource @Arguments
}
actualState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Default
---
desiredState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Desired
actualState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Default
InDesiredState: false # should be ignored in property comparison
inDesiredState: false
differingProperties:
- ValueProperty
---
beforeState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Default
afterState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Default
RebootRequired: false # should be ignored in property comparison
changedProperties: [] # empty because set isn't implemented
Actual behavior
$PSInvokeParams = @{
Module = 'psdsc.repro'
Name = 'ReproResultData'
Property = @{
KeyProperty = 'Repro Example (PSDSC)'
ValueProperty = 'Desired'
}
}
'Get', 'Test', 'Set' | ForEach-Object {
Invoke-DscResource -Method $_ @PSInvokeParams | Format-List
}
KeyProperty : Repro Example (PSDSC)
ValueProperty : Default
---
InDesiredState : False
---
RebootRequired : False
foreach ($Method in @('get', 'test', 'set')) {
$InputJson = @{
KeyProperty = 'Repro Example (DSCv3)'
ValueProperty = 'Desired'
} | ConvertTo-Json
$Arguments = @(
$Method
'-r', 'psdsc.repro/ReproResultData'
'-i', $InputJson
)
dsc resource @Arguments
}
actualState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Default
---
desiredState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Desired
type: psdsc.repro/ReproResultData
actualState:
InDesiredState: false
inDesiredState: false
differingProperties:
- KeyProperty
- ValueProperty
- type
---
beforeState:
KeyProperty: Repro Example (PSDSC)
ValueProperty: Default
afterState:
RebootRequired: false
changedProperties:
- RebootRequired
Error details
No response
Environment data
Name Value
---- -----
PSVersion 7.3.6
PSEdition Core
GitCommitId 7.3.6
OS Microsoft Windows 10.0.22621
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Version
DSC (build from main), PSDSC v2.0.7
Visuals
No response
Fix Proposal
The DSC/PowerShellGroup resource provider should handle munging the data before returning it to dsc - currently, it just passes through the JSONified output from Invoke-DscResource - this breaks the expectations for dsc resource test and dsc resource set, particularly for integrating tools and users unfamiliar with what's happening.
The resource provider could invoke the get method before test/set calls, caching the before state. For Set calls, it could call get again after the set operation.
We need further thought and discussion on how to handle the InDesiredState and RebootRequired values from PSDSC Resources.