Hyper V - tgs-jbraun/JumpCloud-Seeding GitHub Wiki
The hyper-v/ folder imports golden VM exports on a Hyper-V host. Each technician gets their own copy of every golden VM, named <name>_JCLab_<vm> and stored as <destination>\<name>_JCLab_<vm>. The golden exports stay untouched.
Export each lab VM once with Hyper-V's Export-VM into the source folder. An export keeps its config at <source>\<VM>\Virtual Machines\<GUID>.vmcx, and the tools name each lab VM after its export folder.
The tools skip any golden folder that a VM registered on the host runs from. That keeps a permanent VM out of the lab, such as a domain controller that runs from <source>\DC01, and it avoids that VM's locked files.
| Runs from | Tool | Needs | Interface |
|---|---|---|---|
| The Hyper-V host | import-golden-vms.ps1 |
Windows PowerShell 5.1 and the Hyper-V module, both on the host. Run it as administrator. | Plain prompts and a progress bar |
| Your workstation, over WinRM HTTPS | jclab.py | Python 3.9+, pip install -r requirements.txt, and PowerShell 7.4. No Hyper-V module. |
Tables, arrow-key menus and a live progress view |
Both tools run their host-side steps from JCLab.Host.ps1, so keep it next to the scripts. Both need an administrator account on the host. The host script stops on a machine without the Hyper-V module, and jclab.py offers the on-host mode only on a machine with the module.
| Setting | Default | Meaning |
|---|---|---|
Your name (-UserName) |
Asks | Added to each VM name. Spaces become dashes. |
Source (-Source) |
settings.json |
Folder of golden exports on the host |
Destination (-Destination) |
settings.json |
Folder for the lab VMs on the host |
Lab switch (-LabSwitch) |
settings.json |
The vSwitch the golden VMs' lab adapters use |
At once (-ThrottleLimit) |
3 |
VMs imported at once, 1 to 16 |
Put your site's values in hyper-v\settings.json. Copy settings.example.json and fill it in. Git ignores settings.json, and it never holds a password.
-
Source,DestinationandLabSwitchserve both tools. The example uses Hyper-V's default folders:C:\Users\Public\Documents\Hyper-V\GoldenandC:\ProgramData\Microsoft\Windows\Hyper-V. -
ComputerNameandAdminUserserve only jclab.py's remote import. - Parameters of the host script win over the file. jclab.py offers the file's values as defaults.
- Paths work with single or double backslashes.
Both tools check the file before they use it. They stop at the first bad line, such as a stray quote or a misspelled setting, and show its line number.
- Read the golden exports and plan a VM name and folder for each.
- If you already have lab VMs or leftover lab folders, list them and ask:
- Cancel (the default) changes nothing.
- Redeploy deletes your lab VMs, disks and folders, then imports fresh copies.
- Deploy missing keeps your VMs and imports only the ones you don't have yet. It appears when you have part of the lab.
- Delete deletes your lab VMs, disks and folders, then stops.
- Import each VM as a copy with a new ID. Every file goes under that VM's destination folder.
- Rename each VM to
<name>_JCLab_<vm>and start it.
Each lab gets its own network. Before the first import, the tools create a Private vSwitch for the technician, <name>_JCLab_vSwitch. A Private switch connects only the VMs on it, not the host and not other technicians' labs, so VMs of different technicians never share L2. Before each VM's first boot, its adapters on the lab switch move to that Private switch. Adapters on other switches stay as they are, such as a router's WAN on an external switch. If the lab switch name is wrong, the tools stop before they change anything, because no adapters would move. Delete also removes the Private switch.
Deleting uses Hyper-V's own order. For each VM, the tool:
- Discards a saved state.
- Turns the VM off.
- Deletes its checkpoints and waits for the disk merge.
- Removes the VM.
- Deletes its disks.
It waits up to 5 minutes for each step. VMs with checkpoints go last, because their merges take longest. Folders go after all the VMs, once nothing holds their files.
Imports run in parallel. Each import is a Hyper-V background job, 3 at a time by default. That is faster on SSD or NVMe drives. On spinning disks, parallel copies compete for the same disks, so import 1 or 2 at once.
The remote import connects only over WinRM HTTPS. Set it up once on the Hyper-V host, in a PowerShell window run as administrator:
Enable-PSRemoting -Force
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\LocalMachine\My
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force
New-NetFirewallRule -DisplayName 'WinRM HTTPS' -Direction Inbound -Protocol TCP -LocalPort 5986 -Action AllowA self-signed certificate works, but jclab.py then asks on every run whether to skip certificate checks. To avoid that, use a certificate from a CA your workstation trusts, issued for the host name you connect to.
Then, on your workstation:
python jclab.pyPick Hyper-V, then "From this workstation".
- jclab.py asks for your name, the host, the folders, the lab switch and how many VMs import at once, then shows them for review. It remembers them for next time.
- It checks the host's certificate on WinRM HTTPS (port 5986) with
Test-WSMan, before it asks for credentials. If the certificate isn't valid, for example because it's self-signed, it shows the reason and asks whether to skip certificate checks for this connection. The default is No. - It asks for the host's administrator account name. PowerShell's
Get-Credentialthen asks for the password in the same terminal. - It shows the skipped exports and the plan, then runs the pre-deployment check.
- It imports the VMs in a live "Deploying lab VMs" table, with a progress bar and status for each VM, then shows a results table.
jclab.py draws the whole UI. A PowerShell 7 helper, JCLab.Bridge.ps1, runs only the PowerShell calls: the certificate check, Get-Credential, the HTTPS session and the JCLab.Host.ps1 functions. Every Hyper-V command runs on the host, inside that session. The helper connects back to jclab.py over loopback with a one-time token, and it refuses any function outside the few that jclab.py needs.
The password stays in a SecureString inside the helper. The helper never converts it to plain text, and it never reaches jclab.py. The helper drops the credential once connected.
While the disks copy, a "While you wait" box below the table shows a random two-sentence pop-culture fact. A bar fills up until the next fact. The facts come from pop-culture-facts.txt, one per line as sentence | sentence | source. Each names its Wikipedia source. To add a fact, add a line.