{"id":50718047,"url":"https://github.com/supermarsx/migration-merlin","last_synced_at":"2026-06-09T20:31:52.433Z","repository":{"id":351990114,"uuid":"1209672260","full_name":"supermarsx/migration-merlin","owner":"supermarsx","description":"Migration tool that helps you move Windows User Profiles to a new machine","archived":false,"fork":false,"pushed_at":"2026-04-17T10:35:57.000Z","size":286,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-17T12:12:03.424Z","etag":null,"topics":["microsoft","migration","network","open-source","powershell","remote","state","suite","tool","user-profile","usmt","usmt-wrapper","utility","windows","wrapper"],"latest_commit_sha":null,"homepage":"","language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/supermarsx.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-13T17:02:17.000Z","updated_at":"2026-04-17T10:36:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/supermarsx/migration-merlin","commit_stats":null,"previous_names":["supermarsx/migration-merlin"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/supermarsx/migration-merlin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarsx%2Fmigration-merlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarsx%2Fmigration-merlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarsx%2Fmigration-merlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarsx%2Fmigration-merlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supermarsx","download_url":"https://codeload.github.com/supermarsx/migration-merlin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarsx%2Fmigration-merlin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34125332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microsoft","migration","network","open-source","powershell","remote","state","suite","tool","user-profile","usmt","usmt-wrapper","utility","windows","wrapper"],"created_at":"2026-06-09T20:31:52.291Z","updated_at":"2026-06-09T20:31:52.424Z","avatar_url":"https://github.com/supermarsx.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg width=\"300\" height=\"300\" alt=\"Migration Merlin Logotype\" src=\"assets/migration-merlin-logo.png\" /\u003e\n\n# MigrationMerlin\n\nUSMT-based Windows user-profile migration toolkit with TUI, batch wrappers, and a robust test suite.\n\n[![CI](https://img.shields.io/github/actions/workflow/status/supermarsx/migration-merlin/ci.yml?branch=main\u0026label=CI\u0026style=flat-square)](https://github.com/supermarsx/migration-merlin/actions/workflows/ci.yml)\n[![Version](https://img.shields.io/badge/version-26.6-blue?style=flat-square)](version)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green?style=flat-square)](license.md)\n![Built with PowerShell](https://img.shields.io/badge/built%20with-PowerShell-5391FE?style=flat-square\u0026logo=powershell\u0026logoColor=white)\n\nRolling release · [latest release](https://github.com/supermarsx/migration-merlin/releases/latest)\n\nMigrationMerlin is a PC-to-PC user-state migration tool for Windows sysadmins and power users. It wraps Microsoft's official User State Migration Tool (`scanstate.exe` / `loadstate.exe`) with a friendly interactive TUI, numbered batch wrappers for step-by-step runs, an auto-configured SMB transfer share, optional AES-256 store encryption, multi-user include/exclude filtering, and a substantial Pester test suite. It is designed for the real-world case of moving a user (or a handful of users) from an old Windows 10/11 PC to a new one over the local network without hand-rolling USMT commands.\n\n## Features\n\n- USMT auto-detect and auto-install (bundled zip or silent Windows ADK fallback)\n- SMB share auto-setup on the destination PC, including firewall rule\n- Optional ACL tightening via `-AllowedSourceUser` and firewall scoping via `-AllowedSourceIP`\n- AES-256 encryption of the migration store (`-EncryptStore` + SecureString key)\n- Multi-user include / exclude filtering (`-IncludeUsers`, `-ExcludeUsers`)\n- Live progress bars, file counters, and MB/s throughput during scanstate / loadstate\n- Codepage-aware UI (braille spinner on UTF-8, ASCII fallback on OEM 437/850)\n- Dry-run mode that prints the composed USMT command line without executing it\n- Auto-elevation via UAC with safe SecureString marshalling across the boundary\n- Transcript logging with credential masking to the migration folder's `Logs\\`\n- Interactive TUI launcher (`MigrationMerlin.bat`) with saved configurations\n- Pester v5 test suite (~645 tests) covering modules, scripts, and integration paths\n\n## Repo layout\n\n```\n/\n├── MigrationMerlin.bat        Entry point (auto-elevating batch wrapper)\n├── MigrationMerlin.ps1        Interactive TUI launcher\n├── modules/                   Reusable PowerShell modules (8 files)\n├── scripts/                   Workflow scripts (capture / restore / verify)\n├── wrappers/                  Numbered .bat wrappers for the 5 manual steps\n├── config/                    USMT XML config (custom-migration.xml)\n└── tests/                     Pester suite (~645 tests)\n```\n\n## Requirements\n\n- Windows 10 or Windows 11 (source and destination)\n- Windows PowerShell 5.1 or PowerShell 7+\n- Administrator privileges on both PCs (scripts auto-elevate via UAC)\n- Both PCs reachable on the same network (SMB port 445 open between them)\n- Pester 5.x to run the test suite (auto-installed by `tests\\Run-Tests.ps1`)\n\nUSMT itself is **not** a prerequisite - the source script auto-installs it if it's not already present.\n\n## Quick start\n\n### Two-PC migration (recommended, numbered wrappers)\n\nOn the **new** (destination) PC, as Administrator:\n\n```bat\nwrappers\\1-Setup-Destination.bat\n```\n\nOn the **old** (source) PC, as Administrator:\n\n```bat\nwrappers\\2-Capture-Source.bat\n```\n\nBack on the **new** PC, once capture completes:\n\n```bat\nwrappers\\3-Restore-Destination.bat\nwrappers\\4-Verify-Migration.bat\nwrappers\\5-Cleanup.bat\n```\n\n### Interactive TUI\n\nDouble-click `MigrationMerlin.bat` (or run `.\\MigrationMerlin.ps1`) for an arrow-key driven menu that walks through setup, capture, restore, verification, and cleanup in sequence. Configuration is persisted to `%LOCALAPPDATA%\\MigrationMerlin\\config.json` between runs.\n\n### Scripted invocation\n\n```powershell\n# Destination (new PC)\npwsh -File scripts\\destination-setup.ps1\n\n# Source (old PC) - share path is printed by the destination script\npwsh -File scripts\\source-capture.ps1 -DestinationShare '\\\\NewPC\\MigrationShare$'\n```\n\nDefault migration folder is `C:\\MigrationStore` and default share name is `MigrationShare$` (the trailing `$` makes it a hidden share).\n\n## Common scenarios\n\n**Encrypted capture.** Pass a SecureString key to protect the store with AES-256. There is no recovery path if the key is lost.\n\n```powershell\n$key = Read-Host -AsSecureString 'Encryption key'\npwsh -File scripts\\source-capture.ps1 `\n    -DestinationShare '\\\\NewPC\\MigrationShare$' `\n    -EncryptStore -EncryptionKey $key\n```\n\n**Selective users.** Migrate only a specific set of profiles, optionally excluding others.\n\n```powershell\npwsh -File scripts\\source-capture.ps1 `\n    -DestinationShare '\\\\NewPC\\MigrationShare$' `\n    -IncludeUsers 'alice','bob' -ExcludeUsers 'tempuser'\n```\n\n**Restricted destination share.** Lock the share to a single source account and source IP on the destination PC.\n\n```powershell\npwsh -File scripts\\destination-setup.ps1 `\n    -AllowedSourceUser 'OLDPC\\alice' `\n    -AllowedSourceIP '192.168.1.50'\n```\n\n**Extra data + custom XML.** Include taskbar pins, Wi-Fi profiles, power plans, and the rules defined in `config\\custom-migration.xml` (browsers, dev tools, SSH, Git, VSCode, etc.).\n\n```powershell\npwsh -File scripts\\source-capture.ps1 `\n    -DestinationShare '\\\\NewPC\\MigrationShare$' `\n    -ExtraData\n```\n\n**Dry run.** Validate everything and print the scanstate command line without capturing.\n\n```powershell\npwsh -File scripts\\source-capture.ps1 `\n    -DestinationShare '\\\\NewPC\\MigrationShare$' -DryRun\n```\n\n## Troubleshooting\n\n### Cannot reach `\\\\DEST-PC\\MigrationShare$`\nRun `scripts\\destination-setup.ps1` on the destination PC first - the share does not exist until then. Confirm SMB ports 445 (and optionally 139) are open on the destination's firewall and that both PCs are in the same subnet or VLAN. If name resolution is unreliable, try the destination's IPv4 address in the UNC path: `\\\\192.168.1.50\\MigrationShare$`.\n\n### USMT not found\nThe source script tries to auto-install USMT via the ADK. If that fails (no internet, managed endpoint, etc.), drop a pre-downloaded USMT zip into one of the `USMT.SearchPaths` locations (for example `C:\\USMT` or `%TEMP%\\USMT-Tools`), or install the ADK manually and pick only the \"User State Migration Tool\" feature: https://learn.microsoft.com/en-us/windows-hardware/get-started/adk-install.\n\n### Capture stuck or slow\n`scanstate.exe` can run for several hours on large profiles. Monitor real-time progress by watching the migration store grow: `Get-ChildItem \\\\DEST-PC\\MigrationShare$\\USMT -Recurse | Measure-Object -Property Length -Sum`. The inline spinner also prints a running file count and MB/s figure.\n\n### UAC prompt cancelled\nIf the script is launched without elevation it re-launches itself via UAC. Clicking \"No\" at the prompt leaves no admin child running and the original window exits cleanly - no partial state is written. Re-run the batch file or script to retry.\n\n### Encryption key forgotten\nThere is no recovery path. Migration stores created with `-EncryptStore` cannot be decrypted without the original key. Re-capture on the source PC with a fresh key and restore that new store.\n\n### Everyone has access to the migration share\nBy default the hidden share is readable by `Everyone` on the local network (with file-system ACLs still guarding the contents). To restrict reads to a single source account, pass `-AllowedSourceUser \u003cDOMAIN\\user\u003e` to `scripts\\destination-setup.ps1`. Firewall scoping via `-AllowedSourceIP` is also available.\n\n### Non-UTF-8 console renders progress bars as `?`\nProgress bars and the braille spinner use Unicode glyphs. On legacy OEM codepages (437, 850) the UI auto-detects the console encoding and falls back to ASCII glyphs (`#`, `-`, and the classic `|/-\\` spinner). No configuration needed - `Get-MigrationUIGlyphs` picks the right set per call.\n\n### `Test-UncPath` rejects my share\nThe validator accepts `\\\\server\\share` and `\\\\server\\share$`, optionally followed by sub-paths. Paths with wildcards or any of `\\ / : * ? \" \u003c \u003e |` in the server or share segment are rejected on purpose. If the share name contains special characters, rename the share on the destination PC.\n\n## Testing\n\nRun the full Pester suite from the repo root:\n\n```powershell\npwsh -File tests\\Run-Tests.ps1\n```\n\nUseful options:\n\n```powershell\npwsh -File tests\\Run-Tests.ps1 -Filter 'destination'  # Subset by file name\npwsh -File tests\\Run-Tests.ps1 -Output Detailed       # Verbose output\npwsh -File tests\\Run-Tests.ps1 -CI                    # JUnit XML for CI\n```\n\nExpected baseline on Windows with Pester 5.x installed: **645 passed / 0 failed / 2 skipped**. The two skipped tests are environment-gated (long-running integration paths).\n\n## Releases\n\nMigration Merlin ships as a rolling release. Every commit that passes\nlint, format, test, build, and package stages is published as a new\nrelease automatically.\n\nVersion format: **YY.N** (two-digit year, dot, incremental within\nthe year). No `v` prefix. The current version is stored in the\n`version` file at the repo root and bumped automatically by CI.\n\nExamples: `26.1`, `26.2`, … `26.47`. A new year resets the counter:\n`27.1`, `27.2`, …\n\nReleases are tagged on `main`. Downloadable zip artifacts are\nattached to each GitHub Release.\n\n## License\n\nSee [`license.md`](license.md).\n\n## About\n\nBuilt on Microsoft's [User State Migration Tool (USMT)](https://learn.microsoft.com/en-us/windows/deployment/usmt/usmt-overview).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupermarsx%2Fmigration-merlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupermarsx%2Fmigration-merlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupermarsx%2Fmigration-merlin/lists"}