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
unspecifiedRulesAction shipped in #1599 (thanks!) and the core mechanism works. Two behaviours that were discussed and agreed in #1579 didn't make it into the implementation, and both block adopting authoritative mode in practice. Raising them separately since #1579 is closed.
Tested on dsc 3.3.0-preview.4, FirewallRuleList v0.2.0, Windows Server 2025.
1. unspecifiedRulesAction has no scope, so it reaches rules in dimensions you never declared
set_rules enumerates every rule from the COM store and skips only (a) names present in the declared rules array and (b) names beginning with ms-resource://. There is no filter on direction or profiles.
On a stock Windows Server 2025 host, declaring a single inbound rule with unspecifiedRulesAction: remove and running --what-if projects removal of ~180 rules, of which ~62 are outbound — the built-in outbound rules Windows ships (Core Networking ICMPv6, Network Discovery UPnP, Distributed Transaction Coordinator, and so on).
So a config that only ever describes inbound rules will silently delete the host's outbound ruleset. There's no way to express "this list is authoritative for inbound, leave outbound alone."
I think scope should probably be explicit, at least by direction and ideally by profiles, because deriving scope from the declared rules gets difficult when rules: [] is valid.
The WG note that followed settled the property's name, values and default, but didn't cover scope, so it looks like this simply wasn't carried forward rather than being decided against.
Request: an explicit scope for authoritative mode, minimally direction, ideally profiles. For example:
Deriving scope implicitly from the declared set is the alternative, but it breaks down for an empty rules array (below), which is why an explicit knob seems better.
Concretely: we are replacing a PowerShellScript reconciler that filters -Direction Inbound. With an enabled local outbound rule present, the reconciler leaves it alone and unspecifiedRulesAction: disable disables it. That difference is what currently blocks us swapping one for the other.
1b. A single action can't express a realistic authoritative policy
Related to the above. The reconciler we're replacing takes two different actions on unspecified rules:
undeclared rules that Windows ships → disable (reversible, no churn when the OS regenerates built-ins)
orphaned rules our own tooling previously created and no longer declares → remove
unspecifiedRulesAction applies one action to everything unspecified, so neither setting covers this: disable leaves orphans behind forever, and remove deletes built-in rules we only want disabled. Worth considering whether the action could be expressible per-scope, or whether a name-pattern-limited scope would cover it.
ERROR The rules array cannot be empty for get operations
ERROR Failed to run process 'windows_firewall': [exit code 3] Firewall error
Two problems:
This is the natural way to express "no local rules are permitted in this scope" — a baseline delivered entirely by GPO with the local store empty. That's a real posture, and it was agreed in Implement canonical _purge on Microsoft.Windows/FirewallRuleList for authoritative rule management #1579 that it should be valid. Gijs Reijn (@Gijsreyn): "I agree that _purge: true with rules: [] should be valid, as long as the purge scope is clear. That should mean 'no local persistent rules are allowed in this scope.' (currently this is not the case)"
The error says "for get operations" but is raised on set and set --what-if too, which is confusing when the operation requested was a set.
Request: accept rules: [] when unspecifiedRulesAction is disable or remove, meaning "nothing is permitted in scope". Keeping it an error for get alone is reasonable.
What does work (for the record)
Validated on real hosts, so these need no action:
Local-store isolation holds. GPO-delivered rules are never enumerated or touched, verified under a real (non---what-if) set in disable mode: GPO rule count and enabled count identical before and after. The COM enumeration matches Get-NetFirewallRule -PolicyStore PersistentStore exactly and excludes RSOP/GPO entries. This is the property the whole rollout depends on — could a regression test be added asserting a GPO-delivered rule survives unspecifiedRulesAction: remove? It currently holds as a consequence of the COM API rather than as an explicitly tested guarantee.
disable idempotency works. Already-disabled undeclared rules are correctly skipped; a second set performs no further rule changes.
Declared rules are correctly spared in both modes.
Two documentation notes:
The enum values are lowercase (ignore/disable/remove), but the WG decision on Implement canonical _purge on Microsoft.Windows/FirewallRuleList for authoritative rule management #1579 was written as Ignore, Remove, Disable. We copied the capitalised form into our internal plan and it fails validation with Schema: "Disable" is not one of "ignore", "disable" or "remove". Either accepting both casings or noting the lowercase requirement where the values are documented would save others the same trip.
The resource's name property maps to the Windows DisplayName, not the Name/rule identifier that New-NetFirewallRule -Name sets. Worth stating explicitly in the schema description — under authoritative mode, a config keyed on the wrong field means rules get treated as unspecified and swept.
Summary
unspecifiedRulesActionshipped in #1599 (thanks!) and the core mechanism works. Two behaviours that were discussed and agreed in #1579 didn't make it into the implementation, and both block adopting authoritative mode in practice. Raising them separately since #1579 is closed.Tested on
dsc 3.3.0-preview.4,FirewallRuleListv0.2.0, Windows Server 2025.1.
unspecifiedRulesActionhas no scope, so it reaches rules in dimensions you never declaredset_rulesenumerates every rule from the COM store and skips only (a) names present in the declaredrulesarray and (b) names beginning withms-resource://. There is no filter ondirectionorprofiles.On a stock Windows Server 2025 host, declaring a single inbound rule with
unspecifiedRulesAction: removeand running--what-ifprojects removal of ~180 rules, of which ~62 are outbound — the built-in outbound rules Windows ships (Core Networking ICMPv6, Network Discovery UPnP, Distributed Transaction Coordinator, and so on).So a config that only ever describes inbound rules will silently delete the host's outbound ruleset. There's no way to express "this list is authoritative for inbound, leave outbound alone."
In #1579 this was raised as the point most needing resolution, and Gijs Reijn (@Gijsreyn) agreed:
The WG note that followed settled the property's name, values and default, but didn't cover scope, so it looks like this simply wasn't carried forward rather than being decided against.
Request: an explicit scope for authoritative mode, minimally
direction, ideallyprofiles. For example:Deriving scope implicitly from the declared set is the alternative, but it breaks down for an empty
rulesarray (below), which is why an explicit knob seems better.Concretely: we are replacing a
PowerShellScriptreconciler that filters-Direction Inbound. With an enabled local outbound rule present, the reconciler leaves it alone andunspecifiedRulesAction: disabledisables it. That difference is what currently blocks us swapping one for the other.1b. A single action can't express a realistic authoritative policy
Related to the above. The reconciler we're replacing takes two different actions on unspecified rules:
unspecifiedRulesActionapplies one action to everything unspecified, so neither setting covers this:disableleaves orphans behind forever, andremovedeletes built-in rules we only want disabled. Worth considering whether the action could be expressible per-scope, or whether a name-pattern-limited scope would cover it.2.
rules: []is rejectedTwo problems:
_purge: truewithrules: []should be valid, as long as the purge scope is clear. That should mean 'no local persistent rules are allowed in this scope.' (currently this is not the case)"setandset --what-iftoo, which is confusing when the operation requested was a set.Request: accept
rules: []whenunspecifiedRulesActionisdisableorremove, meaning "nothing is permitted in scope". Keeping it an error forgetalone is reasonable.What does work (for the record)
Validated on real hosts, so these need no action:
--what-if)setindisablemode: GPO rule count and enabled count identical before and after. The COM enumeration matchesGet-NetFirewallRule -PolicyStore PersistentStoreexactly and excludes RSOP/GPO entries. This is the property the whole rollout depends on — could a regression test be added asserting a GPO-delivered rule survivesunspecifiedRulesAction: remove? It currently holds as a consequence of the COM API rather than as an explicitly tested guarantee.disableidempotency works. Already-disabled undeclared rules are correctly skipped; a secondsetperforms no further rule changes.--what-ifreports without mutating. Rule counts and enabled counts unchanged across all what-if runs. Messages are clear and exactly what was asked for in Implement canonical _purge on Microsoft.Windows/FirewallRuleList for authoritative rule management #1579.Two documentation notes:
ignore/disable/remove), but the WG decision on Implement canonical _purge on Microsoft.Windows/FirewallRuleList for authoritative rule management #1579 was written asIgnore,Remove,Disable. We copied the capitalised form into our internal plan and it fails validation withSchema: "Disable" is not one of "ignore", "disable" or "remove". Either accepting both casings or noting the lowercase requirement where the values are documented would save others the same trip.nameproperty maps to the Windows DisplayName, not theName/rule identifier thatNew-NetFirewallRule -Namesets. Worth stating explicitly in the schema description — under authoritative mode, a config keyed on the wrong field means rules get treated as unspecified and swept.Refs: #1579, #1599