Problem description
Adding a realistic set of AD principals to a domain controller via AddsDomainPrincipals alongside AddsOrgUnitsAndGroups produces a node MOF of tens of MB that cannot be applied. Start-DscConfiguration (push) fails with MOF file size exceeded max size limit. / MI RESULT 27 (MI_RESULT_SERVER_LIMITS_EXCEEDED) — the hard, non-configurable ~10 MB LCM push limit. Raising WinRM MaxEnvelopeSizekb does not help (confirmed by Microsoft365DSC issue #357).
This is a second, independent explosion from the one fixed in #248 / PR #249 (each DomainLocal group depending on the full OU list). After #248 the node MOF drops from ~52.5 MB to ~17.8 MB — so it now compiles (< the 50 MB ValidateInstanceText limit) but still cannot be pushed (> the ~10 MB LCM limit).
Root cause is the composite-level dependency the consumer places on AddsDomainPrincipals:
AddsDomainPrincipals:
DependsOn:
- "[AddsDomain]AddsDomain"
- "[AddsOrgUnitsAndGroups]AddsOrgUnitsAndGroups"
Both entries are composite references, and DSC applies two multiplicative expansions:
- Reference expansion — a composite reference in
DependsOn expands to references to every resource that composite generated (~5 for AddsDomain + ~557 OUs/groups for AddsOrgUnitsAndGroups = 562).
- Composite propagation — a
DependsOn set on a consuming composite is copied onto every resource that composite emits (~130 ADUser + ~96 _MemberOf Script + … ≈ 230).
Result ≈ 230 × 562 ≈ 129,000 fully-qualified DependsOn strings ≈ 16 MB. Measured on a real DC (~130 users, ~200 groups, ~350 OUs): each MSFT_ADUser MOF block was 73,360 bytes, of which 72,770 (99.2 %) was a 562-entry DependsOn array; the node MOF was 17.8 MB (unpushable). The AddsDomainPrincipals composite itself is fine — each _MemberOf script correctly depends only on its own [ADUser]; the bloat is entirely the propagated composite-level DependsOn.
Verbose logs
Start-DscConfiguration : The configuration 'VPFPDC001.mof' MOF file size exceeded max size limit.
+ CategoryInfo : NotSpecified: (root/Microsoft/...:String) [], CimException
+ FullyQualifiedErrorId : MI RESULT 27
+ PSComputerName : VPFPDC001
# MI_RESULT_SERVER_LIMITS_EXCEEDED (27). This is the hard ~10 MB LCM push limit.
# Increasing WinRM MaxEnvelopeSizekb has no effect (see Microsoft365DSC #357).
# Amplification (measured on the compiled node MOF, post-#248):
# node MOF total ......... 17.8 MB (unpushable)
# single MSFT_ADUser block 73,360 bytes
# of which DependsOn ... 72,770 bytes (99.2 %) = 562-entry array
# ~230 principal resources x 562 refs ~= 129,000 DependsOn strings
DSC configuration
# Reproduction: a DC that runs both composites, where AddsDomainPrincipals carries
# a composite-level DependsOn on the whole AddsOrgUnitsAndGroups composite.
#
# In a DscWorkshop/Datum data repo this is expressed in a role, e.g.
# source/Roles/RootDomainController.yml:
#
# AddsOrgUnitsAndGroups:
# OrgUnits: [ ... ~350 OUs ... ]
# Groups: [ ... ~200 groups ... ]
#
# AddsDomainPrincipals:
# Users: [ ... ~130 users ... ]
# DependsOn:
# - "[AddsDomain]AddsDomain"
# - "[AddsOrgUnitsAndGroups]AddsOrgUnitsAndGroups" # <-- the trigger
#
# Equivalent stand-alone configuration:
Configuration RootDomainController
{
Import-DscResource -ModuleName CommonTasks
Node VPFPDC001
{
AddsOrgUnitsAndGroups AddsOrgUnitsAndGroups
{
DomainDN = 'DC=contoso,DC=com'
OrgUnits = $orgUnits # ~350 OUs
Groups = $groups # ~200 groups
}
AddsDomainPrincipals AddsDomainPrincipals
{
DomainDN = 'DC=contoso,DC=com'
Users = $users # ~130 users, most with MemberOf
DependsOn = @(
'[AddsDomain]AddsDomain'
'[AddsOrgUnitsAndGroups]AddsOrgUnitsAndGroups' # expands to all 562 members,
) # then propagates to all ~230 principals
}
}
}
Suggested solution
Add a completion anchor to AddsOrgUnitsAndGroups: a single, always-in-desired-state Script resource (AddsOrgUnitsAndGroupsComplete) that DependsOn every OU and group the composite creates. Consumers then order after the whole composite with one cheap, non-expanding reference:
DependsOn = "[Script]AddsOrgUnitsAndGroupsComplete::[AddsOrgUnitsAndGroups]AddsOrgUnitsAndGroups"
- The anchor is processed only after every OU/group exists.
AddsDomainPrincipals's single anchor reference propagates to its ~230 resources as 1 edge each instead of 562, so ordering is preserved (users find their Path OU; _MemberOf scripts find their target groups) while the MOF stays small.
- No cycle:
AddsDomainPrincipals → anchor → OUs/groups; nothing points back.
- Backward compatible: the anchor is inert (
TestScript = { $true }) and is skipped when neither OUs nor groups are defined; existing consumers are unaffected.
Expected result: node MOF drops from ~17.8 MB to < 2 MB; each MSFT_ADUser / _MemberOf block carries a small DependsOn (its own + the single anchor ref) instead of the full 562-entry list.
An alternative fine-grained approach (each user DependsOn only its parent OU; each _MemberOf only its target groups) is correct but couples AddsDomainPrincipals to AddsOrgUnitsAndGroups's resource-naming and sibling instance name — the completion anchor is preferred.
Operating system the target node is running
<!-- Replace with your target node, e.g.: -->
Windows Server 2022 Datacenter, 64-bit, en-US
(Get-ComputerInfo -Property @('OsName','OsOperatingSystemSKU','OSArchitecture','WindowsVersion','WindowsBuildLabEx','OsLanguage','OsMuiLanguages'))
PowerShell version and build the target node is running
<!-- Replace with your $PSVersionTable (DSC LCM push runs under Windows PowerShell 5.1): -->
PSVersion 5.1.20348.xxxx
PSEdition Desktop
BuildVersion 10.0.20348.xxxx
CLRVersion 4.0.30319.42000
CommonTasks version
<!-- Replace with your installed version; reproducible on 0.12.0 and current `main`. -->
Name Version Path
---- ------- ----
CommonTasks 0.12.0 C:\Program Files\WindowsPowerShell\Modules\CommonTasks\0.12.0\CommonTasks.psd1
Problem description
Adding a realistic set of AD principals to a domain controller via
AddsDomainPrincipalsalongsideAddsOrgUnitsAndGroupsproduces a node MOF of tens of MB that cannot be applied.Start-DscConfiguration(push) fails withMOF file size exceeded max size limit./MI RESULT 27(MI_RESULT_SERVER_LIMITS_EXCEEDED) — the hard, non-configurable ~10 MB LCM push limit. Raising WinRMMaxEnvelopeSizekbdoes not help (confirmed by Microsoft365DSC issue #357).This is a second, independent explosion from the one fixed in #248 / PR #249 (each
DomainLocalgroup depending on the full OU list). After #248 the node MOF drops from ~52.5 MB to ~17.8 MB — so it now compiles (< the 50 MBValidateInstanceTextlimit) but still cannot be pushed (> the ~10 MB LCM limit).Root cause is the composite-level dependency the consumer places on
AddsDomainPrincipals:Both entries are composite references, and DSC applies two multiplicative expansions:
DependsOnexpands to references to every resource that composite generated (~5 forAddsDomain+ ~557 OUs/groups forAddsOrgUnitsAndGroups= 562).DependsOnset on a consuming composite is copied onto every resource that composite emits (~130ADUser+ ~96_MemberOfScript+ … ≈ 230).Result ≈ 230 × 562 ≈ 129,000 fully-qualified
DependsOnstrings ≈ 16 MB. Measured on a real DC (~130 users, ~200 groups, ~350 OUs): eachMSFT_ADUserMOF block was 73,360 bytes, of which 72,770 (99.2 %) was a 562-entryDependsOnarray; the node MOF was 17.8 MB (unpushable). TheAddsDomainPrincipalscomposite itself is fine — each_MemberOfscript correctly depends only on its own[ADUser]; the bloat is entirely the propagated composite-levelDependsOn.Verbose logs
DSC configuration
Suggested solution
Add a completion anchor to
AddsOrgUnitsAndGroups: a single, always-in-desired-stateScriptresource (AddsOrgUnitsAndGroupsComplete) thatDependsOnevery OU and group the composite creates. Consumers then order after the whole composite with one cheap, non-expanding reference:AddsDomainPrincipals's single anchor reference propagates to its ~230 resources as 1 edge each instead of 562, so ordering is preserved (users find theirPathOU;_MemberOfscripts find their target groups) while the MOF stays small.AddsDomainPrincipals→ anchor → OUs/groups; nothing points back.TestScript = { $true }) and is skipped when neither OUs nor groups are defined; existing consumers are unaffected.Expected result: node MOF drops from ~17.8 MB to < 2 MB; each
MSFT_ADUser/_MemberOfblock carries a smallDependsOn(its own + the single anchor ref) instead of the full 562-entry list.An alternative fine-grained approach (each user
DependsOnonly its parent OU; each_MemberOfonly its target groups) is correct but couplesAddsDomainPrincipalstoAddsOrgUnitsAndGroups's resource-naming and sibling instance name — the completion anchor is preferred.Operating system the target node is running
PowerShell version and build the target node is running
CommonTasks version