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

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions