Skip to content

AddsOrgUnitsAndGroups: composite-level DependsOn on AddsDomainPrincipals explodes the node MOF past the ~10 MB LCM push limit (MI RESULT 27) #250

Description

@raandree

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:

  1. 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).
  2. 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

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions