You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# repro.dsc.yaml$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.jsonresources:
- name: fwtype: Microsoft.Windows/FirewallRuleListproperties:
unspecifiedRulesAction: ignore # documented as "same as if not specified, does nothing"rules:
- name: DSC-Reprodirection: Inboundaction: Allowprotocol: 6localPorts: '32921'enabled: true
dsc config test -f repro.dsc.yaml
Expected
inDesiredState: true. unspecifiedRulesAction: ignore is documented as "same as if not specified, does nothing", so it should be indistinguishable from omitting the property.
Removing the unspecifiedRulesAction line from the same config yields inDesiredState: true with differingProperties: []. The only variable is the property itself — actual firewall state is identical in both cases.
All three enum values reproduce it:
config
inDesiredState
differingProperties
property omitted
true
[]
unspecifiedRulesAction: ignore
false
["unspecifiedRulesAction"]
unspecifiedRulesAction: disable
false
["unspecifiedRulesAction"]
unspecifiedRulesAction: remove
false
["unspecifiedRulesAction"]
Cause
get_rules() returns unspecified_rules_action: None unconditionally, and the field is skip_serializing_if = "Option::is_none", so dsc resource get never emits the property:
The engine's synthetic test then compares a desired state that has the property against an actual state that lacks it, and records a difference. This matches the intent stated in #1579 that the property be write-only and absent from output state — but combined with synthetic test, "absent from output" produces permanent false drift.
Also affects set convergence reporting
After a set has fully converged, a second identical set still reports:
The underlying rule work is correctly idempotent (already-disabled rules are skipped), but every run reports a change. For fleet reporting this means a converged estate never shows as converged.
Suggested fix
Two options, in preference order:
Exclude the property from state comparison. In Implement canonical _purge on Microsoft.Windows/FirewallRuleList for authoritative rule management #1579, Steve Lee (@SteveL-MSFT) argued for a canonical _-prefixed property (_disableUnspecified) partly for schema discoverability. A canonical write-only property would also sidestep this, since the engine already knows not to diff canonical metadata. If a resource-specific name is preferred, the resource or engine needs an equivalent "write-only, do not compare" marker.
Echo the property back from get, defaulting to ignore when absent, so desired and actual agree.
Option 1 seems more correct — the property is an instruction, not observable state — but it needs a mechanism that doesn't exist for non-canonical properties today.
Impact
Any configuration using unspecifiedRulesAction permanently reports out-of-desired-state and reports a change on every run, regardless of actual firewall state. This makes the property unusable for compliance reporting, which is its primary use case.
Steps to reproduce
Tested on
dsc 3.3.0-preview.4,Microsoft.Windows/FirewallRuleListv0.2.0, Windows Server 2025, elevated.Create a rule, then declare it exactly as it exists so there is genuinely no drift:
Expected
inDesiredState: true.unspecifiedRulesAction: ignoreis documented as "same as if not specified, does nothing", so it should be indistinguishable from omitting the property.Actual
{ "inDesiredState": false, "differingProperties": ["unspecifiedRulesAction"] }Removing the
unspecifiedRulesActionline from the same config yieldsinDesiredState: truewithdifferingProperties: []. The only variable is the property itself — actual firewall state is identical in both cases.All three enum values reproduce it:
inDesiredStatedifferingPropertiestrue[]unspecifiedRulesAction: ignorefalse["unspecifiedRulesAction"]unspecifiedRulesAction: disablefalse["unspecifiedRulesAction"]unspecifiedRulesAction: removefalse["unspecifiedRulesAction"]Cause
get_rules()returnsunspecified_rules_action: Noneunconditionally, and the field isskip_serializing_if = "Option::is_none", sodsc resource getnever emits the property:{"actualState":{"rules":[{"name":"DSC-Repro","protocol":6,"localPorts":"32921", ... }]}}The engine's synthetic test then compares a desired state that has the property against an actual state that lacks it, and records a difference. This matches the intent stated in #1579 that the property be write-only and absent from output state — but combined with synthetic test, "absent from output" produces permanent false drift.
Also affects
setconvergence reportingAfter a
sethas fully converged, a second identicalsetstill reports:{ "changedProperties": ["unspecifiedRulesAction"] }The underlying rule work is correctly idempotent (already-disabled rules are skipped), but every run reports a change. For fleet reporting this means a converged estate never shows as converged.
Suggested fix
Two options, in preference order:
_-prefixed property (_disableUnspecified) partly for schema discoverability. A canonical write-only property would also sidestep this, since the engine already knows not to diff canonical metadata. If a resource-specific name is preferred, the resource or engine needs an equivalent "write-only, do not compare" marker.get, defaulting toignorewhen absent, so desired and actual agree.Option 1 seems more correct — the property is an instruction, not observable state — but it needs a mechanism that doesn't exist for non-canonical properties today.
Impact
Any configuration using
unspecifiedRulesActionpermanently reports out-of-desired-state and reports a change on every run, regardless of actual firewall state. This makes the property unusable for compliance reporting, which is its primary use case.Refs: #1579, #1599