I maintain ConfigMgr Lab Builder, a PowerShell 7 + Hyper-V engine that builds a working ConfigMgr 2509 lab from a bare Windows host. One cmdlet, no external module dependencies, MIT licensed.

PowerShell
Import-Module .\modules\HomeLab\HomeLab.psd1
Install-HomeLab

About an hour later, that gives you this:

ConfigMgr console showing Site Status with seven site systems reporting OK

Seven site systems, all OK: component server, management point, distribution point, software update point, site server, and both site database objects. Nothing to click through afterward.

The topology is a config file

Every lab is described by a data file, not a script. This is most of the default 3-VM topology:

PowerShell
@{
    LabName    = 'HomeLab'
    DomainName = 'contoso.com'
    SiteCode   = 'MCM'
    Network    = '192.168.50'

    VMs = @(
        @{
            Name           = 'DC01'
            Roles          = @('DomainController','CertificateAuthority')
            IP             = '192.168.50.10'
            Memory         = 2GB
            Processors     = 2
            AutoStartDelay = 30
        }
        @{
            Name           = 'CM01'
            Roles          = @('SqlServer','SiteServer','ManagementPoint',
                               'DistributionPoint','SoftwareUpdatePoint')
            IP             = '192.168.50.20'
            Memory         = 10GB
            MaxMemory      = 12GB
            Processors     = 4
            OSDiskSize     = 150
            AutoStartDelay = 90
        }
        @{
            Name  = 'CLIENT01'
            Roles = @('Client')
            IP    = '192.168.50.100'
            Memory = 4GB
        }
    )
}

Roles drive everything. Add SoftwareUpdatePoint to a VM and the engine installs WSUS, configures the SUP, and wires it to the site. Move SqlServer onto its own VM and you have a split-SQL lab. Seven templates ship in templates/, from a 2-VM schema exercise up to a 9-VM CAS hierarchy. The one I run daily is two-clients — the default lab plus a second Windows 11 client, so application testing has a clean control machine instead of a checkpoint rollback:

Hyper-V Manager showing DC01, CM01, CLIENT01 and CLIENT02 running

The numbers

Measured on my host (20 threads, 32 GB, NVMe), with transcripts to back them:

  • Bare host to healthy site: about 1 hour 10 minutes. From ISOs. The engine builds sysprepped base images, provisions VMs from differencing disks, promotes the DC, installs SQL 2022, runs CM 2509 setup, and configures the site through to a green health report.
  • Teardown and full rebuild from cache: 45 to 65 minutes, depending on topology. Base images cache by ISO hash, so a rebuild skips image creation. CM setup is the long pole and nothing caches that.
  • Re-run against a healthy lab: under ten minutes. Every phase probes existing state and short-circuits, so re-running after a config tweak converges instead of rebuilding.

What it replaces

The classic way to get a ConfigMgr lab is a hydration kit: MDT builds an ISO, the ISO automates the OS and role installs, and everything around it is yours to do by hand. Create the VMs, wire the network, boot things in the right order, wait, and clean up whatever is left when you want to start over. It works, and I used that approach for years. The parts it leaves to you are the parts you get wrong at 11 PM.

Install-HomeLab owns the whole loop. It creates the switch, writes the hosts entries the host needs to reach lab VMs by name, checks that your topology's startup memory fits the RAM you actually have free right now, provisions in parallel, and sequences phases with readiness gates.

Teardown you can prove

This is the part I lean on most. Remove-HomeLab tears the lab down, and a separate audit script enumerates every artifact a lab run can leave behind, then exits non-zero if it finds any.

Here is a real audit against a running lab:

Plain text
HomeLab artifact audit -- 2026-08-01 13:28:59
  ImageRoot : C:\LabImages
  Sources   : C:\LabSources
  Identity  : 11 VM name(s), switches: HomeLab-Network, HomeLab-AIO-Network, ...

DIRTY -- 17 artifact(s) found:

Class     Item                                          Detail
-----     ----                                          ------
BaseImage 6ca1f8b97b2b5649.base.vhdx                    16.07GB, modified 07/17/2026
BaseImage 906ec15f3573f719.base.vhdx                    14.13GB, modified 07/17/2026
HostNic   vEthernet (HomeLab-Network)                   host IP 192.168.50.1/24 on lab subnet
HostsFile 192.168.50.10 DC01 DC01.contoso.com           lab entry in ...\etc\hosts
HostsFile 192.168.50.100 CLIENT01 CLIENT01.contoso.com  lab entry in ...\etc\hosts
HostsFile 192.168.50.101 CLIENT02 CLIENT02.contoso.com  lab entry in ...\etc\hosts
HostsFile 192.168.50.20 CM01 CM01.contoso.com           lab entry in ...\etc\hosts
Switch    HomeLab-Network                               type=Internal
TempFile  ...\Local\Temp\HomeLab-VcStage                VC++ redistributable staging folder
VM        CLIENT01                                      state=Running; disk under C:\LabImages
VM        CLIENT02                                      state=Running; disk under C:\LabImages
VM        CM01                                          state=Running; disk under C:\LabImages
VM        DC01                                          state=Running; disk under C:\LabImages
VmDisk    CLIENT01.vhdx                                 25.48GB
VmDisk    CLIENT02.vhdx                                 26.54GB
VmDisk    CM01.vhdx                                     49.63GB
VmDisk    DC01.vhdx                                     19.81GB

Report-only (not counted dirty):
Logs      C:\ProgramData\HomeLab\Logs                   30 log file(s) -- evidence, kept
Sources   C:\LabSources                                 consumed input -- kept

VERDICT: host is DIRTY.

Note what it catches beyond the obvious VMs: the host's own vEthernet adapter still holding an IP on the lab subnet, four hosts-file entries, the vSwitch, and a temp staging folder. It also finds strays — VMs from a config you renamed months ago, discovered by disk location rather than by name. CLIENT02 above came from a different template than the one loaded, and the teardown picked it up anyway:

Plain text
[WARN] [CLIENT02] not in current config but its disk lives under C:\LabImages;
       adding to removal set

After Remove-HomeLab -KeepBaseImages, the same audit run again:

Plain text
No lab artifacts found.

Report-only (not counted dirty):
BaseImage 6ca1f8b97b2b5649.base.vhdx  16.07GB (exempted by -AllowBaseImageCache)
BaseImage 906ec15f3573f719.base.vhdx  14.13GB (exempted by -AllowBaseImageCache)
Logs      C:\ProgramData\HomeLab\Logs 30 log file(s) -- evidence, intentionally kept
Sources   C:\LabSources               consumed input (ISOs/packages) -- kept

VERDICT: host is provably clean of lab artifacts.

The exit code matters as much as the text. Invoke-VerifiedE2E.ps1 chains teardown, audit, build, and health check under one transcript, and refuses to start the build if the audit comes back dirty.

That gate exists because I once shipped a "successful" end-to-end test that had silently consumed a stale cached image from an earlier run. The build passed. It proved nothing. An audit that exits non-zero makes that class of mistake loud instead of quiet.

Two flags control what counts as clean, and they have to agree with each other. Remove-HomeLab -KeepBaseImages preserves the image cache for fast rebuilds, and the audit's -AllowBaseImageCache exempts those same files. For from-scratch validation you pass neither, and the cache has to go.

What you get on day one

A three-VM lab by default — DC with root CA, site server with SQL 2022 and all roles co-located, Windows 11 client — with the operational details already handled: AD discovery on, boundaries and boundary group built, client push that works on Windows 11 (the engine opens the firewall paths push needs; a default Windows 11 install blocks them even when domain-joined), a test collection with a maintenance window, WSUS and a software update point, and driver choices that current CM actually tolerates. ODBC is pinned to 18.5.2.1 because 18.6.x has a documented NULL regression that breaks CM. MSOLEDB is left alone because CM setup installs its own.

There is also a WPF wizard for people who would rather click through it. It composes the same Install-HomeLab call against the same topology data, with validation before anything gets provisioned:

The HomeLab wizard's topology page, showing a per-VM grid and a validation dialog reporting 3 VMs, 8 vCPU, 16GB RAM

Who this is for

MECM admins who need a disposable, truthful replica of the product they run in production: testing application packaging, validating a claim before repeating it in a runbook, rehearsing an upgrade, or having a site you can break on purpose. The lab is cheap enough to destroy that you actually destroy it, and provable enough that "fresh build" means something.

Requirements: a Windows 10/11 Pro or Server host with 32 GB RAM and about 300 GB free, PowerShell 7.6, and the eval ISOs staged. The README walks through all of it.